socatを使ってDockerコンテナ内からlocalhostでホストPCのサービスにアクセスする
devcontainer(Docker)で開発をしていると、たまにコンテナ内からホストPC上で動いているサービス(開発用APIサーバーなど)に接続したい場面があります。
しかしコンテナ内で localhost や 127.0.0.1 を指定すると、それはコンテナ自身を指すため、ホストPCには届きません。
この問題の一般的な解決策は、Dockerが用意した特殊なホスト名 host.docker.internal を使うことです。
このホスト名はホストPCのIPアドレスに解決されるため、コンテナ内からホストのサービスにアクセスできます。
弊社ブログでも、host.docker.internal を使った接続方法が紹介されています。
localhost や 127.0.0.1 が固定されていて変えられない場合
では、コードの接続先URLを変えられない場合はどうすれば良いでしょうか?
host.docker.internal を使うには、接続先のURLが変更可能でないといけません。
既存コードに localhost や 127.0.0.1 がハードコードされていて変更できないケースもあります。
そういったときに役立つのが、socatを使ったポートリレーです。socat のコンテナをリレー役として挟むことで、 アプリケーションのコードを一切変えずに localhost 接続をホストPCへ中継できます。
これを試してみました。
最初に結論
alpine/socat を使ったリレーサービスを追加します。
services:
proxy-relay:
image: alpine/socat:latest
command: TCP-LISTEN:80,fork,reuseaddr TCP-CONNECT:host.docker.internal:3000
my-app:
image: curlimages/curl:latest
command: [ "sleep", "infinity" ]
network_mode: "service:proxy-relay"
depends_on:
- proxy-relay
my-app コンテナ内から http://localhost/ でアクセスすると、 proxy-relay がホストPCの 3000 番ポートへ中継します。
イメージ的にはこんな感じです。
socatとは
socat(SOcket CAT)は、2つのデータストリーム間でデータを双方向に中継するコマンドラインツールです。TCP、UDP、UNIXソケット、ファイルなど様々なデータチャンネルに対応しています。
- 参考:socat
今回は alpine/socat というDockerイメージを使います。
Alpine Linuxベースの軽量イメージで、Docker Composeのサービスとして簡単に組み込めます。
実装手順
前提環境
- Docker、Docker Composeがインストール済み
docker-compose.ymlの設定
以下の例では、ホストPCの 3000 番ポートで動いているサービスにコンテナ内から接続できるようにします。
services:
# ホストPCへの中継サービス
proxy-relay:
image: alpine/socat:latest
command: TCP-LISTEN:80,fork,reuseaddr TCP-CONNECT:host.docker.internal:3000
## Linux環境の場合必要
# extra_hosts:
# - host.docker.internal:host-gateway
# アプリケーションサービス(例)
my-app:
image: curlimages/curl:latest
command: ["sleep", "infinity"]
network_mode: "service:proxy-relay"
depends_on:
- proxy-relay
socat コマンドの各パラメーターの意味は次のとおりです。
| パラメーター | 説明 |
|---|---|
TCP-LISTEN:80 |
80 番ポートでTCP接続を待ち受ける |
fork |
接続ごとに子プロセスを作成し、複数接続を並行処理する |
reuseaddr |
ソケットをすぐに再利用できるようにする |
TCP-CONNECT:host.docker.internal:3000 |
ホストPCの 3000 番ポートへ転送する |
extra_hosts: host.docker.internal:host-gateway はLinux環境で必要な設定です。
macOSとWindowsでは host.docker.internal が標準で使えますが、Linuxでは明示的に追加する必要があります。
network_mode: "service:proxy-relay" を指定すると、my-app コンテナは proxy-relay のネットワーク名前空間を共有します。これにより my-app 内の localhost が proxy-relay 自身のループバックインターフェースを指すようになり、socat が待ち受けているポートへ届きます。
動作確認
実際に動作確認してみます。ホストPCでPythonの簡易HTTPサーバーを起動します。
# ホストPCで実行
$ python3 -m http.server 3000
Serving HTTP on :: port 3000 (http://[::]:3000/) ...
次に、コンテナを起動してコンテナ内から接続を確認します。
# コンテナ内で実行
$ curl http://localhost
<!DOCTYPE HTML>
...
ホストPCの簡易HTTPサーバーのレスポンスが返ってきました。コンテナ内からホストのサービスに接続できています。
ホストPC側のターミナルにもアクセスログが表示されます。
# ホストPCのターミナル
::ffff:127.0.0.1 - - [25/Feb/2026 15:31:38] "GET / HTTP/1.1" 200 -
注意点
接続するポートごとにsocatサービスが必要
1つの socat サービスは1ポートの中継に対応します。複数のポートを中継したい場合は、それぞれにサービスを追加するか、 socat コマンドを複数並べる工夫が必要です。
セキュリティ
開発環境での使用を想定しています。本番環境への適用は慎重に検討してください。
おわりに
socat を使ったDockerコンテナからホストPC接続の方法を紹介しました。
docker-compose.yml に数行追加するだけで、アプリケーションのコードを一切変更せずに localhost 接続をホストPCへ中継できます。既存コードに手を加えたくないケースや、devcontainer環境からホストのサービスに気軽につなぎたいときに便利です。
このブログがどなたかのお役に立てれば幸いです。







