ミニPCにDocker + Cloudflare Tunnelでセルフホスティング
自宅のミニPC 1台で複数のWebサービスを安全に公開する方法。ポート開放なしでCloudflare TunnelでHTTPSをつなぎ、Docker Composeで運用します。
要点まとめ
ミニPCでDocker Composeによりサービスを立ち上げ、Cloudflare Tunnel(cloudflared)でポート開放なしにドメインとHTTPSをつなぐ。ルーター設定も、固定IPも、証明書の更新も必要ない。
目次
クラウド料金は小さなプロジェクトには地味に負担です。私はこのブログを含むいくつかのサービスを、自宅のミニPC 1台に載せて運用しています。その方法を共有します。
なぜミニPCなのか
- 常時稼働していて、電気代は月数千ウォン程度
- Dockerさえあればデプロイ環境はクラウドと同じ
- トラフィックが増えたら、そのとき移せばいい
問題はただ1つ、「自宅ネットワークをどう安全に外へ公開するか」です。
ポートを開けないでください
伝統的にはルーターのポートフォワーディング + DDNS + 証明書更新をやります。面倒ですし、ホームネットワークをそのままインターネットに開くようなものなので危険です。
代わりにCloudflare Tunnelを使います。ミニPCで cloudflared がCloudflareへ外向きに接続を開き、トラフィックはそのトンネルを通って入ってきます。外向けに開けているインバウンドポートは0です。
사용자 → Cloudflare(HTTPS) → 터널 → 미니 PC 의 컨테이너
- 固定IP・ポートフォワーディング不要
- HTTPS証明書はCloudflareが自動処理
- 動的IPでも問題なし
Docker Composeでサービスをまとめる
各サービスはコンテナで立ち上げます。Next.jsアプリなら output: "standalone" でビルドして軽いイメージを作ります。
services:
blog:
build:
context: .
dockerfile: apps/blog/Dockerfile
container_name: why-next-blog
restart: unless-stopped
networks: [api]
networks:
api:
external: true # cloudflared 와 같은 네트워크
ポイントはcloudflaredと同じDockerネットワークに置くことです。そうしてこそ、トンネルがコンテナ名でサービスを見つけられます。
ドメインをつなぐ
Cloudflareダッシュボード(またはトンネル設定)でPublic Hostnameを1つ追加します。
blog.example.com → http://why-next-blog:3001
これで終わりです。docker compose up -d --build すれば、数分後にはドメインでサイトが開きます。
まとめ
- ミニPC + Docker = 安くてクラウドと同じデプロイ
- Cloudflare Tunnelでポート開放なしにHTTPSとドメイン
- cloudflaredと同じネットワークにコンテナを配置
- Public Hostnameで
ドメイン → コンテナ:ポートをマッピング
小さなサービスなら、この組み合わせだけで十分長く持ちます。私もこうやって複数のアプリを運用しながら、作ったものを増やしています。
よくある質問
自宅のIPが動的でも大丈夫ですか?
大丈夫です。Cloudflare TunnelはミニPCがCloudflareへ外向きに接続を開く方式なので、固定IP・ポートフォワーディング・DDNSは一切必要ありません。
費用はかかりますか?
Cloudflare Tunnel自体は無料です。ドメイン費用さえあれば始められます。
関連記事
- 💻 開発
1つのバケットに所有者が2人いると、最後にapplyした側が勝つ
S3のlifecycleルールを1つ追加したらterraform applyが失敗した。原因は、同じバケットのlifecycle設定を2つのリソースがそれぞれ所有する構造。S3のlifecycleはルール単位ではなくドキュメント単位なので、最後の勝者が相手のルールを静かに消す。
- 💻 開発
受け取り損ねていた割引 - SpotとGravitonはなぜ安いのか
AWSの請求書が2か月連続で予算を超えた。削れるリソースを探したが、本当のレバーは「どれだけ使うか」ではなく「どう買うか」だった。SpotとGravitonがなぜ安いのか、そして無駄に見えて実は切ってはいけないコスト(RDS Proxy)まで - 請求書の数字ひとつひとつに宿る「理由」についての話。
- 💻 開発
テストは緑なのに、通知は一度も送信されていなかった
キューにジョブを入れるコードが初日から毎回失敗していた。エラーは握りつぶされ、テストはモックのおかげで緑のまま。コロン一文字が3つの機能を静かに殺した話。