Skip to content

Nuface Blog

隨意隨手記 Casual Notes

Menu
  • Home
  • About
  • Services
  • Blog
  • Contact
  • Privacy Policy
  • Login
Menu

把 webmail 搬家踩到的一路坑:Docker 網路、反向代理、iptables 與 DNS 的完整筆記

Posted on 2025-11-052025-11-05 by Rico

場景:

  • 主機 A(192.168.100.1):wwwapp(Apache 反向代理,Docker 預設 bridge → 172.17.0.0/16)
  • 主機 B(192.168.100.2):webmail(Roundcube,Docker 自建 mail-network → 172.24.0.0/16,-p 83:8000)
    目標:把 webmail 容器搬到 主機 A,讓 wwwapp 反向代理 https://webmail.nuface.tw → http://192.168.100.1:83/。

症狀與線索

  • Apache 錯誤:
    • No route to host / failed to make connection to backend: 192.168.100.1:83
    • 或 DNS lookup failure for: mailwebmailnuface(同網段 service name 解析不到)
  • 容器內工具缺:curl/nc/ip route 不便測試。
  • 用 --network=container:wwwapp 進測,/etc/resolv.conf 指向 8.8.8.8/8.8.4.4(legacy 模式,沒有 127.0.0.11 內建 DNS)。
  • 反之在 mail-network 的容器,/etc/resolv.conf 為 127.0.0.11(Docker 內建 DNS)。
  • 在主機 A 上 iptables 僅見 DOCKER-USER / DOCKER-FORWARD,不像主機 B 那樣有一大串 DOCKER-ISOLATION-*、per-bridge 規則。
  • 關鍵發現:filter INPUT 沒有允許 Docker 子網進入(預設 DROP);補上「允許 172.17/16 與 172.24/16 進 INPUT」後,全部恢復正常。

問題根因(多重)

  1. 容器 → 主機 的流量被 INPUT policy 擋掉
    • 髮夾 DNAT 路徑:wwwapp容器 → 主機 192.168.100.1:83 →(nat/PREROUTING→DOCKER DNAT)→ webmail容器:8000
    • 封包第一站是 主機 INPUT,若 INPUT 預設 DROP 且未放行來自 docker0 / mail-network,DNAT 根本進不去。
  2. 跨網段 service name 解析的預期誤解
    • Docker 只會在「同一個 network」 幫你解析容器名稱(embedded DNS)。
    • wwwapp 若只在 bridge(172.17),而 webmail 在 mail-network(172.24),彼此不會互相解析容器名。
    • 解法:用 主機 IP + 發布埠(例:http://192.168.100.1:83/),或把兩個容器接到同一個 network。
  3. iptables 後端不一致(legacy vs nft)可能造成你“看不到” Docker 寫入的規則
    • 舊機:iptables v1.4.21(legacy)
    • 新機:iptables v1.8.10 (nf_tables)(nft)
    • 若 Docker 用 nft、你用 legacy(或反之),會像「規則不見/不完整」。
  4. 橋接封包是否進入 iptables 與回包政策
    • br_netfilter 未載入、net.bridge.bridge-nf-call-iptables 未開,會讓橋接流量繞過 iptables。
    • 多橋接/PPPoE 場景,rp_filter 開啟可能導致回包被丟棄(建議關閉或調成寬鬆)。

關鍵概念快速複習

  • 髮夾 DNAT(Hairpin NAT):容器打主機的發布埠,再被 DNAT 到同機另一個容器。關鍵點:
    1. INPUT 要先放行容器打主機的那個埠(例如 83)。
    2. FORWARD 必須允許 docker0 ↔ 目標bridge 的東西向流量(多為 Docker 自動處理)。
    3. POSTROUTING MASQUERADE 讓容器出網/東西向 SNAT 正常回程。
  • DOCKER / DOCKER-USER:
    • DOCKER 鏈由 Docker 自己管理,放 DNAT/SNAT、per-bridge 規則。
    • 自訂請掛在 DOCKER-USER,不要清 DOCKER-* 鏈。
  • 容器 DNS:
    • 同網路:內建 127.0.0.11 解析容器名。
    • 不同網路:不能互相解析容器名;請用 IP:PORT 或接到同一個網路。

最有用的診斷指令(直接抄)

# 看每個 bridge 的規則是否存在(Docker 自動生成)
iptables -L DOCKER-FORWARD -nv
iptables -L DOCKER-ISOLATION-STAGE-1 -nv
iptables -L DOCKER-ISOLATION-STAGE-2 -nv
iptables -t nat -L DOCKER -nv | sed -n '1,120p'

# 看 POSTROUTING 的 MASQUERADE 對各個 172.x/16 是否存在
iptables -t nat -S | grep MASQUERADE

# 在容器內測 name/IP
docker run --rm --network=container:<app> busybox sh -lc \
'cat /etc/resolv.conf; echo "----"; getent hosts google.com; getent hosts <backend-name>'

# 在 wwwapp 容器內測到主機發布埠(髮夾入口)
docker exec -it wwwapp sh -lc 'wget -qO- --timeout=5 http://192.168.100.1:83/ | head -n 5' || echo FAIL

修復步驟(可擇要)

A) 最小變更:放行「容器 → 主機」的 INPUT

這是這次真正解鎖的一步。

簡易版(你採用的做法):

# 信任 docker 預設網段
iptables -A FW-INPUT -s 172.17.0.0/16 -j ACCEPT
# 信任 mail-network
iptables -A FW-INPUT -s 172.24.0.0/16 -j ACCEPT

