恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
firewalld完全指南:Zone、Rich Rule与多网卡服务器实战
首页
资讯中心
/
firewalld完全指南:Zone、Rich Rule与多网卡服务器实战
firewalld完全指南:Zone、Rich Rule与多网卡服务器实战
发布时间:2026/10/19 8:58:44
1. firewalldLinux服务器上那个常被忽略的守门员老早以前在机房里折腾Linux服务器环境刚装好第一件事就是先把iptables规则清掉因为默认策略太死板稍不留神就给自己关门外。后来firewalld逐渐成了主流发行版默认自带的防火墙管理工具很多刚开始接触服务器运维的同行反而对它比较陌生甚至搞不清楚它和iptables到底是什么关系。firewalld说白了就是一个Linux下的动态防火墙管理工具底层用iptables或者nftables做实际包过滤用户在firewalld层做配置firewalld负责把配置翻译成底层规则。它解决的核心问题有两个一是让防火墙管理变得更灵活支持运行时修改和永久修改分离二是按区域zone组织规则让一台服务器面对不同网络来源时自动切换不同策略。这一点在笔记本、桌面系统以及多网卡服务器上尤其受用。我见过不少同行用了好几年的Linux遇到要放行端口还是习惯性去改iptables文件其实firewalld提供了更顺手的管理方式。这篇文章就是一篇偏实战向的梳理适合刚接触Linux防火墙的新手也适合已经会用iptables但对firewalld一直“半熟”的运维同事。看完之后你能根据自己服务器的实际业务场景把firewalld用得明明白白。2. 核心概念拆解zone和runtime两个绕不开的关键词2.1 zone是什么为什么要分zonezone这个东西第一次接触会觉得有点抽象但它理解起来其实特别生活化。打个比方你家门口装了个带门禁的保安他手里有两套规则文件一套用于接待快递员的只需登记就能进单元楼另一套用于防陌生人尾随的进电梯必须刷卡。这套规则文件就是zone根据来访者身份选择用哪一套就是防火墙根据包的来源去匹配zone。firewalld里默认划分了好几个zonetrusted、home、internal、work、public、external、dmz、block、drop。对服务器来说最常用的是public、internal和trusted。public表示不信任来源网络仅允许极少数明确放行的服务trusted表示完全信任进来的包不拦internal和work介于两者之间适合内网环境里其他主机有一定可信度但又不完全放开的场景。不同zone的作用范围是网卡级别的。一块网卡可以绑定到一个zone上数据从这块网卡进来就走这个zone的规则。比如你的服务器上有两块网卡一块连着公网一块连着内网那么公网网卡绑public内网网卡绑internal。这样来自公网的流量严格受限而内网来的流量可以有更多服务权限一套机器顶两套防火墙策略不需要额外做策略路由配置成本非常低。2.2 runtime和permanent为什么改完规则总是“丢失”我经常在群里看到新人问明明firewall-cmd --add-port8080/tcp执行成功了为什么重启后端口又变成关闭状态原因很简单firewall-cmd默认只改运行时配置这个配置存在于内存当中一旦firewalld服务重载或者系统重启就丢失了。要永久保存必须加上--permanent参数再执行一遍或者用--runtime-to-permanent把当前所有运行时修改固化成永久配置。这个设计和iptables的“改动立即生效、重启全部还原”其实思路一致但firewalld把两种状态的管理做得更显式了。runtime适合临时调整比如线上临时排查问题放个端口用完了直接reload或者remove就干净了。permanent适合正式的业务端口和规则变更写好之后重启服务器依然有效。有个实用技巧是在改永久配置之前先用不带--permanent的版本加一次运行时规则验证效果没问题再加--permanent固化。这样可以避免一不小心写错规则把线上服务端口永久封死。火墙规则的错误写进永久配置比运行时配置要麻烦得多因为重启排障的过程很可能就把远程连接彻底断掉。2.3 默认zone和网卡绑定先搞清楚你的包从哪张网卡进来每一台跑firewalld的机器都有一个默认zone所有没有显式绑定zone的网卡都会落在默认zone上。用以下命令查看当前默认zonefirewall-cmd --get-default-zone一般发行版默认是public。用下面命令查看所有zone的当前配置以及网卡和zone的绑定关系firewall-cmd --list-all-zones firewall-cmd --get-active-zones--get-active-zones这个命令非常实用它会列出所有绑定了网卡的zone以及对应网卡名几秒钟就能看出当前机器的实际规则流向。我排查远程连不上服务器的问题时第一件事就是跑这个命令确认发起连接的网卡是不是绑定在了我想当然的那个zone上。网卡和zone的绑定关系用以下命令设置firewall-cmd --zoneinternal --change-interfaceeth1注意这条命令同样是运行时生效要永久保存得带上--permanent或者最后做一次runtime-to-permanent转换。同时还要注意--change-interface会把这个网卡从原来的zone里移出来放到新的zone里是移动关系。如果只想添加绑定而不改变原有关系用--add-interface但通常一个网卡同时绑两个zone没有实际意义默认还是走change更符合使用场景。3. 实操配置从最基础的服务放行到复杂应急规则3.1 前置检查装了、开了、启动了吗拿到一台新服务器先确认firewalld装了没有、状态如何。CentOS类的系统一般自带Debian系有些精简安装需要手动装Ubuntu默认的ufw和firewalld不共存如果装了ufw并启用了firewalld启动时可能会报冲突建议二选一。systemctl status firewalld systemctl start firewalld systemctl enable firewalld这里有一个很容易踩的坑firewalld启动之前服务器上如果有遗留的iptables规则或者nftables规则firewalld启动后的行为可能跟预期不一致。firewalld接管的是自己的规则链它启动时默认会刷新掉部分旧的底层规则。所以如果你之前手动加过iptables规则又准备改用firewalld最好先把旧的iptables规则保存备份然后做一次清空再让firewalld接管避免新旧规则互相纠缠导致排查问题的时候思路混乱。3.2 添加服务与端口常用命令一次搞懂firewalld支持两种放行方式一种是按服务名放行一种是按端口放行。按服务名放行底层其实也是端口但是firewalld替你把服务对应的协议和端口映射都内置好了例如firewall-cmd --permanent --add-servicehttp firewall-cmd --permanent --add-servicehttps firewall-cmd --reload按端口放行则更常用因为很多自建应用用的不是标准端口firewall-cmd --zonepublic --add-port8080/tcp --permanent firewall-cmd --zonepublic --add-port10050-10060/tcp --permanent firewall-cmd --reload端口段用短横线连接格式是“起始端口-结束端口”。协议可以是tcp也可以是udp。注意放行某个端口前确认这个端口确实在业务上对外开放而不是凭习惯把一堆端口全放出去。我见过一个真实事故某公司为了方便管理把数据库端口3306在public zone里放开了结果数据库直接被外部扫描爆破一天晚上业务系统就被攻击进来。防火墙规则的最小化原则在这个场景下就是保命原则。删除服务和端口的命令和添加几乎一一对应把--add换成--remove即可firewall-cmd --permanent --remove-port8080/tcp firewall-cmd --permanent --remove-servicehttp firewall-cmd --reload3.3 修改默认zone让内网机器走更宽松的策略有时候服务器的网卡比较多懒得的把每张网卡单独绑定zone可以直接修改默认zone让所有没有绑定关系的网卡自动落到指定zone。比如一台内网数据库服务器业务网段都在内网默认zone改成internal比改成public要省大量配置firewall-cmd --set-default-zoneinternal修改默认zone立即生效不需要reload。这个操作最典型的应用场景是桌面Linux用户。刚装完系统和默认zone是public访问局域网里其他电脑的共享目录、打印机等服务会被拦得很死把默认zone改成home或者trusted许多局域网服务就正常了。但是在服务器上我建议默认zone保持public宁可多配几条精确规则不要图省事把默认信任边界扩大。3.4 用富规则rich rule实现更精细的控制富规则是firewalld提供的一种条件表达能力比较强的规则写法支持按源地址、目的地址、端口、协议、审计、日志等维度组合匹配。新手容易逃避富规则觉得比如--add-port够用但实际遇到场景时就知道它有多重要。举个例子只允许192.168.1.0/24网段的机器访问本机的3306端口其他网段一律拒绝用富规则写firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 source address192.168.1.0/24 port protocoltcp port3306 accept firewall-cmd --permanent --zonepublic --add-rich-rulerule familyipv4 port protocoltcp port3306 drop这里的顺序非常重要。firewalld的规则集合里富规则遵循先匹配先落地的原则。如果把drop规则放在accept规则前面drop会先命中后面的accept永远轮不到。所以要放行特定网段访问特定端口要遵循“精确放行写前面兜底拒绝写后面”的顺序。再比如记录来自某个IP的所有访问日志firewall-cmd --permanent --add-rich-rulerule familyipv4 source address10.0.0.8 log prefixvisitor-from-10.0.0.8 levelnotice这类需求用普通--add-port完全实现不了必须靠富规则。富规则的语法初看很啰嗦但实际上手之后会发现它就是一套“先family后source再port最后action”的声明式描述逻辑链完整。3.5 应急操作禁止一切外部新连接与临时封禁服务器被打、被大量扫描的时候最大的诉求往往是怎么快速切断外部访问。一条命令能做到firewall-cmd --panic-onpanic模式会把所有入站流量全部丢弃相当于瞬间把服务器“藏起来”。这个模式是运行时的重启或者再执行一次firewall-cmd --panic-off就能恢复。注意此命令对所有网卡都生效包括内网网卡执行前务必确认自己的远程连接不会被意外打断通常建议用带外管理或本机执行。临时封禁某个IP持续骚扰的请求firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.66 drop firewall-cmd --reload这里顺便说明一点判断是否需要配封禁规则先看日志里来源地址是否高频出现。我曾经处理过一个案例某台业务服务器短时间内收到大量来自某个地址段的畸形请求导致业务进程CPU打满。用富规则封掉那个地址段后CPU立刻回归正常整个过程没重启任何服务。4. 进阶场景端口转发、地址伪装与多网卡服务器4.1 端口转发把流量导到内网另一台机器firewalld支持端口转发也就是常说的DNAT把发往本机某个端口的流量转发到内网另一台主机的某个端口。典型场景就是跳板机或者说转发机。假设有一台公网服务器公网IP是203.0.113.10需要把发往它8080端口的流量转发到内网主机192.168.10.5的80端口。先开启IP转发功能。确认内核参数net.ipv4.ip_forward已经打开sysctl net.ipv4.ip_forward如果输出是0需要修改/etc/sysctl.conf文件加上net.ipv4.ip_forward 1然后执行sysctl -p生效。这个步骤不做后面配置了转发也不通。然后开启masquerade并添加富规则firewall-cmd --permanent --add-masquerade firewall-cmd --permanent --add-forward-portport8080:prototcp:toport80:toaddr192.168.10.5 firewall-cmd --reload不加--add-masquerade其实是转发的一个常见坑因为目标地址在另一个网段网关在做转发时如果不做地址伪装回包自己就到不了客户端了。很多人转发规则配了好久不通最后发现就是少了这一步masquerade。4.2 地址伪装让内网机器借道访问互联网地址伪装就是SNAT对内网流量做源地址转换把内网机器的源IP改成服务器出口的公网IP。这个在家庭路由器、云上的NAT实例、公司办公网的出口设备上都很常见。在firewalld里开启伪装很简单firewall-cmd --permanent --zoneexternal --add-masqueradeexternal这个zone默认就配置了address masquerade所以直接把外网网卡绑到external zone上再在trusted zone里放行内网网卡一套外网访问NAT就做好了。之所以用external zone是因为它就是为这种场景设计的外部流量被严格过滤内部流量做源地址转换。4.3 多网卡服务器的zone规划多网卡服务器在防火墙规划时一个简单的拓扑可能就足以把人绕晕。我建议按照最朴素的思路来从哪个网络进来的流量该走哪套信任策略就绑哪个zone。举一个典型的多网卡服务器示例网卡连接对象建议zone放行内容eth0公网/外部public80、443eth1内网办公网internalSSH、监控、公司内部服务eth2内部数据库网段trusted数据库端口、内部远程调用端口关联命令firewall-cmd --permanent --zonepublic --add-interfaceeth0 firewall-cmd --permanent --zoneinternal --add-interfaceeth1 firewall-cmd --permanent --zonetrusted --add-interfaceeth2 firewall-cmd --reload这个配置一旦写进永久规则任何想访问数据库端口的人就算从eth2进入是可信的从eth0进来也会被public挡住。这就是多zone设计的意义信任边界是由入口决定的不是由业务端口决定的。很多人图省事把所有规则堆在默认zone里那就像把家门的钥匙放在门垫下面一根安全绳整个解掉。4.4 与业务进程的联动firewalld和Docker共存的问题现在很多服务器上都跑着DockerDocker会自动往iptables里塞自己的规则尤其是那几条NAT规则。firewalld本身也管理iptables/nftables两者同时存在时偶尔会出现“firewalld重启后Docker容器网络异常”的现象。这类问题最著名的症状是firewalld reload之后Docker容器的端口映射全部失效外部访问不到容器内的服务。原因是firewalld reload时重新加载了自己的规则集合清掉了一部分由Docker写入链的规则导致容器和宿主机的IP转发链路断裂。我的处理方式是这样业务上容器映射的端口同步在firewalld里显式放行reload前记录下当前容器的端口映射列表reload后逐个检查外部连通性发现异常就检查DOCKER链是否还在最省心的做法是如果服务器主要跑Docker且内部依赖复杂干脆用systemd把docker和firewalld的启动顺序固定好并在firewalld reload后执行Docker服务的restart让Docker重新写入自己的规则。这个问题没有完美的无痛解法因为两个系统都在抢同一块底层规则表。能做的就是不回避问题把容器端口映射的清单管理起来当作防火墙规则的一部分。5. firewalld上层设计和底层实现为什么它比直接改iptables省心5.1 firewalld、iptables、nftables三者的关系很多新手搞不清楚firewalld和iptables谁是谁的替代品。这里一句话说透iptables是一个命令行工具nftables是Linux内核里新一代的包过滤框架firewalld则是一个管理守护进程。firewalld的底层既可以调用iptables也可以调用nftables取决于你的发行版和内核情况。在较新的发行版上firewalld默认的backend是nftables。你用firewall-cmd写的zone和规则实际落地时会被翻译成nftables规则集。这和传统上理解的一行一行iptables命令是有差别的。nftables不再像iptables一样靠多条独立的链来组织规则而是整张规则表一次性加载。这套设计对普通使用者的价值是防火墙配置从“零散的规则行”变成了“有结构的规则文档”。你可以通过firewall-cmd --list-all查看动静态的全部配置而不是在iptables -L的输出里一行行猜哪条是自己加的。对管理大量服务器的运维来说这种统一的可读结构能减少非常大的人为失误。5.2 图形管理工具firewall-config什么时候用firewalld除了命令行还带了一个图形配置工具firewall-config。不少纯命令行党从来不知道它存在但其实这个图形工具在调整大量zone、服务和富规则时效率非常高。firewall-config把左上角分成Runtime和Permanent两个视图右下角是网卡绑定左边是zone和服务列表勾选和取消勾选非常直观。我平时迁服务器配置的时候喜欢用firewall-cmd --list-all --zonexxx查看文字规则但如果要做大规模比对或者调整网卡绑定关系开一个firewall-config出来反而更方便。不过要注意firewall-config依赖图形环境纯命令行的服务器上没有X就不需要强求。大多数线上环境的管理场景还是firewall-cmd为主。5.3 规则文件不通过命令行的另一种管理方式firewalld的永久配置其实都保存在/usr/lib/firewalld和/etc/firewalld目录下。前者是系统自带默认配置后者是用户自定义配置。当/etc/firewalld下的配置文件存在时会覆盖/usr/lib/firewalld下的同名配置。运维走查时直接去看/etc/firewalld/zones/public.xml这类文件比一条条敲firewall-cmd来得更快cat /etc/firewalld/zones/public.xml生产环境如果需要批量部署多台服务器比起在每台机器上敲命令直接把写好的XML文件分发给多台机器然后执行firewall-cmd --reload速度和一致性都远高于手工操作。这是规模化运维的常规做法也让firewalld的配置管理天然具有“代码即配置”的基因。6. 常见问题与排查技巧实录那些年我踩过的坑6.1 配置明明写了端口却始终不通这种问题出现频率最高。排查步骤首先确认服务本身在监听对应的端口ss -lntp | grep 8080如果服务没监听防火墙配置再对也没意义。接着确认firewalld当前生效配置里是否真的包含这条规则firewall-cmd --list-all --zonepublic | grep 8080如果连list-all里都看不到说明规则没写进这个zone检查是不是用了--permanent却忘了reload。如果第一次执行时只加了--permanent没有reload这时配置只在文件里内存里的运行时规则根本没有变化这是新手最容易忽略的一步。正确顺序是永久规则写完必须先reload或者用firewall-cmd --reload显式加载。如果list-all里能看到规则但外面就是不通再检查是不是网卡绑定的zone和你操作的zone不一致。用前面说过的--get-active-zones看网卡实际落在哪个zone很可能你对着public配置了半天网卡实际在internal里。6.2 加了drop规则把远程连接弄断了这事我不仅自己碰到过几乎每个运维都经历过那么一两次。给某台服务器加了一条“拒绝某个网段”的富规则结果自己也在这个网段里下一秒终端就断了所有连接。一旦发生这种情况唯一的出路就是带外管理。云服务器用厂商提供的控制台VNC物理服务器用IPMI或者机房远程管理卡。如果没有带外手段只能赌机器上有没有定时任务能自动清理防火墙规则或者在重启后自动恢复配置。这也引申出一个黄金习惯凡是涉及drop、panic、移除默认放行的操作先在本地开一个长时间挂着的SSH会话然后一步一步加规则并测试不要一次性把多条风险命令手一抖全丢上去。我在生产环境配防火墙时倾向于把变更做成脚本脚本里加上回滚逻辑如果变更后失去了外部连通性定时任务会在几分钟内自动执行reload并恢复旧规则。尽管不是所有环境都适合这种自动化但这一招让我在大批量服务器变更时心里踏实很多。6.3 “FirewallD is not running”和“unit not found”执行firewall-cmd时报FirewallD is not running表示服务没启动或者启动失败。先看服务状态systemctl status firewalld journalctl -u firewalld -n 50常见原因是firewalld启动时找不到合适的backend比如系统里既没有iptables也没有nftables或者firewalld的新版本对nftables的某些内核特性有依赖。解决办法是确认内核版本够新并安装对应的nftables软件包。如果报unit not found说明系统里压根没装firewalld。按发行版用对应命令安装即可。Ubuntu用户要特别注意系统自带ufwfirewalld和ufw同时启用会抢iptables规则。建议哪一个是主要管理工具就留哪一个不要同时跑。ufw不是firewalld的fork两者是并列的防火墙前端互不兼容。6.4 reload之后容器网络异常上文简单提过这里再补充一个具体排查命令。正常情况下Docker会维护自己的iptables链包括DOCKER、DOCKER-USER等。执行以下命令查看iptables -t nat -L -n | grep DOCKER正常情况下能看到DOCKER链存在并且有对应的DNAT规则。如果reload之后发现整个链消失了基本就是firewalld把Docker的规则清掉了。解决办法是用前面提到的固定顺序或者重启Docker。想从根本上降低冲突也可以考虑把Docker的iptables启用开关调成false并手动维护容器端口到宿主机的转发但这样维护成本高适合对网络控制要求极高的环境。普通场景我不推荐关闭Docker的iptables集成因为那需要你完全自己接管容器的网络隔离。6.5 direct规则和使用它的风险firewalld里有一个direct接口允许用户直接传入iptables规则绕过zone的抽象。例如firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -p tcp --dport 25 -j REJECTdirect规则在需要快速注入特定底层规则时确实方便但它破坏了firewalld整个zone抽象的一致性。一旦用了direct规则你等于同时维护两层配置时间一长容易混乱。我在线上环境的原则是能用富规则解决的就不用direct。富规则表达不了的先想清楚是否真的需要那么底层的操作不到万不得已不碰direct。7. 把习惯固化下来管理firewalld的一些长期经验7.1 规则命名和注释简单但很多人不做firewalld的富规则支持加comment注释这点非常实用。规则多了以后一条平铺的端口放行规则和一段带注释的规则维护成本相差巨大。添加注释的方式firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.2.0/24 port port5432 protocoltcp accept commentallow develop network access postgres虽然注释不会被翻译进底层匹配逻辑但会在firewalld的配置结构里保留。我接手过一台规则极其混乱的服务器里面十几条端口放行全靠猜测是哪个业务在用的。从那以后我给自己定的规矩是所有新增防火墙规则必须带业务注释。遇到没有注释的历史规则顺手查清楚后补上或者干脆删掉。这个习惯会在三个月后给你省下大量时间和脑力。7.2 变更流程备份、变更、验证、回滚一套可复用的firewalld变更流程要比任何命令技巧更值钱。我在实际维护中的做法如下第一步备份当前配置cp -r /etc/firewalld /etc/firewalld.bak.$(date %Y%m%d%H%M%S)二步执行变更先做运行时变更验证后固化永久配置。三步从外部视角验证可以借助另一台测试机、云监控的端口探测工具、甚至手机流量开个端口测试脚本。一定要站在防火墙外面测而不是在本机上用curl测本机回环流量走的是lo网卡往往不经过防火墙的某些规则链所以本机测试通过不代表外部可以访问。四步确认无误后执行reload并复查firewall-cmd --reload firewall-cmd --list-all如果发现异常先把运行时规则恢复备份再把永久配置文件恢复最后再做一次reload。回滚方案越清晰线上操作就越从容。7.3 别把firewalld当成唯一的纵深防线Linux服务器的安全防线不止防火墙这一层。firewalld解决了网络层的访问控制但应用层的问题它管不了。比如某个Web服务存在注入漏洞firewalld放行了80端口攻击者照样可以通过80端口进来搞破坏。所以我的习惯是firewalld负责按最小权限原则开网络口子业务侧再独立做访问控制、认证、授权和审计。防火墙和业务安全是两条平行的防线缺一不可。我自己在实际运维中体会最深的一点是绝大多数防火墙问题都不是命令不会写而是对数据流向和信任边界想得不够清晰。决定请求从哪张网卡进、走哪个zone、命中什么规则比背多少条firewall-cmd命令都重要。所以大家配规则的时候多花一点时间把拓扑和网卡关系画清楚把规则和业务对应起来加注释而不是急着把端口一股脑放行。firewalld的地基稳住之后后面的管理会顺很多。最后再分享一个小技巧每次大版本升级或者换服务器把旧的配置用脚本导出一份列表放在新环境上逐条核对哪些服务还在用、哪些端口已经废弃顺便做一次规则瘦身。我这样清理过几次之后每台服务器的防火墙规则数量都明显下降排障时的脑力负担也跟着降下来了。