docker『Firewall blocks docker0 bridge』の原因と対処法

docker『Firewall blocks docker0 bridge』の原因と対処法

コンテナが外部ネットワークに出られない・ホストからコンテナに繋がらないとき、ホスト側のファイアウォールが docker0 ブリッジや NAT ルールをブロックしていることがある。iptables・firewalld・UFW・企業FWなど、どのレイヤでブロックされているかを切り分けながら、docker0 まわりの通信を適切に許可していく。

症状と発生条件(docker0 ブリッジがFWに阻まれるとき)

よくある症状と条件は次のようなもの。

・コンテナからインターネットに出られない(apt/curl がタイムアウト)。

・ホストからコンテナIP(例 172.17.0.x)に ping/TCP 接続できない。

・ホスト→コンテナのポートフォワード(-p 80:80 など)が動かない。

・Docker インストール前は問題なかったが、FWを有効化してから問題が発生。

・firewalld や UFW を有効にした瞬間からコンテナ通信が不調になる。

多くの場合、「docker0 が信頼ゾーンに入っていない」「FORWARD チェーンがDROP」「NAT後のトラフィックが外部FWで拒否」などが原因になる。

docker0 ブリッジと iptables の基本構造

Linux 上の Docker は以下のような構造でパケットを流す。
・docker0:デフォルトのブリッジインタフェース(例 172.17.0.1/16)。

・コンテナ:veth ペアで docker0 にぶら下がる。

・iptables:nat テーブル(POSTROUTING)で MASQUERADE(NAT)を行い、コンテナ→外部への通信をホストIPから出している。

# docker0のIP確認
ip addr show docker0

# iptables のNATルール(Dockerの追加ぶん)を確認
sudo iptables -t nat -L -n -v | grep -i docker -A2

# FORWARDチェーンのポリシーも確認
sudo iptables -L FORWARD -n -v

FORWARD チェーンがDROPになっていたり、docker0 関連のルールがFWツールによって消されたりすると、docker0 経由のトラフィックが通らなくなる。

iptables での診断と一時的な許可ルール

iptables を直接使っている環境では、まず FORWARD ポリシーと docker0 向けルールを確認する。

# FORWARDチェーンのポリシーを確認
sudo iptables -L FORWARD -n -v

# 一時的に、docker0→外部/外部→docker0 を許可して動作確認
sudo iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o docker0 -m state --state RELATED,ESTABLISHED -j ACCEPT

・この一時ルールで通信が通るようになれば、FWがdocker0ブリッジを遮断していたことがわかる。

・恒久対処としては、iptables-save / iptables-restore や FWツールの設定に組み込む。

firewalld 環境での docker0 許可設定(Zone に追加する)

RHEL/CentOS/Fedora 系で firewalld が有効な場合、docker0 を適切な zone に紐付けないと通信が拒否されやすい。

# docker0がどのzoneに属しているかを確認
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --get-zone-of-interface=docker0

# 信頼zoneに docker0 を追加(例: trusted)
sudo firewall-cmd --permanent --zone=trusted --add-interface=docker0

# 必要なサービス/ポートをzoneに追加(例: 80/tcp)
sudo firewall-cmd --permanent --zone=trusted --add-port=80/tcp

# 設定反映
sudo firewall-cmd --reload

・iptables を firewalld の外から直接編集すると、firewalld の reload 時に上書きされるため、基本は firewall-cmd 経由で設定する。

UFW(Ubuntu)の場合の docker0 許可設定

Ubuntu で UFW が enabled のとき、そのままだと docker0 経由の通信がブロックされることがある。よく使われる回避方法は、UFW の before.rules に docker0 経由のFORWARD許可を追加するパターン。

sudo nano /etc/ufw/before.rules

ファイルの *filter セクションに、次のようなルールを追加する。

*filter
:ufw-before-forward - [0:0]

# docker0からの転送を許可
-A ufw-before-forward -i docker0 -o eth0 -j ACCEPT
-A ufw-before-forward -i eth0 -o docker0 -m state --state RELATED,ESTABLISHED -j ACCEPT

COMMIT

その後 UFW を再読み込み。

sudo ufw reload

・環境に合わせて eth0 の部分は ens33 など実インタフェース名に置き換える。

外部ファイアウォール/クラウドセキュリティグループでのブロック

オンプレのハードウェアFWやクラウドのセキュリティグループが「NAT された後のコンテナトラフィック」をブロックしているケースも多い。