更精準(建議其一):

  • 用 入介面 放行(比較安全): iptables -A FW-INPUT -i docker0 -j ACCEPT iptables -A FW-INPUT -i br-64c6b4ce2881 -j ACCEPT # mail-network 的 bridge 名稱
  • 或僅放 必要埠(最嚴謹): # 如果主機需要被容器打 83/TCP(髮夾入口) iptables -A FW-INPUT -i docker0 -p tcp --dport 83 -j ACCEPT # 主機充當 DNS 時 iptables -A FW-INPUT -i docker0 -p udp --dport 53 -j ACCEPT iptables -A FW-INPUT -i docker0 -p tcp --dport 53 -j ACCEPT

B) 讓 Docker 自動規則恢復完整(長期正道)

  1. 統一 iptables 後端(推薦 nft): update-alternatives --set iptables /usr/sbin/iptables-nft update-alternatives --set ip6tables /usr/sbin/ip6tables-nft
  2. 橋接封包進 iptables: modprobe br_netfilter sysctl -w net.bridge.bridge-nf-call-iptables=1 sysctl -w net.bridge.bridge-nf-call-ip6tables=1
  3. 確認 Docker 控管 iptables: docker info | egrep -i 'firewall|iptables' # Firewall: true
  4. 重啟 Docker 讓 DOCKER-* 鏈重建: systemctl restart docker

C) rp_filter 與多橋接/PPPoE

sysctl -w net.ipv4.conf.all.rp_filter=0
sysctl -w net.ipv4.conf.docker0.rp_filter=0
sysctl -w net.ipv4.conf.br-64c6b4ce2881.rp_filter=0
sysctl -w net.ipv4.conf.br.eno1.5.rp_filter=0

反向代理設定要點(兩種做法)

作法 1:主機 IP + 發布埠(不依賴容器名解析)

wwwapp vhost:

ProxyPass        /  http://192.168.100.1:83/
ProxyPassReverse /  http://192.168.100.1:83/
ProxyPreserveHost On
ProxyTimeout 15

配合上面的 INPUT 放行與 DOCKER nat 鏈中的 dpt:83 -> 172.24.x.y:8000 即可。

作法 2:把 wwwapp 接到 mail-network

這樣可用容器名:

ProxyPass        /  http://mailwebmailnuface:8000/
ProxyPassReverse /  http://mailwebmailnuface:8000/

避免了一層髮夾 DNAT,但需要你調整 wwwapp 的 network。


最後提供一份「乾淨可重複」的最小規則片段

前提:INPUT 預設 DROP;Docker 用 nft;其餘規則由 Docker 自管。

### INPUT 基礎
iptables -A FW-INPUT -i lo -j ACCEPT
iptables -A FW-INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# 允許 docker 桥來的封包進主機(選擇一種寫法)
# 1) 介面層級(建議)
iptables -A FW-INPUT -i docker0 -j ACCEPT
iptables -A FW-INPUT -i br-64c6b4ce2881 -j ACCEPT
# 2) 或僅開放 83/TCP(髮夾入口)
# iptables -A FW-INPUT -i docker0 -p tcp --dport 83 -j ACCEPT

# 其他 INPUT 視需求:SSH/HTTP/HTTPS 等
iptables -A FW-INPUT -p tcp --dport 22 -j ACCEPT
iptables -A FW-INPUT -p tcp --dport 80 -j ACCEPT
iptables -A FW-INPUT -p tcp --dport 443 -j ACCEPT

# 其餘丟棄
iptables -A FW-INPUT -j REJECT --reject-with icmp-host-prohibited

最後總結

  • 症狀:反代失敗、DNS 失敗、外網不通,看起來像路由或 Docker 失靈。
  • 真因:filter INPUT 沒放行「容器 → 主機」流量,髮夾 DNAT 進不去;另有 nft/legacy 混用與 DNS 誤解。
  • 一槍斃命:在 主機 A INPUT 放行來自 docker0 / mail-network bridge 的流量(或至少開 83/TCP)。
  • 長期正道:統一到 nft、開 br_netfilter、不要清 DOCKER-* 鏈,只用 DOCKER-USER 掛自家規則。
  • DNS 心法:不同 Docker network 之間不會互相解析容器名;要嘛接同網路,要嘛用 主機 IP + 發布埠。

這篇就是之後遇到類似「容器互打、反代後端在同機、奇怪連不通」時的完整查表與解法。

Recent Posts

  • Postfix + Let’s Encrypt + BIND9 + DANE Fully Automated TLSA Update Guide
  • Postfix + Let’s Encrypt + BIND9 + DANE TLSA 指紋自動更新完整教學
  • Deploying DANE in Postfix
  • 如何在 Postfix 中部署 DANE
  • DANE: DNSSEC-Based TLS Protection

Recent Comments

  1. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on High Availability Architecture, Failover, GeoDNS, Monitoring, and Email Abuse Automation (SOAR)
  2. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on MariaDB + PostfixAdmin: The Core of Virtual Domain & Mailbox Management
  3. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on Daily Operations, Monitoring, and Performance Tuning for an Enterprise Mail System
  4. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on Final Chapter: Complete Troubleshooting Guide & Frequently Asked Questions (FAQ)
  5. Building a Complete Enterprise-Grade Mail System (Overview) - Nuface Blog on Network Architecture, DNS Configuration, TLS Design, and Postfix/Dovecot SNI Explained

Archives

  • December 2025
  • November 2025
  • October 2025

Categories

  • AI
  • Apache
  • Cybersecurity
  • Database
  • DNS
  • Docker
  • Fail2Ban
  • FileSystem
  • Firewall
  • Linux
  • LLM
  • Mail
  • N8N
  • OpenLdap
  • OPNsense
  • PHP
  • QoS
  • Samba
  • Switch
  • Virtualization
  • VPN
  • WordPress
© 2025 Nuface Blog | Powered by Superbs Personal Blog theme