第36章:firewalld 防火墙(CentOS/RHEL)
13 分钟阅读
第三十六章:firewalld 防火墙(CentOS/RHEL)
CentOS/RHEL(以及 Fedora、OpenSUSE 等)默认使用 firewalld 作为防火墙管理工具。和Ubuntu的UFW不同,firewalld是红帽系Linux的标配。
firewalld的核心概念是"区域"(Zone)——每个网络接口可以属于一个区域,每个区域有不同的信任级别和规则。firewalld还支持"服务"(Service)和"端口"(Port)的灵活配置,比直接写iptables规则要友好得多。
本章配套视频:CentOS服务器到手,先把firewalld配置好,别等被黑了才想起来。
36.1 firewalld 简介:动态防火墙
firewalld(Dynamic Firewall Manager)是红帽Linux的默认防火墙管理系统,从RHEL 7开始取代了iptables的静态配置方式。
36.1.1 底层是什么
这里必须先纠正一个流传很广的说法:firewalld 的底层不一定是 iptables。
| 系统 / firewalld 版本 | 默认后端 |
|---|---|
| RHEL 7、CentOS 7(firewalld 0.4 前后) | iptables |
| RHEL 8+、RHEL 9、CentOS Stream、Fedora(firewalld 0.6 以后) | nftables |
无论用哪个后端,都是同一套 Linux 内核的包过滤框架,规则最终下发给内核执行。想确认当前用的是哪个:
| |
firewall-cmd 与 firewalld 守护进程之间通过 D-Bus 通信,所以普通用户不能直接改防火墙——必须通过 sudo 调 firewall-cmd,由守护进程去写后端规则。
graph TB
A["firewalld命令行<br/>firewall-cmd"]
B["firewalld配置<br/>XML文件"]
C["D-Bus接口"]
D["iptables规则"]
E["netfilter内核模块"]
A --> C --> D --> E
B --> C
style A fill:#ccffcc
style D fill:#ffcccc
style E fill:#ff999936.1.2 zone 概念
firewalld引入了"区域"(Zone)的概念。Zone是一组预定义的规则集,代表不同的信任级别。
每个网卡可以分配到一个Zone,firewalld根据网卡所属Zone来决定应用哪些规则。Zone是firewalld的核心,几乎所有的配置都围绕着Zone展开。
graph TB
A["firewalld 内置 Zone<br>按信任度从低到高"] --> B["drop:丢弃<br>所有入站一律丢弃<br>不回任何响应"]
A --> C["block"]
A --> D["public"]
A --> E["external"]
A --> F["internal"]
A --> G["trusted"]
C["block:拒绝<br>所有入站一律拒绝<br>但会回一个 ICMP 拒绝消息"]
D["public:公共(默认)<br>不信任任何主机<br>只放行明确选定的服务"]
E["external:外部<br>开了 NAT 伪装<br>用于路由器/跳板机"]
F["internal:内部<br>信任内网<br>放行 mdns、samba-client 等"]
G["trusted:完全信任<br>放行一切入站<br>等于不开防火墙,慎用"]
style B fill:#ff6666
style C fill:#ff9999
style D fill:#ffe0cc
style E fill:#ffffcc
style F fill:#ccffcc
style G fill:#99ff99完整的 9 个内置 Zone(还有 dmz、work、home)和它们的详细说明,可以直接问 firewalld:
| |
除了教程里详细展开的 drop、block、public、external、internal、trusted,另外三个:
| Zone | 定位 |
|---|---|
dmz | 隔离区:对外提供服务但严格受限,只放行必要端口 |
work | 办公网络:信任同事的机器,放行 ssh、mdns、dhcpv6-client 等 |
home | 家庭网络:比 work 更宽松一点,额外放行 samba-client |
实际运维里,90% 的情况只要一个
public就够了:默认拒绝,然后按需--add-service/--add-port。Zone 的价值在于"同一台机器有多块网卡、连接不同网络"时能套用不同规则。
36.2 firewall-cmd 命令
firewalld的管理命令是firewall-cmd。和UFW类似,它也提供了运行时配置和永久配置两种模式。
| |
| |
重要区别:firewalld 有两套并行的配置,这是它和 UFW 最大的不同:
运行时配置(Runtime) 永久配置(Permanent) 存哪里 内存 /etc/firewalld/zones/*.xml立即生效 是 否,要 --reload(或重启 firewalld)才生效重启后 丢失 保留 怎么改 firewall-cmd --add-port=...firewall-cmd --permanent --add-port=...⚠️ 血泪教训:只写了
--permanent而忘了--reload,规则不会立刻生效,你以为没加上;反过来,只写了运行时规则没加--permanent,重启后规则就没了。“改完永久配置必须 reload"是本章最该记住的一句话。如果已经在运行时调试好了,也可以"就地转正”,不用把命令再敲一遍:
1sudo firewall-cmd --runtime-to-permanent # 把当前运行时配置整体写入永久配置
36.3 zone 概念
firewalld内置了多个预设Zone,每个Zone有不同的默认规则。
36.3.1 drop:最低信任
drop区域是"最不信任"的区域,丢弃所有入站数据包,不回复任何响应。
| |
| |
target: DROP:默认动作是丢弃所有入站interfaces: eth0:eth0网卡属于这个zoneservices::没有放行任何服务
36.3.2 block:拒绝
block区域和drop类似,但会返回ICMP错误(如icmp-host-prohibited)。
| |
| |
%%REJECT%% vs DROP:REJECT会返回ICMP拒绝消息,告诉对方"你被拒绝了";DROP则完全无视,就像石沉大海。
36.3.3 public:公共
public区域是firewalld的默认区域,适用于"公共场所"的网卡(如连接互联网的网卡)。
| |
| |
默认只放行了ssh和dhcpv6-client,其他入站连接一律默认拒绝。
36.3.4 external:外部
external区域用于需要NAT/路由功能的场景,比如把服务器当路由器用。
| |
| |
注意masquerade: yes——这是external区域的特殊之处,它会自动开启IP地址伪装(类似家用路由器的NAT功能)。
36.3.5 internal:内部
internal区域适用于内部网络,信任度较高,默认允许大部分入站服务。
| |
| |
默认允许ssh、mdns(局域网设备发现)、samba-client(Windows文件共享客户端)、dhcpv6-client。
36.3.6 trusted:完全信任
trusted区域是最危险的区域——允许所有入站连接。等同于"关掉防火墙"。
| |
| |
target: ACCEPT意味着所有入站连接都被接受。
使用场景:trusted区域适合用于管理网卡(如VPN网卡),只允许管理员从特定网卡访问。
36.4 firewall-cmd –list-all:查看所有规则
查看当前zone的所有规则:
| |
| |
| |
36.5 firewall-cmd –add-port:开放端口
用--add-port开放端口:
| |
| |
⚠️ 上面这些命令没有写
--zone,默认操作的是"当前默认 zone"(通常是public)。如果机器改过默认 zone,或者有多个 zone 挂在不同网卡上,命令就会落到你不期望的地方。养成显式写 zone 的习惯:
1 2 3sudo firewall-cmd --zone=public --permanent --add-port=3306/tcp sudo firewall-cmd --reload sudo firewall-cmd --zone=public --list-ports # 验证另外注意:
--list-ports看的是运行时规则。只加了--permanent还没 reload 时,它显示不出你刚加的东西——别急着怀疑自己输错了。
36.6 firewall-cmd –remove-port:关闭端口
| |
36.7 firewall-cmd –add-service:按服务开放
firewalld内置了很多预定义服务,比直接指定端口更方便:
| |
| |
| |
⚠️ firewalld 的"服务"清单和 UFW 的应用配置不是一回事。比如 UFW 里有
Nginx Full,但 firewalld 默认没有nginx、nginx-full这样的服务,--add-service=nginx-full会直接报INVALID_SERVICE。这种情况按端口放行即可:
1 2 3sudo firewall-cmd --permanent --add-port=80/tcp sudo firewall-cmd --permanent --add-port=443/tcp sudo firewall-cmd --reload想自己定义一个名为
nginx的服务?在/etc/firewalld/services/下写一个 XML 即可(把/usr/lib/firewalld/services/里的现成文件复制过来改端口最省事),然后firewall-cmd --reload。
| |
| |
36.8 firewall-cmd –permanent:永久生效
--permanent参数是firewalld的"持久化开关"。不加这个参数,配置只对当前会话生效,重启后丢失。
| |
实战顺序:先
--permanent添加规则,最后--reload一次性使所有永久配置生效。不要每改一条就reload一次,效率太低。
36.9 firewall-cmd –reload:重新加载
--reload重新读取配置文件,使所有--permanent添加的规则生效。
| |
注意 --list-all 和 --permanent --list-all 看的是两套数据,别混淆:
| |
另外,--reload 会丢弃所有只在运行时做的改动。所以"运行时调试 → 满意后 –runtime-to-permanent → reload 验证"这条路径,比"边改边 reload"稳得多。
| |
36.10 rich-rule 高级规则
rich-rule(富规则)是firewalld的高级规则语法,支持复杂的条件判断和动作。
36.10.1 基于 IP 的规则
按来源IP放行或拒绝:
| |
| |
| |
36.10.2 端口转发
firewalld支持端口转发(Port Forwarding),将一个端口的流量转发到另一台机器:
| |
| |
应用场景:内网服务器没有公网IP,通过有公网IP的跳板机做端口转发访问内网服务。
⚠️ 端口转发必须有
masquerade(NAT 伪装)配合,否则转出去的包回不来。转发到另一台机器时,要在做转发的这台机器上开启:
1 2sudo firewall-cmd --permanent --add-masquerade sudo firewall-cmd --reload同时内核转发也得打开:
1 2echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-forward.conf sudo sysctl --system还有一点容易漏:请求得先能被"接收"才谈得上转发。如果
publiczone 的默认策略是拒绝,那么 2222 端口本身也要放行(--add-port=2222/tcp),否则包在进 zone 的那一步就被丢了。
36.11 常用运维操作与避坑
36.11.1 每台机器都该会的几条
| |
36.11.2 规则存在哪
| |
临时想手工改 XML 也可以,但改完必须 firewall-cmd --reload,并且文件格式写错会导致 firewalld 起不来——不如老老实实用 firewall-cmd 生成。
36.11.3 避坑清单
- 只写
--permanent不写--reload:规则没生效,以为加错了。改永久配置后一律--reload。 - 不写
--zone:落在默认 zone 上。多网卡、多 zone 的机器一定要显式指定。 --list-all和--permanent --list-all混着看:前者是运行时,后者是文件里存的。两者不一致时,先想清楚要不要--runtime-to-permanent。- 改 SSH 端口时先删旧规则:正确顺序是"改 sshd 配置 → 放行新端口 → 另开会话验证 → 再删旧端口",和 35.13.3 里的流程一样。
--direct直写规则:这是老 API,容易被 firewalld 的 reload 冲掉。除非确定需要,否则一律用 rich-rule 或 zone 配置。- 和 Docker 混用:Docker 会直接往 nftables/iptables 里插自己的链,绕过 firewalld。容器端口想只对本机开放就写成
-p 127.0.0.1:8080:80,再从外部用nc -vz验证。 - 别把
trusted当作"方便":给网卡加trusted等于那块网卡上的流量全部放行。
本章小结
本章我们掌握了CentOS/RHEL下firewalld防火墙的配置:
- firewalld简介:红帽系 Linux 的动态防火墙;RHEL 8/9 及以后的默认后端是 nftables,不是 iptables
- Zone类型:共 9 个内置 zone,常用的有 drop(丢弃)、block(拒绝)、public(公共,默认)、external(外部/NAT)、internal(内部)、trusted(信任)
- 运行时 vs 永久:
--permanent改的是文件,必须firewall-cmd --reload才生效;--runtime-to-permanent可以把调好的运行时配置转正 - firewall-cmd:firewalld的命令行管理工具
- –list-all:查看运行时规则;加
--permanent才是看文件里的配置 - –add-port / –remove-port:开放/关闭端口
- –add-service / –remove-service:按服务名放行/关闭(firewalld 没有
nginx-full这种服务,按端口放行) - rich-rule:高级规则,支持按 IP 放行、端口转发等复杂场景
- 端口转发:记得同时开
masquerade和net.ipv4.ip_forward - 应急:
--panic-on一键切断所有流量
firewalld的Zone+Service+Rich Rule三层配置,足够应付绝大多数生产环境需求。