・コンテナ→外部:ホストIPからのアウトバウンドが制限されていないか。

・外部→コンテナ(-p 80:80):ホストIP:80 への inbound が許可されているか。

# クラウドの例(概念)
# SG/Firewall設定でホストサーバのpublic IPの 80/tcp, 443/tcp, 任意ポート を開ける

docker0 自体はあくまでホスト内の仮想ブリッジなので、外部FWからは「ホストのIP/ポート」だけが見える。そのため、docker 側でポートフォワードしても、外側のFWが閉じていれば「繋がらない」状態が続く。

Docker デーモンの iptables 管理設定(–iptables=false 時の注意)

Docker はデフォルトで自分用の iptables ルールを追加するが、daemon.json やサービス起動オプションで iptables=false にしていると、自動でルールが追加されない。

# /etc/docker/daemon.json の例
{
  "iptables": true
}

# 変更後はDockerサービスを再起動
sudo systemctl restart docker

・iptables=false にして手動管理している場合は、nat テーブルの MASQUERADE と FORWARDチェーンの許可を自前で定義しておく必要がある。

一時的にFWを無効化して原因を切り分ける

本番では推奨されないが、原因がFWかどうかを切り分けるために、短時間だけFWを止めて動作を確認する方法もある。

# firewalld を一時停止
sudo systemctl stop firewalld

# UFW を一時停止
sudo ufw disable

# iptables を初期化(検証環境のみ)
sudo iptables -F
sudo iptables -t nat -F

FWを停止した状態でコンテナ通信が正常になるなら、「Firewall blocks docker0 bridge」状態が原因と判断できる。判明後は必ずFWを戻し、必要なルールだけ追加する。

セキュアな恒久対処(最低限のポートとサブネットだけ許可する)

恒久対処としては、「docker0 の全通信を丸ごと許可」ではなく、必要な方向とポートに絞って許可すると安全性を保ちやすい。

# 例: コンテナから外部へのアウトバウンドのみ許可
sudo iptables -A FORWARD -s 172.17.0.0/16 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -d 172.17.0.0/16 -m state --state RELATED,ESTABLISHED -j ACCEPT

# 例: コンテナの80番ポートだけ外部公開 (NAT前提)
sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 \
  -j DNAT --to-destination 172.17.0.2:80

・サブネット(172.17.0.0/16 など)は環境によって異なるため、docker network inspect bridge などで確認してから設定する。

NG→OK 早見表(よくあるパターン別の修正例)

# 1) FORWARDポリシーがDROP
# NG:
sudo iptables -P FORWARD DROP
# OK: docker0まわりだけ明示許可
sudo iptables -A FORWARD -i docker0 -o eth0 -j ACCEPT
sudo iptables -A FORWARD -i eth0 -o docker0 -m state --state RELATED,ESTABLISHED -j ACCEPT

# 2) firewalldでdocker0がpublic zoneのまま厳しく絞られている
# NG: zone未設定 or publicでDROP
# OK: trusted zoneに移す
sudo firewall-cmd --permanent --zone=trusted --add-interface=docker0
sudo firewall-cmd --reload

# 3) UFW有効化後にコンテナ通信が全滅
# NG: 何もルールを追加していない
# OK: ufw-before-forwardにdocker0向け許可ルールを追加して reload

# 4) Dockerのiptables管理を切ったまま何もしていない
# NG: daemon.jsonで "iptables": false だが手動ルールもなし
# OK: "iptables": true に戻す or NAT/FORWARDルールを自前で定義

チェックリスト(上から順に潰す)

1) ip addr show docker0 で docker0 が存在し、期待通りのアドレスが付いているか
2) iptables -t nat -L -n -v で Docker用 MASQUERADE ルールが存在するか
3) iptables -L FORWARD -n -v で docker0 向けパケットが DROP されていないか
4) firewalld/UFW を使っている場合、それぞれ docker0 を許可する設定を入れたか
5) Docker daemon の "iptables" 設定が意図通りか(true か、false なら自前ルールを定義したか)
6) 外部FW/クラウドSGで、ホストIPの必要ポート(例: 80, 443, 任意)が開いているか
7) FWを一時無効化すると通信が通るか(原因がFW由来かどうかを切り分けたか)
8) 恒久対処として、docker0 全開放ではなく必要なサブネットとポートに絞ってルールを整備したか