エラーの概要
502 Bad Gateway は、Docker コンテナ内で実行されるアプリケーションやリバースプロキシが、上流のサーバーから不正な応答を受け取ったときに発生します。Docker Compose や Kubernetes でマルチコンテナを運用する環境では、コンテナ間通信の失敗、プロキシ設定のミス、ネットワーク分断などが典型的な原因です。特に、Nginx や Apache をリバースプロキシとして使用している場合に頻出します。
実際のエラーメッセージ例
Bad Gateway
The proxy server received an invalid response from an upstream server.
{
"error": "bad_gateway",
"message": "502 Server Error: Bad Gateway for url: http://upstream-service:8080/api",
"timestamp": "2024-01-15T10:30:45Z"
}
$ curl -v http://localhost:80/api
< HTTP/1.1 502 Bad Gateway
< Server: nginx/1.21.0
< Content-Type: text/html
よくある原因と解決手順
原因1:上流コンテナが起動していない、またはヘルスチェックに失敗している
上流アプリケーション(Node.js、Python、Java など)が起動に失敗していたり、クラッシュしていたりする場合、プロキシは接続できずに 502 を返します。
Before(エラーが起きている設定)
version: '3.8'
services:
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
- app
app:
image: myapp:latest
# ヘルスチェックがない、起動スクリプトが不安定
After(修正後)
version: '3.8'
services:
nginx:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
depends_on:
app:
condition: service_healthy
app:
image: myapp:latest
ports:
- "8080"
environment:
- NODE_ENV=production
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 10s
timeout: 5s
retries: 3
start_period: 20s
原因2:プロキシ設定で上流サーバーのアドレス・ポートが誤っている
Docker Compose のネットワーク内では、サービス名が DNS として解決されます。ホスト名やポート番号を誤ると接続失敗になります。
Before(エラーが起きている設定)
upstream backend {
server app:3000; # 実際は8080で起動している
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
After(修正後)
upstream backend {
server app:8080; # 正しいポート番号を指定
keepalive 32;
}
server {
listen 80;
location / {
proxy_pass http://backend;
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;
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
}
}
原因3:Docker ネットワーク設定の不備またはコンテナ間通信の分断
複数のネットワークを使用している場合や、--net host モードの設定ミスがあると、コンテナ同士が通信できず 502 が発生します。
Before(エラーが起きている設定)
version: '3.8'
services:
nginx:
image: nginx:latest
networks:
- frontend
ports:
- "80:80"
app:
image: myapp:latest
networks:
- backend # nginx とは異なるネットワークに接続
After(修正後)
version: '3.8'
services:
nginx:
image: nginx:latest
networks:
- shared-network
ports:
- "80:80"
app:
image: myapp:latest
networks:
- shared-network # 同じネットワークに接続
networks:
shared-network:
driver: bridge
原因4:コンテナ内でアプリケーションが正しくバインドされていない
アプリケーションが localhost または 127.0.0.1 にのみバインドしている場合、Docker のネットワークインターフェース経由でのアクセスが拒否されます。
Before(エラーが起きている設定)
# Flask アプリケーション
app.run(host='127.0.0.1', port=8080) # localhost のみ
After(修正後)
# すべてのインターフェースにバインド
app.run(host='0.0.0.0', port=8080, debug=False)
Docker 固有の注意点
Docker Compose での Service Discovery
Docker Compose は自動的に各サービス用の DNS エントリを作成します。<service-name> でコンテナ間通信が可能です。ただし、depends_on では起動順序のみを制御し、サービスの準備状況は確認しません。必ず healthcheck と condition: service_healthy を組み合わせ てください。
Nginx プロキシの resolver 設定
Docker のネットワークで DNS が動的に変わる場合、Nginx の resolver 設定が必要になることがあります。
resolver 127.0.0.11 valid=10s;
upstream backend {
server app:8080;
}
ポートバインディングの確認
docker ps --format "table {{.Names}}\t{{.Ports}}"
このコマンドでポートがバインドされているか確認してください。コンテナ内ポートが外部に公開されていない場合、プロキシがアクセスできません。
ログの確認方法
# Nginx プロキシのエラーログを確認
docker logs <nginx-container-name>
# 上流アプリケーションのログを確認
docker logs <app-container-name>
# コンテナ内でプロキシ先への接続をテスト
docker exec <nginx-container-name> curl -v http://app:8080/health
それでも解決しない場合
確認すべきログとデバッグコマンド
Nginx の詳細ログを有効化して接続状況を確認してください。
# コンテナ内から対象サービスへの接続性をテスト
docker exec <nginx-container-name> wget -O- http://app:8080/
# DNS 解決の確認
docker exec <nginx-container-name> nslookup app
docker exec <nginx-container-name> getent hosts app
公式ドキュメント
Docker Compose のネットワーク設定については、Networking in Compose が詳細です。Nginx のプロキシ設定については Nginx Proxy Module Documentation を参照してください。
コミュニティリソース
GitHub の Docker Compose リポジトリ(docker/compose)や StackOverflow のタグ docker-compose では、同様の問題が多く報告されており、解決策が見つかる可能性が高いです。また、アプリケーション固有の設定(Flask、Express、Django など)の問題の可能性もあるため、該当アプリケーションのコミュニティも確認してください。
免責事項:本記事の内容は、執筆時点の公開情報をもとに作成したものです。ソフトウェアの仕様は予告なく変更されることがあります。最新の情報は各ツールの公式サポートページをご確認ください。本記事の情報を利用した結果生じたいかなる損害についても、著者および運営者は責任を負いかねます。
この記事でエラーは解決しましたか?