Cloudflare Tunnelで自宅サーバーを公開する(FreeプランOK)
2022/12/15 追記
手順の変更
以前の記事との違いは、
- Argo Tunnelという名前がなくなった
- cloudflaredの設定にトンネル先を入れていたが、それはCfのWebで入力したものをリアルタイムに反映するようになった。ようするに設定値はトークンだけ。
Tunnelの作成
これで自宅内LANとCfの間のVPN(のようなもの)を確立させる。
ここでインストールする cloudflared が動作していないと公開できないので注意
- Cloudflare(以下Cf) のダッシュボードにログイン
- 左側メニューから
Zero Trustをクリック - 左側メニューの
Access -> Tunnelsをクリック - 右上、
Create a tunnelをクリック - トンネルの名前(何でもよい)を入れて次へ
cloudflaredを動かすための情報が表示されるのでどれかを実行。一番楽なのは dockerSaveボタンを押してTunnelの作成を一度完了させる
Public HostnameとLAN内エンドポイントの紐付け
ようするに、 myapp.example.comにアクセスされたら http://192.168.1.1 を返す。みたいな設定を入れていく。
- 左側メニューの
Access -> Tunnelsをクリック - 先程作ったTunnel名の右側にある
Configureをクリック Public HostnameをクリックAdd a public hostnameボタンをクリック- (1行目 Public hostname と書かれた行の話。インターネットから見える名前の設定)
Subdomainに好きな名前 (例文の場合だと myapp) を入れるDomainはCfに登録されているドメインが列挙されるのでその中から選択する- (ここで
Warning: No DNS record found for this domain. The policy may not execute as expected.と表示されるが無視してよい) Pathはあれば入力する(myapp.example.com/app -> 192.168.1.1/app になると思われる)- (2行目 Service と書かれた行の話。自宅LAN内のどこにトンネルするかの設定)
TypeはWebならHTTPになるはず。選択肢から適切なのを選ぶURLにLAN内でのURLのhttp:// を除外した部分を入れる。 (例: 192.168.1.1:3000)Save Hostnameボタンを押す
これで、myapp.example.com にアクセスすると、LAN内のWebアプリが見えるはず。
ちなみに、自動的にCfの証明書が発行され、httpsアクセスになる。
以前の手順より遥かに簡単になった。すごい。
蛇足
インターネットからアクセスしたいけど自分だけ使いたい
上記の設定に加えて以下を行うことで可能。(FreeプランOK)
先程作成した、 myapp.example.com として説明する。
- Cloudflare(以下Cf) のダッシュボードにログイン
- 左側メニューから
Zero Trustをクリック - 左側メニューの
Access -> Applicationsをクリック Add an applicationボタンをクリックSelf Hostedをクリック- (1行目)
Application nameは好きな名前を入れる- (2行目 Application domain)は先程作成済みのものを入力する
Subdomainは myapp を入力Domainは example.com を入力Pathは入力していれば入力(今回の例であれば空欄)- 右上の
Nextボタンを押す - (誰にアクセスを許可するかの設定)
Policy nameに適当な名前をいれる。 onlyme とか- 下の方にある
Create additional rulesに あるSelectorをEmailsにする Value欄にあなたのメールアドレスを入力- 右上の
Nextボタンを押す - 右上の
Add Applicationボタンを押す
再度、 myapp.example.com にアクセスすると以下のような画面でログインを要求される。
ここにメールアドレスを入力すると認証コードが送られてきて(メール内にリンクもある)ログインするとLAN内のWebアプリが表示できる。
このポリシー周りの設定は色々できるようなので研究のしがいがありそう。
この手順では適当にメールアドレスだけで認証しているけれども、ここでYubicoとかが使える…と思われる。

ちなみに、毎度毎度認証が必要になるわけではなく、普通のセッションと同じように一定時間内に使い続けていれば再認証は不要なようだ(デフォルトでは24時間以内)
追記の蛇足
- Type欄、SMBとかSSHとかがあるので色々とすごいことができそう
:::message alert
以下は古いと思われる手順です(今も動くとは思いますが検証していません)
:::
まえがき
前提
- 自宅サーバーでいくつかのサービスを動かしていて、それをインターネットに公開したい
- IPoE (DS-Lite or MAP-E) を使っているのでパブリックIPv4アドレスを持っていない^[語弊がある表現だけれどもとりあえず無視して]
制限事項
- Cloudflareのネームサーバーを使っているドメインでしかこの方法は使えない^[Google Domainsのネームサーバーを使っているドメインで実験したが、応答しないようになっていた]
- ドメインを移管する必要はない^[namecheapで管理していて、DNSだけcloudflareなドメインでも正常に動いた]が、DNSはCloudflareに向けておく必要がある
メリット
- SSL証明書はcloudflareが自動的に発行してくれる。発行元がcloudflareになる。
- SSL証明書の更新作業は不要。cloudflare側で行われる。
- IPv6に自動的に対応。トンネルがIPv4であってもIPv6のIPアドレスも自動的に割り当てられる。逆にいえばIPv6のトラフィックが流れてきてしまう(設定でIPv6はオフにもできる)
- ngrokのように、ローカルのアプリケーションをかんたんに一時的に公開するのにも使える(本記事のスコープ外)
デメリット
- ネームサーバーをcloudflareに向けていないと使えない
手順
前提として、cloudflareにサイト(ドメイン)が登録されている状態であること
難しそうな話がでてくるが、普通に Free プランで使える。
Zero Trust の設定画面を起動する
なんというか…すごい難しそうなことが書かれているが、通常のダッシュボードと別のところにあるからリンクをたどってください。という話。
初回は、Teamの名前を決めろみたいな質問が表示されるので適当に名前を入れる。^[なお、この名前は少なくともTunnelを使うだけなら表に出ることはないと思われます。]

