VPS構築編・アプリ運用編では、自作トレードシステム Logical225 を ngrok の無料固定ドメインで公開していた。これを Cloudflare Tunnel に移行し、独自サブドメイン trade.codeontheroad.jp + HTTPS + 認証ゲートを全部無料で実現した記録。
なぜ ngrok から乗り換えるのか
ngrok でも「固定URL + HTTPS」は手に入る。ただ本番運用には物足りなかった。
- アクセス時に ngrok の警告ページが挟まる(無料の仕様)
- 認証を前段に置けない — 売買できるダッシュボードを、URLを知っていれば誰でも開ける状態にしたくない
- 自分のブランドドメインで見せたい
これらをまとめて解決できるのが Cloudflare Tunnel + Cloudflare Access。しかも無料枠で収まる。
選択肢の比較
| ngrok 無料 | Cloudflare クイックトンネル | Cloudflare 通常トンネル | |
|---|---|---|---|
| URL | 固定(xxxx.ngrok-free.app) | ランダム・毎回変わる | 自分のドメイン |
| ドメイン要否 | 不要 | 不要 | 必要(Cloudflare管理) |
| 認証(Access) | × | × | ○(無料枠あり) |
| 警告ページ | あり | なし | なし |
| 本番向き | △ | ✕(テスト用) | ◎ |
「手軽さだけ」なら ngrok の固定ドメインで十分。認証付きで本番公開したいから通常トンネルを選ぶ。
Cloudflare Access とは
公開URLに誰かがアクセスすると、アプリに届く前に Cloudflare のログイン画面が出る仕組み。許可した人だけが通過できる。
- 認証方法はメールのワンタイムコード(OTP) が手軽(IdP設定不要)。Google/GitHub などのSSOも可
- 認証は Cloudflare のエッジ(手前) で行われるので、未認証のリクエストは VPS まで到達しない
- 無料プランで 50ユーザー / 50アプリまで。個人利用なら無料枠内
構成
codeontheroad.jpはバリュードメインで取得、ブログは Vercel(apex)で稼働- ブログはそのまま
codeontheroad.jpで動かし続ける(無変更) - トレード用に サブドメイン
trade.codeontheroad.jpを新設
ゴール: https://trade.codeontheroad.jp で Logical225 を HTTPS + 認証で公開。
フェーズ1: DNSを Cloudflare へ移す
Cloudflare Tunnel は「ゾーンが Cloudflare 管理下」であることが条件。無料では部分移管できないので、ドメイン全体のネームサーバを Cloudflare に向ける。ブログを壊さないよう、レコードを完全に引き継ぐのが肝。
- Cloudflare に
codeontheroad.jpを追加(プラン Free) - 既存DNSレコードを引き継ぐ
- バリュードメインでネームサーバを Cloudflare の2つに変更
- ステータスが Active になり、ブログが正常表示されることを確認
ハマり①: 自動スキャンが0件 → 手動で登録
Cloudflare の自動スキャンが既存レコードを0件しか拾えなかった(レジストラによってはよくある)。なので手動で登録した。今回は apex の A レコード1件だけ:
Type: A / Name: @ / IPv4: 216.198.79.1 / Proxy: DNS only(グレー雲)
**Vercel 向けのレコードは必ず「DNS only(グレー雲)」**にする。Cloudflare のプロキシ(オレンジ雲)を通すと二重CDNになり、ブログのSSLが不安定になる。
ハマり②: ドメイン名のタイポで pending 地獄
ネームサーバを変えたのに、何時間経っても pending(Active にならない)。原因は、Cloudflare に追加したドメイン名をタイポしていたこと(codeontheroad.jp の先頭の c が抜けた別物を登録していた)。
切り分けに使えたのが dig。割り当てられたネームサーバに正しいドメインを直接問い合わせると REFUSED(=そのゾーンを持っていない)が返ってきた:
dig codeontheroad.jp SOA @<割り当てられたNS>
# status: REFUSED ← このNSは codeontheroad.jp を担当していない
→ 登録ドメイン名のミスを疑い、間違ったゾーンを削除して正しい codeontheroad.jp で追加し直したら解決。
注意: Cloudflare のゾーンを Remove → 再Add すると、割り当てネームサーバが変わることがある。実際に変わったので、レジストラ側のネームサーバも新しい値に更新した。
再追加後、.jp の委任と Cloudflare の応答が一致して Active。apex も 216.198.79.1 に解決し、ブログは無傷で動き続けた。
フェーズ2: Tunnel を立てて VPS に常駐させる
Zero Trust Free の有効化(カード登録に注意)
Cloudflare の Zero Trust ダッシュボード(one.dash.cloudflare.com)を初めて開くと、チーム名とプラン選択を求められる。Free を選んでも「支払い方法の登録」が必須で少し驚くが、請求は $0。無料枠(50ユーザー)を超えなければ課金されない(個人利用なら超えない)。
cloudflared をサービス導入
- Zero Trust → Networks → Tunnels → Create a tunnel → コネクタは Cloudflared → 名前を付けて保存
- 環境で Windows / 64-bit を選ぶ
- 案内どおり VPS で:
- MSI をダウンロードして実行(cloudflared 本体)
- 管理者でコマンドプロンプト/PowerShell を開き、トークン入りコマンドを実行
cloudflared.exe service install eyJ...(トークンは秘密。表示はコピーボタンで全文取得)
これで cloudflared が Windows サービスとして常駐インストールされる(=再起動後も自動起動)。実行ログに installed successfully が出て、ダッシュボードのコネクタが Connected になればOK。
🔒 トークンは秘密情報。これを持っていれば誰でもこのトンネルを起動できてしまう。漏れたら Tunnel → Refresh token で再発行する。
公開ホスト名を設定
トンネルの Public Hostname に次を登録:
Subdomain: trade / Domain: codeontheroad.jp / Service: HTTP → localhost:3000
trade のDNS(CNAME・プロキシon)は Cloudflare が自動作成する。これで https://trade.codeontheroad.jp が、Cloudflare 発行の有効な証明書付きで開通した(VPSのポート開放は不要)。
フェーズ3: 認証(Cloudflare Access)
この時点ではURLを知っていれば誰でも開ける状態。売買システムなので、すぐ認証を付ける。
- Zero Trust → Access → Applications → Add an application
- Public DNS(公開ホスト名のアプリ)→ Self-hosted
- Public hostname に
trade.codeontheroad.jp - ポリシー: Action Allow / Include → Emails → 自分のメールアドレス
- ログイン方法は One-time PIN(メールOTP)
- 保存
ハマり③: 「設定したのに未ログインで見える」
保存直後に「未ログインでもアクセスできてしまう」ように見えた。原因は同じブラウザに前のセッションが残っていただけ。シークレットウィンドウで確認すると、ちゃんと Cloudflare のログインへリダイレクトされた:
curl -sS -o /dev/null -w "%{http_code}" https://trade.codeontheroad.jp/
# 302 → https://<team>.cloudflareaccess.com/cdn-cgi/access/login/...
未認証アクセスは Cloudflare 側で 302 リダイレクトされ、VPS まで到達しない。許可したメールで OTP ログインした時だけ Logical225 が開く。
できたこと
https://trade.codeontheroad.jpで 独自ドメイン + 有効なHTTPS- Cloudflare Access で許可メールのみアクセス可(前段認証)
- cloudflared は サービス常駐(再起動後もトンネルは自動復活)
- ngrok は役目を終えたので停止
- ぜんぶ無料枠
注意: 「常駐」したのはトンネルだけ
cloudflared をサービス化したのでトンネル自体は再起動後も自動復活する。ただし——
| 対象 | 再起動後 |
|---|---|
| cloudflared(トンネル) | ✅ 自動復活 |
| Cloudflare Access(認証) | ✅ 有効のまま |
Logical225 本体(localhost:3000) | ❌ 起動しない |
| kabuステーション | ❌ 起動しない |
つまり今 VPS を再起動すると、trade.codeontheroad.jp は開けるが中身が動いておらず 502 になる。トンネルは生きているのに、その先のアプリが落ちている状態だ。
次回予告: 常駐化編
残るはアプリ本体の常駐。
- Logical225 を PM2 / タスクスケジューラで自動起動
「再起動しても、人が触らずに売買が再開する」状態を目指して、次は常駐化に取り組む。
シリーズ: