Firewalld实战指南:从iptables迁移到区域化防火墙的运维经验
做运维这些年打交道最多的就是 Linux 防火墙。早年间刚入行时配 iptables 规则那叫一个酸爽——写错一条规则顺序服务直接对外不可达排查半天发现是自己把自己墙了。后来 RHEL/CentOS 系开始默认带 firewalld我一开始还不以为然觉得不就是套了个壳吗。等真把生产环境的防火墙策略从 iptables 迁到 firewalld 之后才意识到这玩意儿确实是省事而且是那种越用越回不去的好用。这篇文章就聊聊我实际使用 firewalld 的经验包括它和 iptables 的核心差异、日常配置套路、还有那些容易踩的坑适合刚接手 Linux 服务器的运维新人也想给还在用老思路配防火墙的朋友一个参考。1. 从 iptables 到 firewalld不只是换个名字1.1 先搞清楚它们到底是什么关系先说个很多人误解的点firewalld 并不是把 iptables 推翻重来而是在 netfilter 框架之上重新做了一层管理机制。内核里真正干活儿的还是 netfilteriptables 是一个经典的命令行配置工具firewalld 则是一个动态管理的守护进程服务它会把你给的配置翻译成内核能理解的规则。它们的核心区别在管理模型上。iptables 的思维模式是表-链-规则你得自己去规划 INPUT、OUTPUT、FORWARD 链里的规则顺序规则之间有严格的先后关系一旦顺序错了后面再正确的规则也可能不生效。我见过很多新手在 iptables 里追加规则时直接把允许规则插到拒绝规则后面结果自己把自己锁在外面只能去机房重启救急这种经历相信不少老运维都懂。firewalld 的思维模式是区域-服务-规则。你不需要关心规则在哪个链里、顺序是什么只要告诉它哪个区域允许访问哪个服务就行。它把复杂的规则编排问题封装起来了你只需要描述意图不用面向内核细节编程。另一个关键差异是动态生效机制。iptables 的规则是即时写入、即时生效但重启服务或者机器后除非你手动保存否则全部丢失。firewalld 则明确区分了运行时配置和永久配置你在命令行改的规则默认只对当前会话生效想要永久保存需要加上 --permanent 参数或者执行 --runtime-to-permanent。这种设计最大的好处是你先在运行环境里验证某条规则没问题再把它固化成持久配置避免了一改规则就再也连不上机器的尴尬局面。从底层实现上来看CentOS 7 时代的 firewalld 后端还是调用 iptables 命令到了 CentOS 8 / RHEL 8 之后firewalld 默认改走 nftables 后端规则兼容性和性能都有提升。不过好消息是无论后端怎么切换firewalld 对使用者暴露的命令和配置语法基本保持不变这也是它能被广泛接受的原因之一。1.2 区域zone这套设计是真的聪明firewalld 最核心的设计思路就是区域zone。这个概念可以用一个很生活化的场景来理解一栋写字楼里有公共大堂、公司办公区、机房重地访客只能进大堂员工能进办公区只有机房管理员才能刷开机房的门。firewalld 的区域就是这个逻辑——每个网络接口或者来源 IP 可以归属到某个区域不同区域有不同的信任级别和放行策略。默认情况下系统会把所有网络接口都划到 public 区域这是最保守的区域只允许非常有限的外部访问。如果你的服务器有多个网卡比如一张网卡接公网、一张接内网那你完全可以把内网网卡划到 trusted 或者 internal 区域内网之间的互访就不用再加一堆放行规则而公网网卡保持 public 区域的严格策略。这种按信任级别分流的思路比 iptables 里面对所有来源统一起规则要清晰得多。区域设计还有一个很妙的点规则匹配是自动完成的。数据包到达时firewalld 会根据它从哪个网卡进入、或者来源地址匹配哪个区域自动套用对应区域的规则。你不需要像 iptables 那样手动指定这条规则针对 eth0、那条规则针对 eth1只要把网卡和区域绑定好剩下的策略配置就是纯逻辑操作。我在某公司的生产环境里维护着二十多台服务器网络拓扑不算复杂但也不简单有公网入口、有内网服务区、有数据库隔离区。用 iptables 的时候每台机器的规则脚本都是几百行换一个人来维护基本等于从零读代码。迁移到 firewalld 之后每台机器的策略可以清楚地拆成网卡归属哪个 zone 每个 zone 放行哪些 service配置一目了然审计的时候也不用对着规则列表发愁了。1.3 什么时候该用 firewalld什么时候还得碰 iptablesfirewalld 虽然省事但它不是万能的。常规的服务端口放行、来源 IP 限制、端口转发这些需求firewalld 都能舒舒服服地解决日常维护 90% 的场景其实都在这类需求里。但如果你要做非常复杂的流量整形、针对特定数据包特征做匹配、或者需要细粒度控制 FORWARD 链上的流量走向那 firewalld 的抽象层级可能不够用。这时候有两个选择一个是它提供的直接规则direct rule允许你用原生的 iptables 语法插入规则但这样一来又回到了老路规则顺序问题依旧存在另一个是干脆停掉 firewalld直接用 iptables 或者 nftables 写规则集。我个人的建议是直接规则适合偶尔补个洞但如果你的需求复杂到一半以上的策略都要靠直接规则实现那说明你的场景该上专业防火墙设备或者用 nftables 独立管理了。另外还有一个必须知道的点Docker、Kubernetes 这类容器平台会直接操作 iptables/nftables 的链。firewalld 并不是系统中的唯一规则写入者容器平台自己会在 FORWARD 链和 NAT 表里加规则。这意味着什么你可能会遇到明明 firewalld 里放行了端口但容器服务还是访问不了或者反过来firewalld 拒绝了端口容器端口却依然对外暴露的诡异情况。这不是 firewalld 的 bug而是规则源有多个、管理面被打散了。后面我在常见问题部分会细说怎么处理。2. 核心概念逐个拆解区域、服务、富规则和直接规则2.1 四大核心概念一次讲透想用好 firewalld必须理解它这套抽象出来的词汇表。我用最通俗的话逐个解释区域Zone前面说过它就是一个信任级别 策略集合的容器。每个区域有自己独立的允许/拒绝规则集合网卡和来源 IP 会被归入某个区域。系统预设了 trust、internal、public、external、dmz、work、home、block、drop 等区域默认区域是 public。服务Service服务不是指跑在系统里的那个进程而是端口/协议集合的命名封装。比如 http 服务 TCP 80 端口https TCP 443ssh TCP 22。为什么要搞一层封装因为这样你只需说允许 http而不是开放 TCP 80配置可读性大幅提升而且一个服务可以包含多个端口甚至包含源端口规则比单一端口配置灵活得多。富规则Rich Rule这是 firewalld 的高级编程接口。它允许你把区域、来源地址、端口、协议、动作组合成一条完整的条件规则。比如拒绝来自 192.168.1.100 的 IP 访问 TCP 8080 端口、限制单 IP 对新连接每秒最多 5 次这些都是富规则的典型应用。它的语法比 iptables 友好不少表达能力也足够应付绝大多数访问控制场景。直接规则Direct Rule最后一层兜底机制允许以 root 身份直接向 iptables/nftables 的链里插入原生规则。这是在 firewalld 抽象能力不足时的逃生通道但就像我在前面说的能用富规则解决的尽量不要用直接规则否则你又要面对规则顺序、链管理这些老问题。把这四个概念放在一起看你就能发现 firewalld 的设计思路用区域管理信任边界用服务管理端口集合用富规则处理复杂条件用直接规则作为兜底。层级清晰、职责分明比 iptables 那种所有规则摊在一张表里的方式更适合现代服务器的管理需求。2.2 一张表看懂默认区域和适用场景系统自带的区域不少但日常常用的其实就那几个。我把它们整理成一张对照表方便你根据实际网络环境做选择区域名称信任级别典型适用场景trusted最高放行所有流量内网服务器之间互访、管理网段、已知可信终端home较高放行常见家庭服务办公/家用网络里的设备互访work较高放行常见工作服务同一办公区的团队协作、打印机共享internal中高放行默认的内部服务公司内网区域内的服务器互访public中低只放行明确允许的服务公网入口服务器、面向互联网的业务节点默认区域external低默认拒绝入站支持 NAT网关/路由器所在的外网出口网卡dmz低只放行指定服务隔离区服务器比如对外提供服务的 Web 节点block极低默认拒绝所有入站临时隔离可疑流量来源drop极低直接丢弃所有入站危机处理时把某个来源整体丢弃这张表不用背选区域的核心逻辑就一句话**把信任级别最高、最常互访的网卡放到 trusted 或 internal把面向外部用户的网卡保留在 public 或 external。**我见过有些同事把公网服务器的所有网卡都扔在 trusted 区域等于把防火墙关了这比 iptables 规则写错还危险。2.3 firewalld 命令体系速记firewalld 的命令围绕着 firewall-cmd 这一个工具展开配合 systemctl 管理服务本身。我最常用的命令其实不超过十个列表如下systemctl enable --now firewalld开机自启并立即启动firewall-cmd --state查看防火墙是否在运行firewall-cmd --get-default-zone查看当前默认区域firewall-cmd --get-active-zones查看当前所有网卡归属的区域firewall-cmd --list-all查看默认区域的完整规则firewall-cmd --list-all --zoneinternal查看指定区域的完整规则firewall-cmd --permanent --add-servicehttp永久放行 HTTP 服务firewall-cmd --permanent --remove-servicehttp永久移除 HTTP 放行firewall-cmd --permanent --add-rich-rule...永久添加富规则firewall-cmd --reload重载配置让持久配置应用到运行时这里有个核心概念必须强调**不带 --permanent 的命令只修改运行时配置重启 firewalld 服务后失效带了 --permanent 则写入配置文件需要 --reload 才能生效于运行时。**新手最常见的错误就是改了规则忘了加 --permanent重启后一脸懵防火墙策略怎么又变回去了。我的习惯是凡是需要长期生效的规则一律命令中带上 --permanent然后统一 reload如果只是临时测一下端口通不通就先不带 --permanent 直接加上测完再删掉干净利落。3. 实操从安装到生产场景配置全记录3.1 安装与基础状态检查firewalld 在 RHEL/CentOS/Rocky/Alma 这些发行版里基本都是包自带的不过有些精简安装的系统可能没启用。装上很简单# 安装如果没有预装 yum install -y firewalld # 或者使用 dnf dnf install -y firewalld # 开机自启并立即启动 systemctl enable --now firewalld # 查看运行状态 systemctl status firewalld # 或使用 firewall-cmd 查询 firewall-cmd --stateUbuntu/Debian 系要稍微注意一下系统里可能默认带的是 ufw但 firewalld 同样可以安装使用安装后用 systemctl 管理即可。如果你的云服务器使用的是安全组策略别忘了安全组本身就是一层防火墙firewalld 是主机内部的第二层两层都会影响最终的连通性。启动之后先看一眼当前的规则全貌firewall-cmd --list-all输出大致是这样的public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: cockpit dhcpv6-client ssh ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:看到 eth0 归属在 public 区域并且默认放行了 ssh说明这台机器具备最基本的远程管理能力。很多云服务器的镜像在初始化时会额外放行一些管理端口具体看发行版而定。3.2 场景一开放 Web 服务的标准操作假设你要在一台服务器上部署 Nginx对外提供 80 和 443 端口的 Web 访问。以前用 iptables 你可能要写两条规则iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT用 firewalld 只需要两句话firewall-cmd --permanent --add-servicehttp firewall-cmd --permanent --add-servicehttps firewall-cmd --reload看着只是命令变短了但更深层的价值在于服务这个抽象。如果后续你想让 http 服务同时支持 IPv6不需要改规则因为它本来就支持如果某个服务包含多个端口比如某种应用需要同时开放 TCP 8000-8010直接在服务定义里扩展就行不需要在规则列表里维护一堆散落的端口条目。查看效果firewall-cmd --list-services输出http https说明两个服务都已经在放行名单里。这里我特别想提醒一点**能用服务名就用服务名不要一上来就 --add-port。**很多运维图省事不管什么服务一律加端口比如放行 3306 就直接--add-port3306/tcp短期能跑但时间一长防火墙规则里全是裸端口号根本看不出是给哪个应用开的审计和交接的时候就是一场灾难。用服务名等于给规则加了一层注释这是最好的自文档化实践。3.3 场景二只允许办公网段访问 SSH这是另一个高频需求。服务器上 SSH 是远程管理的生命线但公网环境里 SSH 一直在被扫描爆破。最稳妥的办法就是只允许你们公司的出口 IP 段访问 22 端口。firewalld 做这个需求有两种思路我更推荐第一种思路一把信任网段划入 trusted 区域再从 public 中移除 ssh 服务# 临时生效先把公司网段加进 trusted 区域 firewall-cmd --zonetrusted --add-source203.0.113.0/24 # 验证可以正常连接后固化配置 firewall-cmd --permanent --zonetrusted --add-source203.0.113.0/24 firewall-cmd --permanent --zonepublic --remove-servicessh firewall-cmd --reload这个方案的精妙之处在于trusted 区域本身就是完全信任你不需要在 trusted 里再显式添加任何服务规则来自该网段的访问一路绿灯。而 public 区域里的 ssh 服务被移除后外部其他来源尝试连接 22 端口会直接被拒绝。两个区域各管一头逻辑干净后续想加新的内网网段只需往 trusted 区域再 add-source 一次即可。思路二用富规则精确控制如果你不想动区域的默认信任模型也可以用富规则实现firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address203.0.113.0/24 port port22 protocoltcp accept firewall-cmd --permanent --zonepublic --remove-servicessh firewall-cmd --reload这条富规则的语义是在 public 区域内仅接受来自 203.0.113.0/24 网段的 TCP 22 端口访问。其他来源没有匹配到任何允许规则默认就会被丢弃或拒绝取决于区域的 target 设置。我实际操作中更喜欢思路一因为 trusted 区域是现成的信任容器理解成本低团队其他成员接手后也是一眼就能看懂。富规则虽然表达能力更强但多条富规则叠加时阅读和维护成本会慢慢上来。3.4 场景三富规则解决复杂访问控制富规则是 firewalld 里最有技术含量的部分它能做的事情比想象的要多。我举两个生产环境里实际遇到过的例子。案例 A封禁某个恶意 IP某天发现一个 IP 在疯狂扫描服务器想立刻拒绝它firewall-cmd --permanent --zonepublic --add-rich-rulerule source address198.51.100.77 drop firewall-cmd --reload注意这里的 drop 动作。和 reject 不同drop 是直接丢弃数据包客户端那边表现出来的就是连不上不会收到明确的拒绝回执。好处是攻击者无法通过扫描结果判断服务器到底在不在坏处是排查网络问题时你可能会分不清是防火墙丢弃还是网络链路问题。日常管理中临时防扫描用 drop业务上有明确冲突需要快速反馈用 reject。两个动作都有适用场景。案例 B限制单 IP 的连接速率防止某个客户端疯狂建立连接消耗资源可以用 limit 控制firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address0.0.0.0/0 port port80 protocoltcp limit value20/m accept firewall-cmd --reload这条规则的含义是针对所有来源的 TCP 80 端口每分钟最多接受 20 个新连接超过的将被丢弃。这里的 value 语法支持/s、/m、/h、/d等时间单位。要注意的是limit 的匹配是基于一段时间内总连接数的速率限制不是严格的并发连接数控制但对于抵御一些低烈度的恶意请求已经够用了。案例 C复杂场景的优先级逻辑富规则支持 accept、drop、reject 等不同动作并且可以叠加多条。匹配时遵循一个原则更具体的规则优先于模糊的规则。比如你有一条拒绝某 IP 访问 8080的富规则同时又有一条所有来源允许访问 8080的富规则firewalld 会先匹配到更具体的来源规则拒绝动作生效。这是富规则相对 iptables 的又一个优势——iptables 里规则顺序决定一切富规则里则按具体优先自动排序你不需要手动维护规则的先后顺序。3.5 场景四端口转发和内网穿透firewalld 做端口转发也是日常高频操作。比如你有一台公网服务器想把 8080 端口的流量转发给内网某台机器假设为 192.168.1.10的 80 端口。以前用 iptables 你得自己配 FORWARD 链和 NAT 规则稍不注意就掉进链规则的泥潭里。firewalld 下只需要三条命令# 第一步开启防火墙的 IP 伪装MASQUERADE这是 NAT 转发的前提 firewall-cmd --permanent --add-masquerade # 第二步添加端口转发规则 firewall-cmd --permanent --add-forward-portport8080:prototcp:toport80:toaddr192.168.1.10 # 第三步重载配置 firewall-cmd --reload注意开启 masquerade 意味着这台机器对外表现为一个 NAT 设备这会隐藏后端真实 IP。如果你的场景不需要伪装只想做本机端口转发比如把本机的 8080 转发到自己机器的 80 端口那么--toaddr可以省略只需要port8080:prototcp:toport80即可。这里还有一个很容易被忽略的点**端口转发是否生效还要看 FORWARD 链是否放行了流量。**firewalld 在开启 masquerade 后通常会放行匹配转发规则的流量但在某些版本或者某些区域里你可能还需要额外检查或添加富规则来放行 FORWARD 流量。实操中遇到转发规则配了但不通的情况优先检查这条。3.6 配置保存机制运行时与永久配置的哲学firewalld 最值得称道的设计之一是运行时配置和永久配置的分离。运行时配置在内存里改完立即生效永久配置写在/etc/firewalld/zones/*.xml里重新加载后才生效。二者的关系有点像程序里的热更新和持久化。有几个细节值得展开说第一/etc/firewalld/ 目录下有 zones、services、icmptypes 等子目录对应的 XML 文件就是用户的持久配置。系统预设的配置在 /usr/lib/firewalld/ 目录下两者优先级不同/etc/ 下的同名文件会覆盖 /usr/lib/ 下的默认文件。这就意味着你完全可以自定义服务文件放到 /etc/firewalld/services/ 下比每次写裸端口规则优雅得多。第二--permanent参数只写文件不生效必须配合--reload或firewall-cmd --complete-reload才能在运行时体现。--reload是优雅重载会保留当前运行时的非永久规则--complete-reload是彻底重载会把运行时配置重置为永久配置。生产环境里我几乎只用--reload只有需要重置所有运行时临时规则时才用 complete-reload。第三如果你已经做了一堆临时验证想把它们全部固化成永久配置不需要重新敲一遍带 --permanent 的命令直接一条命令搞定firewall-cmd --runtime-to-permanent这个命令会把当前所有运行时配置写入永久配置文件。我在测试新策略的时候习惯先不加 --permanent全部验证通过后再执行这一条命令固化既保证了配置正确性又省了重复输入命令的麻烦。强烈推荐。4. 常见问题与排查技巧实录4.1 规则明明加了为什么就是不生效这个问题的出现频率极高排除法用起来第一步确认规则加到了正确的区域。很多服务器有多块网卡默认区域是 public你开放端口时只改了默认区域但数据实际上从另一块网卡进来而那块网卡可能归属其他区域。用firewall-cmd --get-active-zones看看活动区域再确认网卡归属。第二步确认运行时和永久配置一致。如果你加了带 --permanent 的规则但没有 reload运行时里的规则列表里自然看不到。第三步看看是不是云安全组拦截了。我用过的一台云服务器就遇到过这种情况firewalld 里放行了端口本机用 curl 测端口通但外网怎么都访问不了。排查到最后发现是云控制台的安全组没放行。记住云安全组是网络边界的第一道门它拦住的流量根本到不了主机网卡。第四步检查 SELinux。有些场景下firewalld 的规则看起来没问题但 SELinux 把服务的网络访问给拦了。用ausearch -m avc -ts recent查一下是否有 SELinux 拒绝日志。4.2 手滑把来源 IP 加错了管理权限被锁死有一次我在某机房配置环境想限制 SSH 只允许办公网访问结果手抖把一个错误的 IP 段加进了 trusted 区域同时又从 public 区域移除了 ssh 服务。双重打击下我自己也被挡在了门外。当时好在机房还有带外管理控制台可以本地登录我通过控制台把 public 区域重新加回 ssh 服务才算解围。这件事给我的教训有三条一是在改动 SSH 放行策略前至少保留一个已知可用的登录通道二是重要规则改动最好分批执行先加新的信任来源验证能登录后再移除旧的放行策略而不是一步到位三是远程操作防火墙时最好开一个后台会话万一把自己锁了还能通过那个会话快速回滚。怎么快速回滚如果你记得之前的状态可以直接firewall-cmd --permanent --zonepublic --add-servicessh再 reload如果已经乱成一团更粗暴的办法是firewall-cmd --permanent --zonepublic --change-interfaceeth0把网卡重新绑回 public 区域然后恢复默认策略。要是连命令行都没法操作只能通过物理控制台或者带外管理口进入系统处理。4.3 firewalld 和 Docker 共存的那些坑Docker 默认使用 iptables/nftables 来管理容器网络它有自己的链比如 DOCKER 链并且会在 FORWARD 链上插入规则。这意味着容器的端口发布和网络隔离不完全受 firewalld 管控两者并存时经常出现规则“打架”的情况。举个例子你用docker run -p 8080:80发布了一个容器端口Docker 会在 iptables 的 nat 表和 filter 表里插入自己的端口映射规则。即使 firewalld 的 public 区域没有放行 8080 端口外部依然可能通过 Docker 自动添加的规则访问到容器服务。反过来你在 firewalld 里放行了 8080但 Docker 的网络策略没有配置好容器依然可能不通。针对这个问题我的处理思路是部署容器服务的机器尽量明确容器端口由 Docker 管主机服务端口由 firewalld 管不要重复管理同一批端口。如果一定要让 firewalld 完全接管容器网络需要在/etc/firewalld/direct-interface.xml或者直接规则里手动管理 DOCKER 链但这已经属于进阶操作不建议新手在没有充分理解网络转发机制前尝试。排查容器端口不通的问题时除了看 firewalld 的规则还要看 Docker 的docker network inspect和 iptables 里 DOCKER 链的状态多查一层才能定位问题。4.4 自定义服务按需创建服务文件有时候系统预置的服务列表里没有你需要的服务比如某个内部应用固定使用 TCP 9999 端口。你可以创建一个自定义服务# 在 /etc/firewalld/services/ 下创建文件 vim /etc/firewalld/services/myapp.xml写入内容?xml version1.0 encodingutf-8? service shortmyapp/short descriptionInternal myapp service/description port protocoltcp port9999/ /service保存后重载firewall-cmd --reload firewall-cmd --permanent --add-servicemyapp这样后续放行我的应用服务就只需--add-servicemyapp和系统内置服务用起来没区别。自定义服务文件的本质就是把端口、协议这些底层细节封装成语义化的标签对多台服务器的一致性管理非常有帮助。4.5 常见问题速查表症状可能原因排查/解决思路端口放行后外网仍不通云安全组未放行登录云控制台检查安全组入站规则规则加了但重启后丢失未加 --permanent重新用 --permanent 添加或执行 --runtime-to-permanent修改规则后不生效未 reload执行 firewall-cmd --reload 或 --complete-reload默认区域规则不对多网卡但只改了默认区域用 --get-active-zones 查看各网卡归属远程连接被拒绝来源 IP 被加入 drop 区域通过带外管理/控制台移除来源或规则端口转发不生效未开启 masquerade检查是否执行 --add-masquerade容器端口意外暴露Docker 自动添加规则查看 iptables DOCKER 链调整 Docker 发布策略想放行的端口不属于任何内置服务服务列表里没有创建自定义服务 XML 文件5. 进阶玩法与排查思路5.1 利用日志和抓包工具定位防火墙问题firewalld 的运行日志通过 journald 管理排查问题时先从日志开始journalctl -u firewalld --since 10 minutes ago --no-pager但说实话firewalld 自身的日志信息比较有限更多时候你需要用 tcpdump 来确认数据包到底有没有到达主机# 抓取某个端口的数据包 tcpdump -i eth0 -n tcp port 8080如果 tcpdump 能看到数据包到达但服务还是连不上说明问题可能出在防火墙规则或服务本身如果 tcpdump 根本看不到包那问题在更前面的链路比如云安全组或者路由。另一个实用技巧是统计规则被匹配的次数。firewalld 通过firewall-cmd --direct --get-all-rules可以查看直接规则但配合iptables -L -v -n查看已有规则的包计数能快速判断哪条规则真正命中、哪条规则形同虚设。这个方法在我排查 Nginx 访问延迟时帮过大忙发现某条富规则的 limit 限制被频繁触发连接被丢掉导致外部访问时断时续。5.2 性能调优的几个注意点客观地说firewalld 这种抽象层会带来一些性能开销但在绝大多数业务场景下这个开销微乎其微。真正影响性能的是规则本身的复杂度和数量而不是 firewalld 还是 iptables 这个选择。先说规则数量。防火墙规则本质上是链上的线性匹配规则越多每个数据包需要经过的比对次数就越多。firewalld 的富规则在翻译成内核规则时有时会产生比预期更多的底层规则如果机器规格很高、流量很大规则膨胀的影响会被放大。处理原则是能用服务名解决的就用服务名能合并的规则尽量合并避免堆砌大量细颗粒度的富规则。再说 conntrack 表。开启 masquerade 之后防火墙需要维护连接跟踪表。如果服务器的并发连接数非常高默认的 conntrack 表容量可能不够表现为新连接无法建立。这时需要调整内核参数sysctl net.netfilter.nf_conntrack_max1000000 sysctl net.netfilter.nf_conntrack_buckets262144写入 /etc/sysctl.conf 持久化。这个调优主要针对于高并发网关/代理场景普通业务服务器不需要动它。最后提一句 nftables 后端。CentOS 8/RHEL 8 之后的 firewalld 默认使用 nftables 后端性能比老旧的 iptables 后端更好规则集也更紧凑。查询当前后端可以用firewall-cmd --version # 如果版本号是 0.9.0 及以上默认后端一般是 nftables了解底层后端有助于排查一些奇怪的 compat 问题但绝大多数情况下你不需要关心后端是哪一个firewalld 已经把差异封装掉了。5.3 firewalld 的日常维护建议在实际维护中我养成了几个习惯长期下来避免了不少问题每次变更配置都执行 --list-all 验证一遍确保改动符合预期而不是改完就完事。重要的防火墙策略用脚本管理把一组相关的配置写成一个 shell 脚本放进版本控制。机器重装或者迁移时直接执行脚本就能恢复策略比手工敲命令靠谱得多。脚本里每行都注明用途相当于防火墙策略的文档。定期审计区域和服务的配置尤其是那些历史遗留的 --add-port 规则能迁移成 --add-service 就迁移保持规则集整洁。在变更管理窗执行防火墙改动避免业务高峰期改策略引发意外。这最后一条是我在某个大促前夜改防火墙规则导致线上服务短暂波动后总结出来的教训。当时我以为只是加一条放行规则不会有什么影响结果 reload 之后连接数瞬时抖动引发了告警。从那以后任何防火墙改动都先在灰度机器或者低峰期验证再逐步扩大到全量机器。结尾最后再分享一个小技巧。日常使用 firewalld 时我用 tab 键补全命令参数的频率非常高但 firewalld 的命令参数较多有时补全出来的语法让人摸不着头脑。我建议把它当成一个快速提词器来用配合firewall-cmd --help和 man 文档查看具体参数含义。另外如果你和我一样管理着很多台机器建议把常用的防火墙配置脚本统一管理起来配合 git 做版本控制改了什么、为什么改都留痕在案。对比 iptables 时代那些动辄几百行、注释混乱的规则脚本firewalld 的配置文件本身就是可读的策略文档再给它加上版本管理整个防火墙运维的透明度和可维护性就完全不一样了。这就是我为什么说firewalld 比 iptables 省事——它省的不只是敲命令的手更是后续维护时烧掉的脑细胞。