リバースプロキシ:1 つのアドレスで複数のアプリケーション
1 つの公開 VDS アドレスをドメインとパスで複数のアプリケーションに振り分ける方法、ヘッダーを正しく渡す方法、WebSocket を壊さない方法について説明します。
更新日 2026年8月23日
1台のマシンにはパブリックIPv4アドレスが1つしかありませんが、通常は複数のアプリケーションが動作しています。リバースプロキシはポート80と443へのすべてのリクエストを受け取り、ドメイン名またはパスに基づいて内部サービスへルーティングします。また、単一の証明書と共有ログも保持します。
レイアウト
各アプリケーションは独自のローカルポートで、127.0.0.1のみをリッスンします。
- フロントエンドサイト —
127.0.0.1:3000 - API —
127.0.0.1:8000 - 監視ダッシュボード —
127.0.0.1:9090
外部に公開されるのはNginxのみです。アプリケーションが直接公開されていないことを確認するには:
ss -tulpn | grep LISTEN
0.0.0.0:3000のような行は、プロキシを経由せず、暗号化もなしにインターネットからサービスに到達できることを意味します。
ドメイン別
server {
listen 80;
server_name app.example.ru;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name api.example.ru;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
X-Forwarded-Forがないと、アプリケーションはすべてのリクエストが127.0.0.1から来たと認識し、IPベースの制限が機能しなくなります。
パス別
location /api/ {
proxy_pass http://127.0.0.1:8000/;
}
ここではproxy_passの末尾のスラッシュが重要です。スラッシュがある場合、/apiプレフィックスが削除され、アプリケーションは/usersを受け取ります。スラッシュがない場合は/api/usersを受け取ります。プロキシで発生する「謎の404」の半分は、まさにこれが原因です。
WebSocketと長い応答
location /ws/ {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
Upgrade/Connectionのペアがないと、ハンドシェイク直後に接続が切断されます。タイムアウトを延長しないと、1分間の無通信後に切断されます。
よくある間違い
| 症状 | 原因 |
|---|---|
502 Bad Gateway | アプリケーションが起動していない、または別のポートでリッスンしている |
504 Gateway Time-out | アプリケーションの応答がproxy_read_timeoutより遅い |
| 無限リダイレクト | アプリケーションがHTTPSを認識していない — X-Forwarded-Protoを渡してください |
| ファイルアップロードが失敗する | client_max_body_sizeが小さすぎる。デフォルトは1 MB |
| アプリケーションログに同じIPが記録される | X-Forwarded-Forが渡されていない |
プロキシ上の1つの証明書が、その背後にあるすべてのアプリケーションをカバーします。
127.0.0.1経由の内部接続はマシンから出ないため、暗号化は不要です。