言語を切り替える
テーマを切り替える

Dockerコンテナからホストへのアクセス:host.docker.internalとhost-gateway設定ガイド

「開発中のWebアプリをDockerコンテナで起動し、ホストマシンのローカル開発用MySQLに接続したい。」

これは非常に一般的なシナリオですが、多くの開発者がここで躓きます。
コンテナの設定でDB_HOST=localhostと指定しても、接続エラーが発生するのです。

「なぜ?ローカルでMySQLは動いているのに!」

理由は簡単です。コンテナにとってのlocalhost(127.0.0.1)はコンテナ自身であり、あなたのPC(ホスト)ではないからです。

この記事では、コンテナの中から「外側」のホストマシンに正しくアクセスするための、モダンでクロスプラットフォームな解決策を紹介します。

問題の理解:なぜlocalhostではダメなのか

Dockerコンテナは、独立したネットワーク名前空間を持っています。これは、コンテナが独自のIPアドレス、ポート範囲、ルーティングテーブルを持っていることを意味します。

  • ホストのlocalhost: あなたの物理マシン(127.0.0.1)
  • コンテナのlocalhost: そのコンテナ内部(127.0.0.1)

コンテナ内でcurl http://localhost:3306を実行するのは、コンテナ自身の3306番ポートにアクセスしようとしているのと同じです。もちろん、そこにはMySQLはいません。

解決策:host.docker.internal

Dockerは、この問題のために特別なDNS名を用意しています:host.docker.internal です。

これを使うと、Dockerが自動的にホストマシンの内部IPアドレスに解決してくれます。

ケース1: MacとWindows (Docker Desktop)

MacとWindowsのDocker Desktopユーザーにとって、話は非常に簡単です。この機能はデフォルトで有効になっています。

接続文字列を以下のように変更するだけです:

  • Before: mysql://user:pass@localhost:3306/db
  • After: mysql://user:pass@host.docker.internal:3306/db

これだけで繋がります。設定変更は不要です。

ケース2: Linux (Docker Engine)

Linux版のDockerでは、歴史的にこの機能はサポートされていませんでした。しかし、Docker 20.10以降、--add-hostフラグを使うことで簡単にサポートできるようになりました。

docker runコマンドの場合:

docker run -d \
  --add-host host.docker.internal:host-gateway \
  --name my-app \
  node-app

host-gatewayというキーワードがポイントです。これは「ホストへのゲートウェイIP」に自動置換されます。

全プラットフォーム対応の究極の設定 (Docker Compose)

チーム開発では、Macユーザー、Windowsユーザー、Linuxユーザーが混在することがあります。OSごとに設定を変えるのは面倒ですよね。

そこで、docker-compose.ymlに以下の設定を追加することをお勧めします。これで全OSでhost.docker.internalが使えるようになります。

version: '3.8'

services:
  app:
    build: .
    # これを追加!
    extra_hosts:
      - "host.docker.internal:host-gateway"
    environment:
      # これで統一できる
      DB_HOST: host.docker.internal

この設定の素晴らしい点は:

  1. Linux: host-gatewayが正しく解決され、機能します。
  2. Windows/Mac: もともと機能していますが、この設定があっても上書きされるか無視されるだけで、害はありません(Docker Desktopのバージョンによっては明示的な指定が推奨されることもあります)。

これで、OSを問わず DB_HOST=host.docker.internal で統一できます。

実践例:コンテナからホストのRedisに接続する

具体的な手順を見てみましょう。

前提: ホストマシン(あなたのPC)でRedisが動いていて、ポート6379で待受している。

重要: ホスト側のRedis設定で、bind 127.0.0.1となっている場合、外部(コンテナ含む)からの接続を受け付けません。bind 0.0.0.0にするか、DockerネットワークのIP範囲を許可する必要があります。

第一歩:ホスト側サービスの準備

Redisの設定ファイル(redis.conf)を確認します。

# 変更前
bind 127.0.0.1

# 変更後(注意:セキュリティリスクあり。ファイアウォールで制限することを推奨)
bind 0.0.0.0
# または特定のインターフェースのみ許可
# bind 127.0.0.1 172.17.0.1

設定を変更したらRedisを再起動します。

第二歩:コンテナから接続確認

redis-cliを含むコンテナを使ってテストしてみましょう。

Mac/Windowsの場合:

