
做Linux运维的没人敢说自己没被防火墙坑过。新装好的CentOS 7明明服务都起来了外部就是访问不通好不容易把端口规则加进firewalld重启机器又“一夜回到解放前”还有那种手滑把SSH端口给禁了人在机房外急得直跺脚的场景想想都肉疼。这篇文章就把RHEL/CentOS系列下的防火墙规则设置讲透从firewalld和iptables的选型、常用增删改查操作、端口转发与IP封禁等进阶玩法到高频故障的排查思路全是一条龙梳理。不管是刚接手服务器的新手还是被防火墙折腾过的老手都能从中找到自己需要的实操答案。1. 先搞懂防火墙的“家底”firewalld 与 iptables 怎么选很多人一提到Linux防火墙脑子里第一反应是iptables结果登录RHEL或CentOS 7以上的服务器敲了半天的iptables命令却一脸懵压根没生效。原因很简单RHEL/CentOS 7开始默认的防火墙管理工具已经换成了firewalld底层虽然还是netfilter框架但管理方式和iptables完全不同。先把这两者的关系理清楚后面的操作才不会做无用功。1.1 从iptables到firewalld的演进逻辑最老牌的iptables可以理解为一套基于“链”和“规则”的指令集它的工作方式是自上而下逐条匹配INPUT、OUTPUT、FORWARD链上定义的规则直到命中某一条再执行对应的动作ACCEPT、DROP、REJECT等。这种方式的优点是底层、精细、可玩性极高几乎能实现任何数据包层面的控制缺点是门槛高规则一多就难维护稍不留神写错一条匹配顺序服务就全乱了。firewalld则是在iptables之上封装了一层动态管理机制它引入了“区域”zone的概念把不同的网络连接归属到不同的信任级别里。比如默认的public区域信任度很低外部访问基本全拦而internal、trusted区域则放行更多流量。你不再需要去关心规则落在哪条链上只需要告诉firewalld“放行哪个端口”“允许哪个IP访问”它自己会去底层生成对应的iptables规则。这也正是新手会觉得firewalld亲切的原因它把实现细节藏起来了让规则管理变成了“面向结果”的操作。不过要注意一点如果你用的还是CentOS 6或者早期的RHEL 6那默认就是传统iptables服务没有firewalld可装命令体系自然还是老一套。所以动手之前先确认系统版本很关键别拿着CentOS 7的firewalld命令在6上硬敲那只会收获一堆“command not found”。1.2 zone区域不同信任级别的隔离区zone是firewalld最核心但也最容易忽视的概念。可以把它想象成你家的几个门trusted区域就像敞开的大门谁进都行public区域像小区单元门外人进来要登记drop区域干脆就是一面墙连个回应都不给你。默认情况下系统启用的是public区域默认网卡也会自动绑定到public上。这个区域的特点就是“默认拒绝大部分入站流量只放行与出站相关的回应流量”。做服务器配置的时候十有八九都是在和public区域打交道。但如果是内部服务比如公司内网的数据库服务器、监控服务器建议把网卡切到internal或者trusted区域省得每次都单独写一堆放行规则。查看当前默认区域和网卡绑定情况用的是两个命令firewall-cmd --get-default-zone firewall-cmd --get-active-zones第一个返回的是全局默认区域第二个返回的是当前所有“正在被使用”的区域及其绑定的网卡列表比如public interfaces: eth0这代表当前生效的是public区域并且eth0网卡绑在上面。如果想把某块网卡换到internal区域用firewall-cmd --zoneinternal --change-interfaceeth0需要提醒的是不加--permanent时这个更改是临时的。一旦重启firewalld服务或者重启机器网卡又会重新按默认区域绑定。所以如果希望长期生效得加上--permanent或者直接用--permanent --zoneinternal --change-interfaceeth0然后firewall-cmd --reload重新加载。这块也是很多人配置完发现“怎么重启就失效了”的头号原因。1.3 运行时配置与持久化配置的区别firewalld最容易被新手忽略的设计就是它把配置分成了“运行时配置”和“持久化配置”两套。运行时配置是当前正在内存里生效的规则改完立即见效但重启后就没影了。持久化配置是写进磁盘配置文件里的规则重启后依然存在但改了不会立即生效要reload或者重启服务才加载到内存里。用大白话讲运行时配置是“临时改一下试试”持久化配置是“定下来以后都这样”。理解这个区别以后再看那些命令后缀就不迷糊了配置方式立即生效重启后保留典型命令运行时是否firewall-cmd --add-port8080/tcp持久化否需reload是firewall-cmd --add-port8080/tcp --permanent实操里最常见的流程是先用不带--permanent的命令临时放行验证服务确实能通再补一条带--permanent的规则永久保存最后reload让持久化配置进入运行时。这样既能快速验证又不会把错误配置“焊死”在机器里。另外提醒一下firewall-cmd --reload和firewall-cmd --complete-reload是有区别的。前者是平滑重载尽量保留现有连接对线上影响小后者是彻底重载所有连接都会中断重来生产环境慎用。2. 日常防火墙规则增删改查用熟这十几个命令就够了很多人一上来就背一堆参数结果第二天全忘光。其实日常运维里翻来覆去就是那么几个场景看状态、开端口、删规则、临时封禁、保存配置。把这五个场景的命令吃透已经能覆盖90%的服务器防火墙需求。2.1 查询类命令先看明白当前状态接手一台服务器第一件事永远是看防火墙当前什么状态而不是直接就加规则。命令很简单systemctl status firewalld firewall-cmd --statefirewall-cmd --state返回running说明服务在跑返回not running就说明firewalld没启动。很多人配置半天发现不生效回头一看服务根本就没开白忙一场。查看当前区域下已经放行的服务和端口用firewall-cmd --list-all输出大致长这样public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh ports: 8080/tcp protocols: ...这里重点看services和ports两行。services显示的是“服务名”ports显示的是“端口/协议对”。如果有服务放行了但端口没出现在ports里不用奇怪服务名的背后可能包含多个端口比如dhcpv6-client服务本身就自带一串端口定义不需要你手动去填。如果只想看某一块区域下的规则不看默认区域可以用firewall-cmd --zoneinternal --list-all这个在排查多网卡服务器的出站入站异常时特别有用。我遇到过一台服务器eth0上挂公网、eth1上挂内网结果在public区域加了规则不管用后来才发现流量走的是internal区域规则加错了地方。2.2 开放端口与服务最常用的场景开放端口是出现频率最高的操作比如部署一个Web服务要放行80和443firewall-cmd --add-port80/tcp firewall-cmd --add-port443/tcp这里有个细节值得注意/tcp后缀不能省。只写--add-port80会直接报错因为firewalld要求必须指定协议类型。如果某个端口TCP和UDP都要放行那就写两遍firewall-cmd --add-port53/tcp firewall-cmd --add-port53/udp临时验证没问题后再补上持久化保存和重载firewall-cmd --add-port80/tcp --permanent firewall-cmd --add-port443/tcp --permanent firewall-cmd --reload除了端口firewalld还内置了一堆服务名可以直接放行像ssh、http、https、mysql等。放行服务的好处是省心比如firewall-cmd --add-servicehttp这条命令等价于放行了80/tcp因为http服务在firewalld的配置文件里就定义成了80/tcp。但这种便利也有个坑如果你改了服务的默认端口比如把SSH从22改成了22022那--add-servicessh放行的还是22端口根本不生效。这种时候必须用--add-port22022/tcp别再指望服务名了。2.3 删除与修改规则别只会加不会撤加规则容易删规则也一样简单对称写就行。删端口firewall-cmd --remove-port8080/tcp删服务firewall-cmd --remove-servicehttp同样要想重启后也删除需要带上--permanent并reload。不过有一种情况容易踩坑你用--add-port8080/tcp临时加了规则然后又执行了--permanent的添加这时候临时和持久化两套里都有8080端口。如果你只执行firewall-cmd --remove-port8080/tcp删掉的只是运行时的那一条持久化配置里的还在reload之后端口又“复活”了。所以删的时候最好先查一下两套配置里的状态或者干脆加、删都统一带--permanent保持配置口径一致能省去很多麻烦。如果想一次性清掉某个区域下的所有自定义规则恢复到初始状态可以firewall-cmd --zonepublic --permanent --change-interfaceeth0或者直接把配置目录里的对应XML文件恢复默认这里不太建议新人手动去改XML文件容易把语法写错导致firewalld起不来。用命令操作是最稳妥的方式这点慢慢体会。3. 进阶场景实战端口转发、IP封禁与多网卡策略基础操作只是开胃菜生产环境里真正让人挠头的往往是端口转发、恶意IP封禁、多网卡多区域这类场景。这几块掌握了防火墙才算真正入门。3.1 用firewalld做端口转发端口转发的应用场景很常见内网有一台机器跑了某个服务但不想直接暴露它的IP于是让防火墙这台机器帮忙把外部请求转发到内网机器上。firewalld里做端口转发需要两块配置缺一不可。第一步开启IP转发功能也就是让Linux内核允许数据包在不同网卡之间转发。修改内核参数echo net.ipv4.ip_forward1 /etc/sysctl.conf sysctl -p如果不开启这个参数就算防火墙规则写对了数据包到了这台机器也不会被转发出去只会默默丢弃。第二步在firewalld里添加端口转发规则。比如把外部访问本机8080端口的请求转发到内网机器192.168.1.10的80端口firewall-cmd --add-forward-portport8080:prototcp:toaddr192.168.1.10:toport80这里格式比较长拆开看就清晰了port8080本机对外提供服务的端口prototcp协议类型toaddr192.168.1.10目标内网IPtoport80目标端口如果目标端口和本机端口一致可以省略toportfirewall-cmd --add-forward-portport8080:prototcp:toaddr192.168.1.10完成之后记得用--permanent保存并reload。验证端口转发是否成功可以在内网机器上抓包看有没有流量进来或者直接用另一台外部机器访问防火墙的8080端口看返回结果。这里有一个经常被忽略的细节firewalld默认的转发行为还要受target策略影响。如果当前区域的target是default通常放行是没问题的但如果有人把区域target改成了DROP转发规则即使写了也白搭。所以遇到“规则明明加了就是不通”的情况优先检查firewall-cmd --list-all输出的target字段是不是default。3.2 封禁IP与限速的富规则写法封禁某个恶意IP是运维刚需。最简单的办法firewall-cmd --add-rich-rulerule familyipv4 source address1.2.3.4 drop这就是富规则的用法firewalld里叫rich rule比普通端口规则更灵活能组合匹配源地址、目的地址、端口、协议等因素。drop动作是静默丢弃对方连超时都等不到如果想直接拒绝并让对方第一时间感知到连接失败把drop换成reject即可firewall-cmd --add-rich-rulerule familyipv4 source address1.2.3.4 reject封禁整个IP段也简单firewall-cmd --add-rich-rulerule familyipv4 source address192.168.1.0/24 drop富规则还可以做端口级的访问控制。比如只允许某个IP访问本机的3306端口其余一律拒绝firewall-cmd --add-rich-rulerule familyipv4 source address10.0.0.5 port port3306 protocoltcp accept注意富规则里accept动作的匹配优先级问题。通常建议你先写一条全局的拒绝规则再叠加特定IP的accept规则但顺序可能会影响结果。最稳妥的方式是把IP白名单做成一个IPset或者在富规则里明确指定顺序。经验不足时建议先在测试环境验证规则顺序别一上来就上生产。3.3 多网卡与Docker共存时怎么避坑多网卡环境下的第一个矛盾是“区域错位”。前面提到过不同网卡可以绑定不同区域规则要加到对应网卡绑定的区域上才有效。查看网卡和区域绑定关系时不要只看--get-active-zones还要配合ip addr确认网卡名称因为有时候操作系统重命名网卡后规则里的接口名是旧的自然不生效。第二个矛盾来自Docker。Docker会往服务器上添加docker0网桥还有一堆独立的iptables规则链它默认会直接在iptables层操作绕过firewalld的管理范围。这就导致一种诡异的现象firewalld里明明已经放行了某个端口但Docker容器里的服务还是访问不通。排查这个问题的思路是这样的Docker自带的链和firewalld之间会互相影响尤其涉及端口映射时Docker的规则优先于firewalld的规则。如果你用docker run -p 8080:80发布了容器端口流量会先经过Docker的DNAT规则再去匹配firewalld链。此时如果firewalld默认区域是drop或对FORWARD链有严格限制容器端口映射就时好时坏。我的建议是使用Docker的主机除非你能完全理清两者协作关系否则别把firewalld的默认target设成drop。另外操作Docker容器端口映射时尽量只在Docker层做端口发布不要再在firewalld里同时给同一个端口添加富规则双层规则叠加极易出现“加了等于没加”的错觉。4. 常见问题排查与避坑实录以下问题名单全部来自我真实踩过的坑一条条对应的都是血泪教训。希望能帮你少走几步弯路。4.1 远程配置防火墙把会话断了怎么办这是运维圈流传最广的经典事故。远程SSH连着一台服务器手一抖执行了firewall-cmd --remove-servicessh或者更狠的直接把默认区域drop了下一秒终端就卡死再也连不上。这时候如果人在机房现场还好说插上显示器键盘就能救问题是很多时候人在千里之外只能干瞪眼。怎么把损失降到最低我的习惯是改防火墙规则之前先开一个“逃生通道”firewall-cmd --add-rich-rulerule familyipv4 source address你的办公IP port port22 protocoltcp accept --permanent firewall-cmd --reload先把现有办公出口IP的SSH访问永久放行再动其他规则。这样就算后面操作失误把其余规则全清了你也能从那个IP正常连进来补救。万一连逃生通道都忘了开那就只能依赖带外管理了服务器厂商的远程管理卡如HP的iLO、Dell的iDRAC、云厂商控制台的VNC登录这些是最后一道防线。记住防火墙规则操作教科书式的顺序永远是先加白名单再动删改最后验证。4.2 规则添加了却不生效规则明明加了firewall-cmd --list-all里也看得见但外部就是不通。这种问题通常绕不开四个原因。第一个是服务根本没监听。防火墙只是控制“放不放行”如果服务进程本身没监听对应端口外部连接自然失败。排查用ss -tlnp | grep 端口号看看监听状态比死磕防火墙规则快得多。第二个是区域绑错了。流量走的是internal区域你却只在public区域加了规则自然无效。用firewall-cmd --get-active-zones确认流量入口网卡绑定的区域再来谈规则。第三个是SELinux捣乱。RHEL/CentOS默认开启SELinux像nginx监听8000端口、MySQL监听33060端口时SELinux策略里没有对应的端口类型标签就会直接阻止进程绑定端口。排查命令ausearch -m avc -ts recent如果有SELinux拦截记录可以临时用setsebool -P httpd_can_network_connect 1开启对应布尔值或者更粗暴一点用setenforce 0先关掉确认是SELinux导致的问题。但注意生产环境不建议长期关闭SELinux正确做法是按需调整布尔值或端口标签。第四个是云平台安全组。如果你用的是云服务器除了系统内部的防火墙云控制台上的安全组也在拦流量。这个问题其实现场解决起来最简单去控制台看一眼入站规则是否放行了对应端口就行很多人却折腾了几个小时在系统里各种试最后发现是安全组没配。4.3 防火墙开机自启与SELinux配合问题新装系统后防火墙可能压根没开机启动这也是很多服务“重启后就不通了”的隐藏原因。设置开机自启systemctl enable firewalld systemctl start firewalld如果企业安全要求高确实需要默认关闭防火墙那就必须确保机器不直接暴露在不可信网络下并且其他安全手段要到位。但绝大多数服务器场景老老实实开着防火墙才是正道。SELinux和防火墙的关系也需要多说两句。SELinux管的是“进程能不能访问资源”防火墙管的是“网络包能不能进出系统”两者互不替代。常见情况是防火墙放行了SELinux却把进程访问某个文件的行为拦了导致服务表现异常。排查顺序建议由内到外先看进程有没有起来再看端口有没有监听接着查SELinux审计日志最后才轮到防火墙规则。4.4 配置备份与恢复别等出事才想起防火墙规则积累到一定规模以后备份就变成一件必须提前做的事。firewalld的持久化配置全部存储在/etc/firewalld/目录下默认配置则在/usr/lib/firewalld/。自己改过的规则都在/etc/firewalld/zones/下备份最直接的方式就是把这个目录打包tar czf firewall-backup-$(date %F).tar.gz /etc/firewalld/恢复也简单把备份解压回原目录然后firewall-cmd --reload加载即可。另外也可以导出某个区域的全部规则firewall-cmd --zonepublic --permanent --list-all把输出保存成文本方便在新机器上一比一重建。前者适合整机迁移后者适合快速复现相同策略按场景二选一就行。如果用的是传统iptables备份则用iptables-save /etc/iptables-backup-$(date %F).rules恢复的时候iptables-restore /etc/iptables-backup-xxxxxxxx.rules这里特别提一下iptables-save的备份文件要放在安全的地方最好定期同步到备份服务器或对象存储。有人图省事把备份直接放在出问题的服务器上结果磁盘坏了或系统重装备份一并消失等于没备份。5. 写在最后防火墙这堵墙搭得越明白用它越顺手我自己刚接触Linux防火墙那阵子也经历过“十个端口九个不通还有一个要重启”的混乱时期。后来慢慢养成了几个固定习惯这里一并分享出来。第一个习惯所有防火墙操作先做临时验证再落持久化。不管加端口、删规则还是改转发永远先用不带--permanent的命令跑一遍确认业务不受影响再补持久化。这个流程多花十几秒但能避免把错误配置永久写入系统。第二个习惯动防火墙前先看SELinux、看监听端口、看区域绑定三个检查最多花一分钟却能屏蔽掉一半以上的无效排查。顺序上业务不跑先查进程和监听进程正常再查SELinux审计最后才打开防火墙规则逐条核对。第三个习惯远程机器上改防火墙规则永远先放行自己的办公IP再动其他规则。这就像进隧道前先确认备用出口哪怕最后没用上心里也不慌。防火墙规则的本质是把“谁能进、谁不能进、能进到什么程度”说清楚。规则本身不复杂真正的复杂度在业务场景里哪条流量该放、哪条该拦、哪些服务和端口有着隐性的依赖关系。多在自己搭的实验环境里把端口转发、富规则、区域切换都完整跑几遍踩过的坑都会变成你的肌肉记忆。等你哪天遇到“防火墙一切正常但业务就是不通”的诡异问题不再手足无措那说明这关你真的过了。