Tunnelの設定
左側メニューの Access -> Tunnels にある。
初回は Create Tunnel のTutorialがあるのでそこに従うと楽…ですが。
複数のサイト(ここでいうサイトはホスト名の数)を公開したい場合は、設定ファイルをTutorialで表示されるものから変更する必要があります。
ちなみに、手順はLinux環境で作っています。Windows等でもおそらくほとんど同じだと思いますが、適宜読み替えてください。
手順1 cloudflared をインストール
省略。 githubのcloudflaredリポジトリ からバイナリを取得してインストール。 .debなら dpkg -i 、普通のバイナリなら展開して chmod + 等してください。
ちなみに、普通のバイナリを適当において実行すると自動アップデート機能があるみたいです。^[が。自動アップデートがかかるとその間トンネルが切断されるので良し悪し…]
手順2 cloudflared でログイン
cloudflared tunnel login
ブラウザが開くが、そういう環境ではない場合は表示されたURLに別のマシンからアクセスして認証する。認証が終わるとブラウザにこのウィンドウは閉じて良い。というメッセージが表示されるので閉じる。
手順3 トンネルを作る
cloudflared tunnel create すきな名前
トンネルは再生成しないので(しても良いんだけども)本番用の名前で作って大丈夫。
とてもかんたん。ちなみにサイトが複数あってもトンネルは一つで大丈夫。
ここで表示されたTunnel ID が内部的なホスト名に使用される。
ちなみに、この時点で設定ファイルは ~/.cloudflared に作成される。
手順4 設定ファイルを作る
ここが一番書きたかったところ。Tutorialで表示される設定ファイルは1サイト用なので複数サイトの場合は書き方が異なる。 ファイル名は ~/.cloudflared/config.yaml とした
1 | # url: http://localhost:80 |
1行目 url Tutorialではこの項目があるが、複数サイト使う場合はこの項目は書かない
2行目 tunnel 先ほど作成したtunnelのIDを入れる。
3行目 credentials-file ログインした再に作成されたファイルのパス。 ~/.cloudflared/tunnel-id.json にあるはず。この例は後々の手順まで終わった後なのでパスが異なっている
6行目 ingress ここの下にサイト(ホスト名+ドメイン名)とプロキシするURLを記述する
7行目 hostname ホスト名+ドメイン名。 ドメイン名はcloudflareに登録されているものなら指定できる。
8行目 service cloudflaredを実行しているサーバーからアクセスできるURL
(hostname , service を必要な数だけ繰り返す)
13行目 service: http_status:404 最後はこの行を入れる必要がある(入れないとcloudflaredが起動しない)
手順5 cloudflareのDNSにトンネルを登録する
cloudflared tunnel route dns トンネル名 ホスト名+ドメイン名(blog.example.com)
これでcloudflare内のDNSが更新される。
具体的には CNAME <tunnel-id>.cfargotunnel.com が指定される。
逆に言えば、このレコードを手動で作って上記configにそのホスト名+ドメイン名が書いてあれば^[cloudflaredが実行中な場合、設定ファイルを書き換えたらcloudflaredの再起動も必要です] 自動的にトンネルされる。
手順6 サービス登録
cloudflared service install
これでsystemdのサービスが登録される。 多分enableにはなっていないので、別途systemctl enable cloudflared は必要なはず。
なお、インストール方法によっては、 cloudflared-update.service と cloudflared-update.timer も作成されている。 cloudflared-update.timerをenableにすると自動アップデートが可能。
蛇足
接続元ポートをhttpヘッダに入れてもらう
実は書きたかったことその2。
DS-LiteやMAP-EなどのキャリアグレードNATがされている環境の場合、IPv4アドレスだけをログに出力しても接続元を特定することができません。 アクセスログには接続元ポート番号も必要です。
…が。 Cloudflareは標準でCF-Connection-IP というヘッダにIPアドレスはセットしてくれますが、ポート番号はセットしてくれません。(CF-Connection-Port とか作ってくれませんかね?)
そこで、Cloudflareの変換ルールを使って任意のヘッダにポート番号をセットしてもらうことができます。
変換ルールは、ドメインごとに設定が必要です(内容は同じでOK)
※ Zero Trustの設定画面ではなく、いつも見ている設定画面の方にあります。
変換ルールを作成ボタン → HTTPヘッダーを修正 から作成します。
入力内容:
- 名前
Add X-cloudflare-Connecting-Port(何でもOK) - 受信リクエストが一致する場合.. フィールド:
ホスト名 - 受信リクエストが一致する場合.. オペレータ:
次を含む - 受信リクエストが一致する場合.. 値:
.(ピリオド一つ。すべてのリクエストにマッチさせたい) - 実行内容..
Set Dynamic - 実行内容.. ヘッダー名
X-cloudflare-Connecting-Port - 実行内容.. 値
cf.edge.client_port
設定した場合の画面はこちらです。

https://community.cloudflare.com/t/need-cf-connecting-port-for-french-law/319505/7
あとは、nginx等の設定で、ログに X-cloudflare-Connecting-Port を出力するようにすればOKです。
nginxの場合の例 (LTSV出力)
1 | log_format apm 'time:$time_iso8601\t' |
別解
- VPNを使ってレンタルサーバー等と接続すれば実現できる。
- レンタルサーバーと言っても、Oracle CloudのAlways Free枠で十分なのでこれならお金はかからない。
- 有料のレンタルサーバーでも Vultrとかlinodeのミニマムなプランで十分なので$5/月 くらい
- VPNの設定も https://tailscale.com/ を使えば楽にできる