docker『Connection Refused』の原因と対処法
- 作成日 2025.11.18
- その他
「Connection refused」は、TCPレベルで「そのアドレス・ポートに対応するプロセスが現在いない」ことを意味する。Dockerでは、コンテナ内アプリが指定ポートで待ち受けていない、ホスト側ポートのマッピングミス、コンテナ間ネットワークの設定違い、ファイアウォールやプロキシの干渉、起動順の問題などで発生する。まず「どこからどこに」接続しているのかを明確にし、ホスト・コンテナ・ネットワークを切り分けることが重要になる。
- 1. エラーの意味と発生条件(まず押さえるポイント)
- 2. どこからどこに繋いでいるかを明確にする(3パターン)
- 3. ホスト→コンテナ:ポートマッピングとリッスンアドレスを確認
- 4. -p / ports の指定ミス(ポート番号の取り違え)
- 5. コンテナ→コンテナ:ホスト名・ネットワーク・ポートを揃える
- 6. コンテナ→外部サービス:接続先IP/ポートとFirewallを確認
- 7. アプリがまだ起動していない/クラッシュしている(起動順の問題)
- 8. localhostの勘違い(ホストとコンテナの名前空間の違い)
- 9. Docker Desktop / WSL2 / macOS / Windows の特殊ケース
- 10. デバッグ用ワンライナー(curl/ncで接続可否を可視化)
- 11. NG→OK早見(よくあるパターン別の修正例)
- 12. チェックリスト(上から順に潰す)
エラーの意味と発生条件(まず押さえるポイント)
「Connection refused」は以下の条件で発生する。
・接続先IP/ホスト名は解決できている(DNSはOK)。
・そのIPの指定ポートには、リッスンしているプロセスがいない、もしくはカーネルが受付を拒否している。
・docker環境では、次のようなときに出やすい。
- コンテナ内アプリがまだ起動していない、または異常終了している。
- アプリが127.0.0.1で待ち受けていて、0.0.0.0で公開されていない。
- -p / ports のマッピングが誤っている、またはポートが違う。
- コンテナ間で間違ったホスト名やポートを指定している。
- ホスト側のファイアウォールやセキュリティ製品が遮断している。
どこからどこに繋いでいるかを明確にする(3パターン)
dockerでの「Connection refused」は大きく3パターンに分けられる。
1) ホスト → コンテナ(ブラウザで http://localhost:8080 にアクセスなど)
2) コンテナ → 外部サービス(DBやAPIサーバ、SaaSなど)
3) コンテナ → コンテナ(docker compose で app → db など)
それぞれに対して、次のような順で確認するとよい。
・使っているIP/ホスト名・ポートの組み合わせは正しいか。
・実際に、そのIPのそのポートでプロセスがLISTENしているか。
・dockerのネットワークとポートマッピングの設定が意図通りか。
ホスト→コンテナ:ポートマッピングとリッスンアドレスを確認
# ホスト側で「どのポートが何のコンテナに繋がっているか」を確認
docker ps --format 'table {{.Names}}\t{{.Ports}}'
# Linux/macOSでポートのLISTEN状況を確認
ss -ltnp | grep 8080 || lsof -iTCP:8080 -sTCP:LISTEN
# コンテナ内でアプリがどこでLISTENしているかを確認
docker exec -it <container> sh -lc "netstat -ltnp || ss -ltnp"典型的なミスとして、アプリが127.0.0.1:8080で待ち受けており、コンテナ外部からは接続できないケースがある。
この場合、アプリ側の設定を0.0.0.0:8080で待ち受けるよう変更する。
# 例: Express(Node.js) の場合
app.listen(8080, '0.0.0.0', () => {
console.log('listening on 0.0.0.0:8080');
});-p / ports の指定ミス(ポート番号の取り違え)
# NG例: アプリはコンテナ内で8080待ち受けなのに、80をマップしている
docker run -p 80:80 myapp
# OK例: コンテナ内ポートに合わせてマッピング
docker run -p 8080:8080 myapp
# docker-compose.yml の例
services:
web:
image: myapp
ports:
- "8080:8080" # host:containerブラウザやcurlでアクセスしているポートと、ports の host側ポートが一致しているかを必ず確認する。
コンテナ→コンテナ:ホスト名・ネットワーク・ポートを揃える
docker compose での基本は「サービス名がDNS名になる」というルール。
# docker-compose.yml の例
services:
app:
image: myorg/app
depends_on:
- db
db:
image: postgres:16
environment:
- POSTGRES_USER=app
- POSTGRES_PASSWORD=secretこの場合、appコンテナからは「db:5432」で接続できる。
# appコンテナ内からDBに繋ぐ例
psql -h db -U app -d appdb
# よくあるNG例: localhost:5432 に繋ごうとしてしまう(自コンテナの中を見にいく)
DATABASE_URL=postgres://app:secret@localhost:5432/appdb # ← コンテナ間ではNG
コンテナ間通信は、localhostではなくサービス名(またはコンテナ名)を使う。
コンテナ→外部サービス:接続先IP/ポートとFirewallを確認
# コンテナ内から接続テスト
docker exec -it <container> sh -lc "
nc -vz db.example.com 5432 || echo 'ng'
"
# DNS名が間違っていないかも確認
docker exec -it <container> sh -lc "ping -c1 db.example.com || nslookup db.example.com"
社内ネットワークやクラウド環境では、FW・セキュリティグループ・セグメントの制約で「そもそもポートが空いていない」ことも多い。この場合はdocker側ではなくインフラの設定を見直す。
アプリがまだ起動していない/クラッシュしている(起動順の問題)
コンテナ自体は起動しているが、アプリケーションがクラッシュしていたり初期化中で、ポートが開いていない時間帯にアクセスしている場合も「Connection refused」となる。
# ログでアプリの起動状況を見る
docker logs <container> --tail=200
# 再起動を繰り返している場合(Exit Codeが非0)
docker ps -a --filter "name=<service>" --format 'table {{.Names}}\t{{.Status}}\t{{.ExitCode}}'
docker compose ではhealthcheckを定義し、依存サービスが「健康」になるまで待つことで起動順の問題を緩和できる。
services:
db:
image: postgres:16
healthcheck:
test: ["CMD-SHELL","pg_isready -U postgres"]
interval: 5s
timeout: 3s
retries: 10
app:
image: myorg/app
depends_on:
db:
condition: service_healthlocalhostの勘違い(ホストとコンテナの名前空間の違い)
「localhost」は「そのプロセスが動いているOSの中」の127.0.0.1を指す。
・ブラウザから http://localhost:8080 にアクセス → ホストの127.0.0.1:8080に接続。
・コンテナ内から localhost:8080 にアクセス → コンテナ内の127.0.0.1:8080に接続。
よくあるミス:appコンテナからdbコンテナへ接続するのに「localhost:5432」を使ってしまう。
正しくは、docker composeで定義したサービス名(dbなど)を使う。
Docker Desktop / WSL2 / macOS / Windows の特殊ケース
Docker Desktop環境では、ホストOS・VM・コンテナの間にレイヤがある。
・Windowsで「localhost」にブラウザからアクセス → 基本的にはVMのポートフォワードを経由。
・WSL2内でcurl http://localhost:8080 → WSL2のLinux側のlocalhostに接続。
テストするときは、必ず「どの層でコマンドを打っているか」を意識する。
# WSL2内からホストWindows側にアクセスする場合のIP例
ipconfig.exe | grep "vEthernet (WSL)" -n -A5
環境によっては、127.0.0.1ではなく特定のブリッジIPに向けてアクセスする必要がある。
デバッグ用ワンライナー(curl/ncで接続可否を可視化)
# ホスト側から
curl -v http://localhost:8080/health || echo "ng"
nc -vz localhost 8080
# コンテナ側から
docker exec -it <container> sh -lc "
echo '--- from container ---'
nc -vz web 8080 || nc -vz localhost 8080
"
「どこから打つと通って、どこから打つとrefusedになるか」をテーブルにすると原因特定が早くなる。
NG→OK早見(よくあるパターン別の修正例)
# 1) アプリが127.0.0.1でLISTENしている
# NG:
app.listen(8080, '127.0.0.1');
# OK:
app.listen(8080, '0.0.0.0');
# 2) ポートマッピングミス
# NG: コンテナ内ポートと違う
docker run -p 8080:80 myapp
# OK: 正しいポートをマップ
docker run -p 8080:8080 myapp
# 3) コンテナ間接続でlocalhostを使う
# NG:
DATABASE_HOST=localhost
# OK:
DATABASE_HOST=db # サービス名
# 4) DB起動前にappが繋ぎに行く
# NG: depends_onだけ
depends_on:
- db
# OK: healthcheck + condition
depends_on:
db:
condition: service_healthyチェックリスト(上から順に潰す)
1) どこからどこへ繋ぎにいっているか(ホスト→コンテナ/コンテナ→コンテナ/コンテナ→外部)を明確にしたか
2) 接続先IP/ホスト名とポートが正しいか、portsのhost:container対応と合っているか
3) コンテナ内のアプリが0.0.0.0:ポートでLISTENしているか(127.0.0.1ではないか)
4) コンテナ間接続でlocalhostを使っていないか(サービス名を使っているか)
5) アプリは起動に成功し、そのポートで待ち受けているか(ログと状態を確認したか)
6) 外部サービスに対して、Firewall/セキュリティグループ/プロキシが邪魔していないか
7) Docker Desktop/WSL2の場合、階層(ホスト/VM/WSL)を理解して疎通確認したか
8) curl/ncで、どのレイヤからも接続テストを行い、通る/通らない組み合わせを確認したか-
前の記事
docker『Image Not Found』の原因と対処法 2025.11.17
-
次の記事
docker『Invalid Reference Format』の原因と対処法 2025.11.19
コメントを書く