docker run --rm -it redis redis-cli -h host.docker.internal
# host.docker.internal:6379> ping
# PONG

Linuxの場合:

docker run --rm -it --add-host host.docker.internal:host-gateway redis redis-cli -h host.docker.internal
# PONG

接続成功です!

よくあるトラブルシューティング

Q. host.docker.internalが解決できないと言われる

  • Linux: --add-host host.docker.internal:host-gatewayを忘れていませんか?
  • Docker Compose: extra_hosts設定を入れていますか?
  • Alpine Linux: まれにglibcの問題で名前解決できないことがありますが、最近のバージョンではほぼ解消されています。

Q. Connection refusedになる

名前解決はできている(IPはわかっている)が、接続が拒否されています。

  1. ファイアウォール: ホスト側のファイアウォール(UFWやWindows Firewall)がDockerネットワークからの接続をブロックしていませんか?
  2. Bindアドレス: ホスト側のサービス(MySQLなど)が127.0.0.1しかリッスンしていない可能性があります。0.0.0.0に変更して確認してください。

結論

コンテナからホストへのアクセスは、開発環境では頻出の要件です。

OSごとの違いに悩まされるのはもう終わりにしましょう。docker-compose.ymlextra_hostsを1行追加するだけで、チーム全員が幸せになれます。

    extra_hosts:
      - "host.docker.internal:host-gateway"

この魔法の1行を、あなたのプロジェクトのボイラープレートに追加しておくことを強くお勧めします。

Dockerコンテナホストアクセス設定フロー

host.docker.internalを使用してコンテナからホスト上のサービスに接続するための設定手順

⏱️ Estimated time: 15 min

  1. 1

    Step1: 問題と解決策を理解する

    問題:コンテナ内のlocalhostはコンテナ自身を指すため、ホストに繋がらない。
    解決策:host.docker.internalという特殊ドメインを使用する。これはホストのIPに自動解決される。
  2. 2

    Step2: Mac/Windowsでの設定

    設定不要。Docker Desktopはデフォルトでhost.docker.internalをサポートしている。
    使用例:
    environment:
    DB_HOST: host.docker.internal
  3. 3

    Step3: Linuxでの設定(またはクロスプラットフォーム対応)

    Linuxではデフォルトでサポートされていないため、docker-compose.ymlに設定を追加する。

    設定例:
    services:
    app:
    extra_hosts:
    - "host.docker.internal:host-gateway"

    これにより、Linuxでもhost.docker.internalが使えるようになり、Mac/Windowsでも問題なく動作する。
  4. 4

    Step4: ホスト側のサービス設定確認

    重要:ホスト側のサービス(MySQL, Redis等)が 127.0.0.1 のみでリッスンしている場合、コンテナからの接続は届かない(コンテナは外部扱い)。
    対処:設定ファイルのbind addressを 0.0.0.0 に変更するか、ファイアウォール設定を確認する。

FAQ

なぜコンテナ内からlocalhostでホストに繋がらないのですか?
コンテナは独立したネットワーク名前空間を持っているため、コンテナ内のlocalhost(127.0.0.1)はコンテナ自身を指します。ホストマシンとは別の「家」に住んでいるようなものです。
host.docker.internalは全OSで使えますか?
MacとWindows(Docker Desktop)ではデフォルトで使えます。
Linuxでは、Docker 20.10以降で --add-host host.docker.internal:host-gateway オプションを使うことで使用可能です。
Docker Composeなら extra_hosts を設定することで全OS対応にできます。
ホスト側のポートに繋がりません(Connection refused)
ホスト側のサービス設定を確認してください。
例えばMySQLが bind-address = 127.0.0.1 となっていると、ローカルループバック以外からの接続を拒否します。
コンテナはネットワーク的には「外部」からの接続となるため、0.0.0.0でリッスンするように変更する必要があります。
--network hostを使えば解決しませんか?
はい、--network hostを使えばコンテナはホストと同じネットワークを共有するため、localhostで接続できます。
しかし、これはLinuxでしか動作せず(Mac/WindowsではVMの中で動くためホストに繋がらない)、コンテナのネットワーク隔離が失われるため、推奨される解決策ではありません。

2 min read · 公開日: 2025年12月17日 · 更新日: 2026年1月22日

コメント

GitHubアカウントでログインしてコメントできます

関連記事