Next.js + Docker + Mac でポート衝突する地獄と解決法
はじめに
Mac で Next.js を Docker 上で動かしていると、
ある日突然 Error: ports are not available の恐怖に襲われることがあります。
再起動しても直らず、他のコンテナを落としても解決しない——まさに“ポート地獄”。
この記事では、この現象の原因と解決方法をシンプルに整理します。
1. 発生するエラーメッセージ
Error response from daemon: ports are not available:
exposing port TCP 127.0.16.31:9000 -> 127.0.0.1:0: listen tcp4 ...: bind: can't assign requested address
または:
Bind for 0.0.0.0:3000 failed: port is already allocated
2. 原因の正体
このエラーは、Docker ネットワークが macOS の lo0 インターフェース(ループバック)に正しく紐付けられないことが原因です。
Apple Silicon 環境(M1/M2 Mac)では 127.0.16.x 系の仮想アドレスを使うため、
これが正常に解放されないとポート衝突が起きます。
主な原因まとめ
- 以前のコンテナが「ゴースト状態」で残っている
- Docker が
lo0に追加したエイリアスが削除されていない -
docker-compose.yml内で固定IPを指定していて競合している - macOS の Firewall / VPN がループバック通信をブロックしている
3. まず確認するべきこと
(1) ポートがすでに使われていないか確認
lsof -i :3000
もし出力があれば、そのプロセスを終了。
kill -9 <PID>
(2) 使っているDockerネットワークを確認
docker network ls
docker network inspect <network_name>
"IPAM": { "Config": [ { "Subnet": "172.31.0.0/16" } ] } のような部分に注目。
複数のネットワークで同じサブネットを使っていると衝突します。
4. 即効性のある解決法
✅ 1. コンテナとネットワークを一度全部削除
docker stop $(docker ps -aq)
docker rm $(docker ps -aq)
docker network prune -f
docker volume prune -f
→ これで大抵のポート衝突は解消。
✅ 2. lo0 にエイリアスを再設定(Mac専用)
Apple Siliconでは、127.0.16.x がDockerコンテナの仮想アドレスになります。
これを再設定するスクリプトを /tmp/add-lo0-aliases.sh に作成。
#!/bin/bash
for i in $(seq 1 20); do
sudo ifconfig lo0 alias 127.0.16.$i up
done
実行:
sudo bash /tmp/add-lo0-aliases.sh
✅ 3. docker-compose.yml の固定IP設定を削除
services:
app:
ports:
- "3000:3000"
networks:
app_net:
ipv4_address: 172.31.0.5 # ← これを削除
固定IPを削除すると、Docker が自動的に安全なアドレスを割り当てます。
5. 恒久的な対策
💡 1. Mac再起動時に自動でlo0エイリアスを再設定
/usr/local/bin/docker-up-fix.sh に次のスクリプトを登録:
#!/bin/bash
for i in $(seq 1 20); do
if ! ifconfig lo0 | grep -q "127.0.16.$i"; then
sudo ifconfig lo0 alias 127.0.16.$i up
fi
done
ログイン時に自動実行するように launchctl へ登録しておくと安心です。
💡 2. .env でポートを可変にしておく
複数プロジェクトで同じポートを使うと衝突します。
.envにポート番号を変数化して、compose内で参照するのがおすすめ。
ports:
- "${APP_PORT:-3000}:3000"
💡 3. Docker Desktop を定期的に再起動
macOS のネットワークキャッシュは永続化されるため、
定期的に Docker Desktop を再起動してキャッシュをクリアするのが効果的。
6. それでも直らないとき
- VPNをOFFにする(一部VPNが127系通信を奪う)
- RosettaでDockerを動かす(一部のamd64イメージがarm64と競合)
- Docker Desktopをリセット(設定 → Troubleshoot → Reset to factory defaults)
まとめ
Next.js と Docker は最高の組み合わせですが、Mac環境ではネットワーク周りに独特の罠があります。
焦らず「lo0」「固定IP」「ポート競合」の3点をチェックすれば、ほとんどのケースで復旧可能です。
この“地獄”を一度経験すれば、もう怖いものはありません。