资讯动态

firewalld 防火墙从入门到实战:区域模型、命令配置与运维案例

发布时间:2026/10/21 10:48:40 来源:尧图企业网站定制
不用铺垫直接上手写。Linux 服务器跑久了你迟早会跟防火墙打交道。早年大家习惯用 iptables规则一条条往里塞逻辑清楚但维护起来真费劲后来 CentOS 7 开始默认换成 firewalld很多人第一反应是“又来个新东西”实际上手用一阵会发现它把网络信任级别、服务管理、动态更新这些概念揉在一起配置思路跟 iptables 完全不一样理解了这个你再回去看那些“开放端口重启服务”的教程才算真正看懂了门道。这篇文章我打算从零开始把 firewalld 的底层逻辑、日常配置、脚本化操作和实战案例一次性讲透。不绕弯子直接说人话配合可直接复制的命令和配置片段按步骤操作就能落地。1. 先搞懂 firewalld 的底层设计和核心概念1.1 为什么系统要换掉 iptables 那一套管理方式老玩家都知道 iptables 是经典的“链式”规则模型数据包进来从上到下逐条匹配 INPUT、FORWARD、OUTPUT 链上的规则命中了就执行 ACCEPT、DROP、REJECT 这些动作。这种模型本身没问题但真正让人头疼的是两件事一是规则多了之后肉眼很难判断匹配顺序是否正确二是规则的增删改几乎是全量生效你加一条规则等于把整张规则表重新编译一遍连接数一多操作时肉眼可见的卡顿。firewalld 的出发点就是把这套东西“包装”成更贴近运维习惯的模式它把防火墙策略按“区域zone”划分不同区域代表不同的信任级别比如 public 对应不可信的外部网络home、internal 对应相对可信的内网环境。你做的事情不是“在 INPUT 链上插一条规则”而是“告诉系统eth0 网卡属于 public 区域该区域允许 ssh 和 https 服务通过”。底层由 firewalld 自动翻译成 iptables旧版或 nftables新版规则你根本不用关心链是怎么排的。1.2 区域Zone模型一张表看懂信任级别firewalld 默认预置了 9 个区域理解它们之间的信任递进关系是配置防火墙的第一步。你可以把区域想象成“门禁卡等级”等级越高默认放行的流量越多。区域名称默认策略典型适用场景drop丢弃所有入站流量无响应极端安全环境被丢弃方会一直等待超时block拒绝所有入站流量明确回绝临时屏蔽外部访问本机仍可主动出站public仅允许少量指定服务云服务器外网接口最常见生产区域external支持 NAT 伪装转发流量路由器、网关场景dmz允许部分指定服务进入隔离区对外提供 Web 等服务的 DMZ 主机work允许常用办公服务办公网内的工作站home允许常见家庭网络服务家庭内网设备internal类似 home适合内部网络企业内网服务器trusted放行所有入站流量完全可信的内网网段、管理网段生产环境里的标准操作是把外网网卡绑到 public内网网卡绑到 trusted 或 internal这样内网互相访问不做拦截外网只开放 80、443、22 这类必要端口。1.3 运行时配置与永久配置的切换逻辑刚接触 firewalld 的人最容易踩的坑是重启服务后之前加的规则全没了。这不是系统出 bug而是 firewalld 默认操作的是“运行时runtime”配置它只对当前会话生效不做持久化。想要保留配置必须在命令里带上--permanent参数。两个配置空间的关系可以这样理解runtime热修改立即生效适合临时调试和应急封禁。permanent写入磁盘下次重新加载或重启时生效适合正式变更。配置变更后需要执行firewall-cmd --reload让永久配置覆盖运行时配置。注意reload 不会断掉现有连接它是平滑刷新但如果你之前用运行时模式放行了一个临时端口reload 之后这个放行就没了这点在排障时要特别留意。2. 核心配置实操从查询到修改的完整命令体系2.1 先学会查看现状状态、区域、规则三板斧拿到一台新服务器不要急着改配置先花两分钟搞清楚现状。三个最常用的查询命令分别是# 查看防火墙整体状态 systemctl status firewalld firewall-cmd --state # 查看所有区域及其绑定关系、规则详情 firewall-cmd --list-all-zones # 查看默认区域 firewall-cmd --get-default-zone # 查看当前网卡绑定的区域 firewall-cmd --get-active-zones这些命令的输出信息量比较大我一般会先执行--get-active-zones看网卡归属再执行firewall-cmd --list-all --zonepublic精确查看某个区域的详细规则。比如输出里的services:行显示放行的服务名ports:行显示放行的端口rich rules:行显示富规则逐行看下来基本就能摸清现状。2.2 常用配置命令服务、端口、IP 限制、端口转发的增删改查日常运维里最常用到的就是下面这批命令我按场景分好类直接抄作业就行# 放行/移除服务服务是预定义好的名称如 http、https、ssh firewall-cmd --permanent --add-servicehttp firewall-cmd --permanent --remove-servicehttp # 放行/移除端口端口必须带协议类型 tcp 或 udp firewall-cmd --permanent --add-port8080/tcp firewall-cmd --permanent --remove-port8080/tcp # 放行端口范围 firewall-cmd --permanent --add-port6000-6010/udp # 限制来源 IP 访问指定端口只允许特定网段访问 SSH firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.1.0/24 port protocoltcp port22 accept # 拒绝某个 IP 的全部访问 firewall-cmd --permanent --add-rich-rulerule familyipv4 source address10.0.0.8 reject # 端口转发将本机 80 端口转发到 8080 firewall-cmd --permanent --add-forward-portport80:prototcp:toport8080 # 端口转发到远程主机需开启 masquerade firewall-cmd --permanent --add-masquerade firewall-cmd --permanent --add-forward-portport80:prototcp:toport8080:toaddr192.168.1.100 # 修改默认区域 firewall-cmd --set-default-zoneinternal执行完所有--permanent修改后记得跑一次firewall-cmd --reload。如果你改了默认区域但忘记网卡重新绑定有时会出现网卡仍归属旧区域的情况这时手动把网卡绑定过去即可firewall-cmd --permanent --zoneinternal --change-interfaceeth12.3 配置文件长什么样直接编辑 XML 的场景命令行能解决绝大部分问题但批量部署或精细调整时直接编辑配置文件更高效。firewalld 的配置分两大部分/etc/firewalld/zones/存放自定义区域配置/usr/lib/firewalld/zones/存放系统默认区域配置自定义配置永远优先于系统默认配置所以不要修改系统目录下的文件应该把自定义 XML 放到/etc/firewalld/zones/。例如创建一个名为web.xml的区域文件?xml version1.0 encodingutf-8? zone shortWeb/short descriptionWeb server zone/description service namessh/ service namehttp/ service namehttps/ port port8080 protocoltcp/ rule familyipv4 source address192.168.1.0/24/ port protocoltcp port22/ accept/ /rule /zone编辑完成后执行firewall-cmd --reload再用firewall-cmd --zoneweb --list-all检查XML 中每个标签和命令行参数是一一对应的规则来源一致没有魔法。2.4 理解富规则Rich Rules普通规则不够用时的终极武器普通规则只能做“服务 动作”的二元组合限制条件一多就无能为力了。富规则就是为了填这个坑它支持更复杂的条件组合比如限制来源地址、限制并发连接数、按 mac 地址过滤等等。几个典型的富规则写法# 只允许 192.168.1.0/24 网段访问本机 8080 端口 firewall-cmd --permanent --add-rich-rulerule familyipv4 source address192.168.1.0/24 port protocoltcp port8080 accept # 拒绝指定 IP 访问 3306 端口数据库端口 firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.66 port protocoltcp port3306 reject # 限制每分钟新连接数不超过 20 个简易防爆破 firewall-cmd --permanent --add-rich-rulerule service namessh accept limit value20/m富规则的优先级高于普通规则出现规则冲突时以富规则为准。调试时先加一条宽松规则确认能通再逐步收紧条件这是比较稳妥的思路。3. 实战案例拆解从零配置一台 Web 服务器防火墙3.1 场景新上线一台 CentOS 服务器计划部署 Nginx MySQL假设新机器有两个网卡eth0 连接公网eth1 连接内网 192.168.1.0/24。业务需求如下公网仅开放 80 和 443 端口SSH 只允许内网访问MySQL3306只允许内网应用服务器访问禁 ping 但对内网放行按这个需求第一件事是把网络拓扑理清楚然后选区域策略。公网用 public内网用 internal这是最直观的方案。3.2 完整操作流程绑定网卡、开放服务、加载配置按下面的顺序执行每一步都有明确目的# 1. 确认两个网卡名称和归属区域 ip addr firewall-cmd --get-active-zones # 2. 将 eth0 绑定到 publiceth1 绑定到 internal firewall-cmd --permanent --zonepublic --change-interfaceeth0 firewall-cmd --permanent --zoneinternal --change-interfaceeth1 # 3. public 区域放行 http 和 https 服务 firewall-cmd --permanent --zonepublic --add-servicehttp firewall-cmd --permanent --zonepublic --add-servicehttps # 4. internal 区域放行 ssh 和 mysql 服务mysql 是预定义服务名 firewall-cmd --permanent --zoneinternal --add-servicessh firewall-cmd --permanent --zoneinternal --add-servicemysql # 5. 允许内网 ping 通本机internal 区域默认可 ping如果不行就加规则 firewall-cmd --permanent --zoneinternal --add-rich-rulerule familyipv4 source address192.168.1.0/24 protocol valueicmp accept # 6. 正式生效并验证 firewall-cmd --reload firewall-cmd --list-all --zonepublic firewall-cmd --list-all --zoneinternal执行完后可以用curl -I测试 80 端口是否通了用内网机器 ssh 到这台服务器看能不能连上。有个细节--change-interface这个操作是原子的它会将该网卡从原本所有区域中移除再绑定到目标区域比先 remove 再 add 更干净。3.3 端口转发案例把 80 转发到 Tomcat 的 8080Java 开发同学应该遇到过这种场景Tomcat 默认监听 8080但产品要求对外只能暴露 80 端口。如果不想在 Nginx 层做反向代理直接让 firewalld 做端口转发是最快的方案。# 开启 masquerade这是端口转发到非本机端口的前提 firewall-cmd --permanent --add-masquerade # 将访问本机 80 端口的数据转发到本机 8080 firewall-cmd --permanent --add-forward-portport80:prototcp:toport8080 firewall-cmd --reload这里有个容易踩的坑如果 SELinux 是 enforcing 模式转发可能不生效排查时先看/var/log/messages有没有 SELinux 拦截记录必要时用setsebool -P httpd_can_network_connect 1放行。如果需要转发到内网另一台机器把命令改成firewall-cmd --permanent --add-forward-portport80:prototcp:toport8080:toaddr192.168.2.10前提同样是开启 masquerade并且内核参数net.ipv4.ip_forward已设为 1。修改内核参数执行sysctl -w net.ipv4.ip_forward1 echo net.ipv4.ip_forward 1 /etc/sysctl.conf3.4 应急封禁案例防止 SSH 爆破的快速处置新上线的服务器如果安全组没配好ssh 端口被爆破是家常便饭。我自己的服务器就遇到过一天几百次尝试的情况如果没有 fail2ban 这类工具手动封 IP 是很常见的操作。查看哪些 IP 在大量连接本机 22 端口ss -tn state established ( dport :22 or sport :22 ) | awk {print $4} | sort | uniq -c | sort -rn | head发现异常 IP 后用富规则直接封禁firewall-cmd --permanent --add-rich-rulerule familyipv4 source address203.0.113.66 port protocoltcp port22 reject firewall-cmd --reload如果被大量 IP 扫描可以把动态封禁交给 fail2ban但针对单个 IP 的快速处置富规则是效率最高的手段。封禁后检查是否生效firewall-cmd --query-rich-rulerule familyipv4 source address203.0.113.66 port protocoltcp port22 reject3.5 多区域配合案例网关场景下的 NAT 与转发有些场景下服务器要承担网关角色比如给办公室内网做 NAT 上网。firewalld 天然支持这个场景不需要额外配置 iptables。# 外网网卡绑定 external 区域 firewall-cmd --permanent --zoneexternal --change-interfaceeth0 # 内网网卡绑定 internal 区域 firewall-cmd --permanent --zoneinternal --change-interfaceeth1 # external 区域开启 masquerade 伪装 firewall-cmd --permanent --zoneexternal --add-masquerade # 内网区域允许 DNS 和 DHCP 请求通过 firewall-cmd --permanent --zoneinternal --add-servicedns firewall-cmd --permanent --zoneinternal --add-servicedhcp firewall-cmd --reload完成之后内网机器把网关指向这台服务器的内网 IP就能正常上网。external 区域的 masquerade 会自动完成源地址转换不需要手动添加其它规则。4. 疑难杂症排查与高频问题整理4.1 修改配置后不生效或服务异常最经典的问题是规则加了、reload 也执行了但流量还是不通。按下面的顺序排查# 1. 确认网卡绑定区域是否符合预期 firewall-cmd --get-active-zones # 2. 确认规则确实在目标区域里 firewall-cmd --zonepublic --list-all # 3. 确认服务进程在监听正确端口 ss -tlnp | grep port # 4. 检查 SELinux 是否拦截 ausearch -m avc -ts recent规则没写错但流量不通十有八九是网卡绑到了错误的区域或者服务监听了 127.0.0.1 而不是 0.0.0.0。这两个问题都查不出来时再盯一下/var/log/messages和/var/log/firewalld。还有一个隐蔽点firewall-cmd --permanent修改后如果不执行--reload规则不会立即生效但也不会报错。新手上路阶段有 90% 的“我明明加了规则怎么没用”是这个原因。4.2 Dockers 与 firewalld 冲突的解决思路装了 Docker 的主机上firewalld 和 Docker 自带的 iptables 规则经常互相干扰。常见现象是 Docker 容器端口映射出去后外部怎么都访问不到反过来firewalld 放行了某个端口但 Docker 重启后规则被清乱了。其实 Docker 的-p参数会自动写入 iptables 规则firewalld reload 时会刷新整个规则集把 Docker 的规则冲掉。两个解决方案方案一把 Docker 的网段加入 trusted 区域firewall-cmd --permanent --zonetrusted --add-interfacedocker0 firewall-cmd --reload方案二修改 Docker 的 iptables 策略完全托管给 firewalld复杂且不推荐。大部分情况下方案一就够了docker0 是虚拟网桥把流量放行到 trusted 不会产生实际安全问题因为容器本身的网络策略仍然生效。4.3 常见问题速查表症状可能原因解决办法规则加了但重启失效没加--permanent重新加一次带--permanent参数并 reloadreload 后端口失效之前用的是 runtime 临时放行改用 permanent 方式永久放行网卡 IP 变了但规则异常网卡绑定区域错误change-interface 重新绑定容器端口映射不通Docker 规则被 firewalld 刷新docker0 加入 trusted 区域端口转发不生效没开 masquerade 或 SELinux 拦截开启 masquerade检查 SELinux来源 IP 限制不生效富规则语法错误或优先级低检查语法富规则本身优先级更高4.4 firewalld 的性能调优和内核参数配合防火墙在高并发场景下的性能影响不容忽视。firewalld 本身是规则管理工具真正的转发瓶颈在内核网络栈。做高并发业务时下面两组内核参数踩过的坑分享一下# 增加 conntrack 表大小连接数多的场景必须调大 sysctl -w net.netfilter.nf_conntrack_max1048576 sysctl -w net.netfilter.nf_conntrack_buckets262144 # 减少 TIME_WAIT 对性能的损耗 sysctl -w net.ipv4.tcp_tw_reuse1 sysctl -w net.ipv4.tcp_fin_timeout30nf_conntrack_max默认值在几万左右一旦连接数超过这个值新连接会被直接丢弃表现就是高并发下丢包严重、连接超时。调整后可以cat /proc/sys/net/netfilter/nf_conntrack_count观察当前连接数是否逼近上限。5. 工具选型与配置管理firewall-cmd、firewalld 配置库与自动化集成5.1 firewall-cmd 常用参数速查命令虽多但核心参数就那些整理成表格方便查阅功能命令示例查询状态firewall-cmd --state列出区域firewall-cmd --list-all-zones列出指定区域firewall-cmd --zonepublic --list-all添加服务firewall-cmd --permanent --zonepublic --add-servicehttp添加端口firewall-cmd --permanent --zonepublic --add-port8080/tcp添加富规则firewall-cmd --permanent --add-rich-rulerule ...删除规则把 add 换成 remove 即可重新加载firewall-cmd --reload修改默认区域firewall-cmd --set-default-zoneinternal检查端口是否放行firewall-cmd --zonepublic --query-port8080/tcp成人世界的规则每条命令勤加 --permanent再 reload 一次。不加 permanent 的话调试完忘了补永久规则下次重启服务就是一个大坑。5.2 如何用 Ansible 批量管理集群防火墙服务器一多手工敲命令效率太低这时候上 Ansible 是理所当然的。firewalld 模块是 Ansible 内置的不需要额外安装 collection。- name: 开放常用 Web 端口 firewalld: port: 8080/tcp permanent: true state: enabled immediate: yes zone: public - name: 允许内网网段访问 22 端口 firewalld: rich_rule: rule familyipv4 source address192.168.1.0/24 port protocoltcp port22 accept zone: public permanent: true state: enabled immediate: yes执行 Ansible 后规则会立即生效并且永久保存。这里注意immediate: yes参数它在添加 permanent 规则的同时立即应用到 runtime等同于命令行--add-service--reload的组合效果。批量管理几十台机器时这个模块比逐台敲命令靠谱得多。Ansible 模块和底层命令行的参数基本对应最大的好处是幂等性同一规则执行两次不会报错不会产生重复条目。这在手工运维时是做不到的。6. 实战进阶firewalld 与安全加固的联动方案6.1 如何利用富规则实现简单的应用层防护富规则不仅能做来源 IP 限制还能组合出很多应用层防护效果。比如防止某些路径被爬虫大量重试可以对特定 UA 做限流。虽然这种需求通常用 Nginx 层做但某些前置场景下防火墙层直接限制可能更高效# 限制同一来源 IP 对 80 端口的新建连接速率 firewall-cmd --permanent --add-rich-rulerule service namehttp accept limit value30/m这个规则会让每个来源 IP 每分钟最多建立 30 个新连接超出部分直接丢弃。对付低烈度扫描足够但如果是 DDoS 级别流量这层防护确实撑不住还得靠云厂商的流量清洗。另一个实用场景防端口扫描。很多人认为分时段开放端口是安全的做法实际上防火墙层无法完全避免被扫描出开放端口更重要的是确保开放的端口上有足够强壮的认证机制。firewalld 的价值在于缩小暴露面而不是替代应用本身的防护。6.2 ipset 与 firewalld 整合当需要封禁的 IP 数量很大几千、几万条时一条条写富规则会让规则集爆炸性能直线下降。正确做法是和 ipset 配合ipset 本身是内核级的数据结构查询效率极高firewalld 支持直接引用 ipset 名称。创建 ipsetipset create blacklist hash:ip timeout 86400添加封禁 IPipset add blacklist 203.0.113.66在 firewalld 中拒绝该集合的全部流量firewall-cmd --permanent --add-rich-rulerule source ipsetblacklist drop firewall-cmd --reload这个方案在封禁大量 IP 时优势非常明显规则只有一条数据全在 hash 表里O(1) 级别的匹配效率。搭配 fail2ban 使用可以做到自动发现恶意 IP、自动加入黑名单、自动过期这是生产环境的标准玩法。我自己实际测试过直接写一万条富规则和引用一个含一万条 IP 的 ipset规则加载耗时差了一个数量级运行期 CPU 占用差距就更明显了。处理大规模封禁需求时 ipset 基本是唯一合理选择。6.3 基于 firewalld 的端口敲门机制端口敲门Port Knocking是一种把默认关闭端口动态打开的技术通过按顺序访问一组“关闭”的端口防火墙识别到正确的敲门序列后动态放行目标端口。firewalld 虽然没有官方原生支持但可以通过脚本实现类似效果。近几年的安全实践更推荐使用跳板机 堡垒机方案来替代端口敲门因为敲门序列本身可能被嗅探。不过在一些轻量场景下端口敲门仍然是一种有效的隐藏服务方式。我这里给一个简单的思路用systemd监听特定端口的连接日志触发后执行firewall-cmd --add-port22/tcp --zonepublic放行 SSH连接断开后定时收回。由于实现较复杂不展开讲但思路可供有需要的读者参考。6.4 firewalld 和 nftables 的兼容性说明CentOS 7 的 firewalld 后端是 iptablesCentOS 8 及以后版本的后端换成了 nftables。对用户来说firewall-cmd的语法基本不变但如果你直接混用 nftables 规则和 firewalld会发现规则互相覆盖或互不感知。最佳实践是要么纯 firewalld要么纯 nftables不要交叉混用。如果确实需要跑一些 firewalld 覆盖不了的规则建议通过 firewalld 的--direct参数插入而不是直接在 nftables 配置里写这样规则顺序可预期firewalld reload 时也不会清掉你的直接规则firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p tcp --dport 12345 -j ACCEPT--direct参数是 firewalld 官方提供的一条“后门”允许直接插入原始规则。但长期维护的项目里直接规则越多越难管理适合短期应急方案。写在最后的个人经验这些年玩下来最深的体会是firewalld 真正的价值不在于它比 iptables“更安全”而在于它让防火墙规则变得更可管理、可分区、可持久化。真正安全的核心永远是“最小暴露面”原则默认拒绝按需开放定期审计。操作层面我只强调三点改配置务必加--permanent每次变更后跑一次reload并立刻验证生产环境变更前先写好回滚方案——firewalld 的持久化虽然可靠但不能保证你手滑敲错命令不会放错规则。拿新服务器练手时可以故意把默认区域改成 drop再用 trusted 区域放行管理网段感受一下“默认全拒、按需放行”的配置思路。这种模式看起来麻烦但运维后期会给你省掉大量救火时间。实际生产里如果策略已经稳定记得定期把/etc/firewalld目录备份到版本控制里万一哪台机器配置漂移了翻 diff 是定位效率最高的手段。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