2026年5月10日
Kubernetesの自宅サーバー公開をCloudflare Tunnelに移行した(VPS廃止)
以前の記事 IPoE回線の自宅のWebサービスをVPN経由で固定IPのクラウドから公開する では、IPoE 回線の自宅 Kubernetes クラスタを AWS Lightsail の VPS 経由(HAProxy + WireGuard)で外部公開する方法を紹介しました。あれから約3年、Cloudflare Tunnel を使った構成に切り替えたので、その記録を残しておきます。
困っていたこと
- 自宅 Kubernetes を外部公開するために Lightsail の VPS を経由していた
- 月額 $5 の固定費がかかっていた
cert-managerによる証明書管理はできていたが、VPS を挟む構成をもっとシンプルにしたかった
変更前の構成
変更後の構成
Cloudflare Tunnel は、cloudflared というクライアントがアウトバウンド接続で Cloudflare のエッジサーバーへトンネルを張り続ける仕組みです。以前の WireGuard と同様に、ポート開放なしに外部からアクセスできます。さらに VPS が不要になるので固定費がゼロになり、Cloudflare が TLS 終端してくれるため cert-manager の管理も不要になります。
移行手順
1. DNS を Cloudflare に移行
Cloudflare Tunnel は Cloudflare DNS を使う構成が一般的なので、今回は DNS を Cloudflare に移行しました。ドメインレジストラの設定でネームサーバーを Cloudflare のものに変更し、既存の DNS レコードが正しく移行されているか確認します。
移行前に使っていた DNS レコードと同じ内容が Cloudflare 側にも登録されていることを確認します。この時点ではまだ VPS の静的 IP を向き先にしているので、Proxy status は Proxied ではなく DNS only にしておきます。
2. Cloudflare Tunnel を作成
Cloudflare の管理画面で操作します。
- Networking → Tunnels を開く
- Create Tunnel をクリック
- 任意のトンネル名を入力して作成
- ドメイン毎ではなく拠点や環境毎に作るものなので、場所がわかる命名がよさそう
- 例: home, kubernetes, k3s...
- Operating System として Docker を選択し、表示されるコマンドに含まれるトンネルトークン(
--tokenの後ろ)をメモしておくdocker run cloudflare/cloudflared:latest tunnel --no-autoupdate run --token ey...
3. Kubernetes に cloudflared をデプロイ
トンネルトークンを Kubernetes の Secret として登録します。
kubectl create namespace cloudflare kubectl create secret generic cloudflared-credentials \ --from-literal=token=<トンネルトークン> \ -n cloudflare
次に Deployment を作成します。replicas: 2 にすることで cloudflared の Pod が複数起動し、
Cloudflare との接続が冗長化されるため可用性が高まります。1
私は Helm chart 化してデプロイしましたが、以下に同等の内容の YAML を置いておきます。
apiVersion: apps/v1 kind: Deployment metadata: name: cloudflared namespace: cloudflare spec: replicas: 2 selector: matchLabels: app: cloudflared template: metadata: labels: app: cloudflared spec: containers: - name: cloudflared image: cloudflare/cloudflared:latest args: - tunnel - --no-autoupdate - run - --token - $(TUNNEL_TOKEN) env: - name: TUNNEL_TOKEN valueFrom: secretKeyRef: name: cloudflared-credentials key: token
Cloudflare Tunnel の画面で接続確認が取れれば OK です。
4. cloudflared の転送先を Traefik の Service に変更
Cloudflare Tunnel の管理画面の Routes で、公開するドメイン名とバックエンドサービスを紐付けます。
Service URL にはクラスタ内の Ingress controller の URL を指定します。
例えば k3s 環境だと kube-system namespace に traefik という 80 番ポートの Service がある 2 ので、http://traefik.kube-system.svc.cluster.local:80 を指定すれば OK です。
- Add route をクリック
- Published application をクリック
- 必要な項目を入力
- Subdomain: 任意。必要なければ空
- Domain: Cloudflare のゾーン
- Path: 任意。必要なければ空
- Service URL: クラスタ内の Ingress controller の URL
- ルートを追加
- 対応する DNS レコード(
<UUID>.cfargotunnel.com)が追加されます
- 対応する DNS レコード(
ルートドメインと任意のサブドメインをまとめて転送したければ、Subdomain が空のルートとワイルドカード (*) のルートの 2 つを作っておきます。
5. 動作確認
ブラウザで各サービスにアクセスして問題がないか確認します。
Traefik の Ingress ルーティング自体は変わらないので、ホスト名が一致していれば問題なく動くはずです。
6. cert-manager の TLS 設定を Ingress から削除
Cloudflare が TLS を終端するため、今回は Kubernetes 側の cert-manager を削除しました。Ingress リソースの spec.tls セクションおよび cert-manager のアノテーションを削除します。
# 変更前 metadata: annotations: cert-manager.io/cluster-issuer: letsencrypt-prod spec: tls: - hosts: - app.example.com secretName: app-tls rules: - host: app.example.com http: paths: ...
# 変更後 spec: rules: - host: app.example.com http: paths: ...
おわりに
Cloudflare Tunnel への移行は想像より簡単で、サービスを止めることなくスムーズに切り替えられました。固定費ゼロ・構成シンプル・cert-manager 不要は嬉しいですね。
参考文献
Footnotes
-
Cloudflare のドキュメントでは最低2レプリカを推奨しています。レプリカ数を増やすほど接続が安定しますが、個人利用であれば2で十分でしょう。 ↩