Linux 防火墙规则失效的原因

8次阅读

firewalld规则需先–permanent再–reload才生效:–permanent仅写入配置文件,–reload才加载到运行时;docker默认绕过firewalld,需禁用其iptables管理并手动配置masquerade。

Linux 防火墙规则失效的原因

firewall-cmd –permanent 之后没 reload,规则就只是“写进硬盘

这是最常见、也最容易被忽略的失效原因:你执行了 firewall-cmd --permanent --add-port=8080/tcp,终端返回 success,但立刻 telnet 测试失败,reboot 后依然不通。不是命令没跑完,而是规则只落盘到 /etc/firewalld/zones/public.xml,根本没加载进当前运行的 firewalld 实例。

firewalld 的 runtime 和 permanent 是两套状态,--permanent 不会自动同步过去;--reload 才是那个“把磁盘配置全量覆盖 runtime”的关键动作。

  • ✅ 正确流程必须是两步:先 firewall-cmd --permanent --add-port=8080/tcp,再 firewall-cmd --reload
  • ⚠️ --reload 不中断已有连接,比 systemctl restart firewalld 更安全
  • ? 建议在 ~/.bashrc 里加个函数:fwadd() { firewall-cmd --permanent "$@" && firewall-cmd --reload; },以后直接 fwadd --add-port=8080/tcp

Docker 启动时自动绕过 firewalld

如果你在宿主机上跑 docker run -p 8080:80,firewalld 规则大概率无效——因为 Docker 默认会直接往 iptablesDOCKER-USER 链里插一条 ACCEPT 规则,优先级高于 firewalld 管理的链,相当于在防火墙上凿了个洞。

  • ✅ 解法是禁止 Docker 操作 iptables:编辑 /usr/lib/systemd/system/docker.service,在 ExecStart 行末尾加 --iptables=false
  • ? 执行 systemctl daemon-reload && systemctl restart docker
  • ⚠️ 注意副作用:容器默认无法访问外网,需手动开启 masquerade:firewall-cmd --permanent --zone=public --add-masquerade && firewall-cmd --reload
  • ? 验证是否生效:iptables -t nat -L DOCKER-USER -n 应为空(或只有你手动加的规则)

firewalld 服务本身没活过来

规则再对,服务没起来也是白搭。很多 reboot 失效,其实压根不是规则问题,而是 firewalld 根本没自启,或者启动失败后静默退出。

  • ? 先查状态:systemctl is-active firewalld(应为 active),systemctl is-enabled firewalld(应为 enabled
  • ? 若 disabled:运行 systemctl enable firewalld;若 inactive:运行 systemctl start firewalld
  • ❗ 别只信 systemctl status firewalld 的 “running”,要看日志:journalctl -u firewalld --since "1 hour ago" | grep -i Error
  • ? 注意冲突:如果 iptables-services(传统 iptables)也在运行,它会覆盖 firewalld 规则,务必 systemctl disable iptables

规则看似加了,实际没进 permanent 配置文件

有时候你反复 --permanent + --reload,但 reboot 后还是丢,可能是因为规则压根没写进 XML 文件——比如 zone 被改错、XML 格式损坏、或被 ansible/Salt 等工具覆盖重置。

  • ? 对比验证:firewall-cmd --list-all --permanent 输出是否含你加的端口/服务?
  • ? 直接检查文件:grep -A2 8080 /etc/firewalld/zones/public.xml,确认内容存在且闭合标签正确
  • ⚡ 模拟 reboot 效果:systemctl restart firewalld && firewall-cmd --list-all,这个输出应和 --permanent 版本一致
  • ⚠️ ipv6 容易漏:firewalld 默认不管理 IPv6,若业务走 IPv6,得显式加 --ipv6 参数,例如:firewall-cmd --permanent --add-port=8080/tcp --ipv6

真正麻烦的从来不是加一条规则,而是搞清哪一层断了:是 service 没跑、是 reload 没做、是 Docker 插队、还是 XML 被悄悄抹掉。每次怀疑规则失效,先分层验证——从服务状态、到 permanent 配置、再到 runtime 状态,一层一层往下扒,比重试十遍更省时间。

text=ZqhQzanResources