flowchart TB
client["Mac / iPhone"]
subgraph Cloudflare
waf["WAF + Access 認証"]
tunnel["Cloudflare Tunnel"]
end
subgraph Docker["Docker (tunnel-net)"]
cloudflared["cloudflared"]
nginx["nginx"]
end
subgraph Host["ホスト: 開発サーバー"]
app1["localhost:3000"]
app2["localhost:5173"]
app3["localhost:8080"]
end
client -->|HTTPS| waf
waf --> tunnel
tunnel --> cloudflared
cloudflared --> nginx
nginx -->|"app1.ryuki-sasaki.com"| app1
nginx -->|"app2.ryuki-sasaki.com"| app2
nginx -->|"app3.ryuki-sasaki.com"| app3
- Docker Desktop がインストール済み
- Cloudflare アカウントを持っている
- ドメインが Cloudflare の DNS に登録済み
- Cloudflare Zero Trust Dashboard にログイン
- Networks → Tunnels → Create a tunnel
- Tunnel type: Cloudflared を選択
- Tunnel 名を入力(例:
dev-tunnel) - 表示される TUNNEL_TOKEN をコピー
Tunnel の設定画面で、各プロジェクトのホスト名を追加:
| Subdomain | Domain | Service Type | URL |
|---|---|---|---|
| app1 | ryuki-sasaki.com | HTTP | nginx:80 |
| app2 | ryuki-sasaki.com | HTTP | nginx:80 |
| app3 | ryuki-sasaki.com | HTTP | nginx:80 |
すべてのサブドメインの Service URL は
nginx:80(Docker ネットワーク内の nginx コンテナ)
- Access → Applications → Add an application
- Self-hosted を選択
- 設定:
- Application name:
Dev Apps - Session Duration: 任意(例: 24 hours)
- Application domain:
*.ryuki-sasaki.com(またはサブドメインごとに個別設定)
- Application name:
- Policy を追加:
- Policy name:
Allow me - Action: Allow
- Include rule:
- Emails: 自分のメールアドレスを入力
- または Login Methods: Google / GitHub を選択
- Policy name:
- Save
これにより、アクセス時に認証画面が表示され、許可されたユーザーのみ閲覧可能になる
cd ~/documents/tunnel
cp .env.example .env.env を編集し、コピーした TUNNEL_TOKEN を設定:
TUNNEL_TOKEN=eyJhIjoixxxxxxxxx...
nginx/default.conf の server_name は app1.* のようなワイルドカードになっているため、
ドメインに関係なく動作する。変更不要。
cd ~/documents/tunnel
docker compose up -ddocker compose ps
docker compose logs -f # 全コンテナのログ
docker compose logs -f cloudflared # cloudflared のみ
docker compose logs -f nginx # nginx のみdocker compose down例: app4.ryuki-sasaki.com → localhost:4000 を追加する場合
nginx/default.conf に以下の server ブロックを追加:
server {
listen 80;
server_name app4.*;
include /etc/nginx/conf.d/security.inc;
location / {
proxy_pass http://host.docker.internal:4000;
include /etc/nginx/conf.d/proxy.inc;
}
}Tunnels → 対象 Tunnel → Public Hostname → Add a public hostname:
- Subdomain:
app4 - Domain:
ryuki-sasaki.com - Service Type: HTTP
- URL:
nginx:80
リファレンスとしてエントリを追加。
docker compose restart nginxnginx/default.confから該当の server ブロックを削除- Cloudflare Dashboard から該当の Public Hostname を削除
docker compose restart nginx
docker compose logs cloudflaredTUNNEL_TOKENが正しいか確認- Docker ネットワークが正常か確認:
docker network ls
- ローカルの開発サーバーが起動しているか確認
- nginx のログを確認:
docker compose logs nginx - ホストからのアクセスを確認:
curl http://localhost:3000
- Vite の場合、
vite.config.tsで以下を設定:
export default defineConfig({
server: {
hmr: {
// Cloudflare Tunnel 経由の場合
clientPort: 443,
protocol: 'wss',
},
},
})- Next.js / Webpack の場合は通常設定不要(WebSocket は nginx 経由で通る)
Windows + WSL2 の場合、開発サーバーは 0.0.0.0 でリッスンする必要がある:
# Vite の場合
vite --host 0.0.0.0
# Next.js の場合
next dev -H 0.0.0.0この構成では以下のレイヤーで保護されている:
- Cloudflare Access: Google/GitHub 認証で自分だけがアクセス可能
- Cloudflare WAF: 基本的な攻撃を自動ブロック
- nginx セキュリティヘッダ: X-Frame-Options, X-Content-Type-Options 等
- 機密パスブロック:
.env,.git,node_modulesへのアクセスを 403 で拒否 - Docker ネットワーク分離: cloudflared と nginx のみが通信
- デフォルト拒否: 未定義のサブドメインは 444 で切断