できない.dev

curl「(7) Failed to connect」の原因と直し方

curl: (7) Failed to connect は、名前は引けたがそのホストとポートで待ち受けるサーバーが無いと出る。
サーバーの起動とポート番号、待ち受けるアドレス、コンテナの中の localhost の意味を順に確かめれば直る。

公開:

要約

curl: (7) Failed to connect は、ホスト名の解決までは済んだが、そのアドレスとポートへの TCP 接続を相手に拒まれたときに出る。
curl 8.23.0 で何も待ち受けていないポートを指すと、次の表示になり終了コード 7 で終わった。

curl: (7) Failed to connect to localhost:8000 after 0 ms: Could not connect to server

curl 8.14.1 では localhost port 8000 のように書き方が少し違ったが、番号の 7 と意味は同じである。そのホストとポートで待ち受けているプロセスが無いので、curl の設定より先にサーバー側を確かめる。

解決策

1. 待ち受けているプロセスとポートを確かめる

-v を付けると、どのアドレスへの接続が拒まれたかが行ごとに出る。

* connect to ::1 port 8080 from ::1 port 42604 failed: Connection refused
* connect to 127.0.0.1 port 8080 from 127.0.0.1 port 35616 failed: Connection refused
curl: (7) Failed to connect to localhost port 8080 after 0 ms: Could not connect to server

IPv6 と IPv4 の両方で Connection refused なら、そのポートでは何も待ち受けていない。
サーバーのログで実際に待ち受けているポートを確かめ、URL を合わせる。

2. 待ち受けるアドレスを 0.0.0.0 にする

外から呼ぶサーバーは、すべてのアドレスで待ち受けさせる。

python -m http.server 8000 --bind 0.0.0.0

待ち受けを 0.0.0.0 に変えると、別のコンテナからの同じ curl が 200 を返した。
Node.js や Flask などの開発サーバーも、待ち受けるホストの設定に同じ考え方で 0.0.0.0 を渡す。

3. コンテナからはコンテナ名か host.docker.internal で呼ぶ

ユーザー定義ネットワークに入ったコンテナどうしは、コンテナ名で互いを呼べる(新しいタブで開く)。
Compose ならサービス名を使う。

docker network create app-net
docker run -d --name api --network app-net python:3.12 python -m http.server 8000
docker run --rm --network app-net curlimages/curl -sS http://api:8000/

ホストで動いているサービスや、ホストに公開したポートを呼ぶなら、Docker Desktop では host.docker.internal を使う。http://host.docker.internal:18010/ に変えると 200 が返った。

番号が違うときは別の原因

ポートを公開したコンテナの中でサーバーが 127.0.0.1 だけで待ち受けていると、ホストからの curl は (7) ではなく (52) Empty reply from server になった。
接続自体は Docker のポート転送が受けるためである。
この場合も直し方は解決策 2 と同じになる。

よくある原因

  1. サーバーが起動していない。
    起動直後に例外で落ちている場合も同じエラーになる。
  2. ポート番号が違う。
    8000 で動いているサーバーに 8080 で接続すると、名前は引けても (7) になった。
  3. サーバーが 127.0.0.1 だけで待ち受けている。python -m http.server 8000 --bind 127.0.0.1 のコンテナに、同じネットワークの別のコンテナからコンテナ名で接続すると (7) になった。
    同じコンテナの中から 127.0.0.1 で呼ぶと 200 が返る。
  4. コンテナの中の localhost はそのコンテナ自身を指す。
    ホストの 18010 番に公開したサーバーへ、別のコンテナから localhost:18010 で接続すると (7) になった。