firewall-cmd 使用手册
firewall-cmd 使用手册
适用环境:RHEL 7+ / CentOS 7+ / Fedora 18+ / Rocky Linux / AlmaLinux
底层机制:firewalld动态防火墙守护进程,基于nftables(新版)或iptables(旧版)
命令格式:firewall-cmd [选项...]
目录
- 基本概念
- 启动与状态管理
- 区域(Zone)管理
- 服务(Service)管理
- 端口(Port)管理
- 富规则(Rich Rules)
- IP 封禁与访问控制
- NAT 与端口转发
- 直接规则(Direct Rules)
- IP 集(IPSet)管理
- 辅助与查询命令
--permanent与临时规则- 注意事项
- 常见问题排查
1. 基本概念
1.1 什么是 firewalld
firewalld 是一个动态防火墙管理工具,由红帽主导开发。它与传统的 iptables 静态规则不同,支持运行时修改规则而无需断开已有连接或重启服务。firewall-cmd 是其命令行管理前端。
1.2 核心概念
| 概念 | 说明 |
|---|---|
| Zone(区域) | 预定义的安全信任级别集合,每个网络接口被分配到一个 zone |
| Service(服务) | 一组预定义的端口/协议组合,如 ssh、http、https |
| Port(端口) | 直接通过端口号 + 协议开放访问,如 80/tcp |
| Rich Rule(富规则) | 更精细的过滤规则,支持源/目标 IP、日志记录、限速等 |
| Direct Rule(直接规则) | 近乎原生的 iptables/nftables 规则,提供最大灵活性 |
| IPSet(IP 集) | 一组 IP 地址的集合,用于批量管理 |
| Runtime / Permanent | runtime = 当前生效;permanent = 永久存储,重载后生效 |
1.3 预定义 Zone 及信任级别
| Zone | 信任级别 | 默认行为 |
|---|---|---|
drop | 最低 | 所有入站包静默丢弃,仅允许出站 |
block | 极低 | 拒绝入站并返回 icmp-host-prohibited |
public | 低(默认) | 只允许被明确放行的入站连接 |
external | 中低 | 用于 NAT 网关,启用 IP 伪装 |
dmz | 中等 | 用于 DMZ 区,只允许选定的入站连接 |
work | 中高 | 信任工作网络中的大多数计算机 |
home | 高 | 信任家庭网络中的大多数计算机 |
internal | 高 | 信任内部网络中的大多数计算机 |
trusted | 最高 | 所有网络连接都被接受 |
2. 启动与状态管理
firewalld 是一个守护进程(daemon),由 systemd 管理生命周期。启动、停止、重载规则是日常运维最基本的操作。理解 --reload、--complete-reload 与 --check-config 三者的区别,可以避免在远程操作时因规则错误把自己"锁在门外"。本章还介绍了 panic 模式,作为应急开关可在遭遇攻击时一键封锁所有入站流量。
2.1 服务启停
# 启动 firewalld
systemctl start firewalld
# 停止 firewalld
systemctl stop firewalld
# 重启 firewalld
systemctl restart firewalld
# 设置开机自启
systemctl enable firewalld
# 禁用开机自启
systemctl disable firewalld2.2 状态查看
# 查看防火墙运行状态
firewall-cmd --state
# 查看当前默认 zone
firewall-cmd --get-default-zone
# 查看所有已激活的 zone
firewall-cmd --get-active-zones
# 查看全部支持的服务列表
firewall-cmd --get-services
# 查看当前 zone 的完整配置
firewall-cmd --list-all
# 查看指定 zone 的完整配置
firewall-cmd --zone=public --list-all2.3 规则重载
# 重载防火墙(不中断现有连接,推荐)
firewall-cmd --reload
# 完全重载(会短暂中断连接,仅用于状态异常时)
firewall-cmd --complete-reload
# 仅检查配置是否有效(不执行变更)
firewall-cmd --check-config重要:--reload会删除所有仅存在于 runtime 的临时规则;--complete-reload会重置整个防火墙状态。
3. 区域(Zone)管理
Zone(区域)是 firewalld 最核心的抽象概念——它把网络环境按"信任级别"划分为不同等级,每个等级对应一套独立的安全策略。比如你笔记本电脑连到公司网络时可以信任大多数连接,连到咖啡馆 Wi-Fi 时则应该严格限制入站流量。Zone 让这种场景切换变得简单:只需将一个网卡绑定到对应 zone,该 zone 下所有服务、端口、富规则就会自动生效。一台服务器通常只用 1~2 个 zone,默认 public 足以覆盖绝大多数场景。
3.1 查看 Zones
# 列出所有可用 zone
firewall-cmd --get-zones
# 查看当前默认 zone
firewall-cmd --get-default-zone
# 查看网卡接口被分配到哪个 zone
firewall-cmd --get-zone-of-interface=eth0
# 查看指定 zone 的所有配置(runtime)
firewall-cmd --zone=public --list-all3.2 设置默认 Zone
# 设置默认 zone(永久生效)
firewall-cmd --set-default-zone=dmz
# 修改的是 permanent 配置,需 reload 才生效
firewall-cmd --reload3.3 将网卡绑定到 Zone
# 将 eth0 绑定到 external zone(永久生效)
firewall-cmd --permanent --zone=external --change-interface=eth0
# 临时绑定(runtime,重启/重载后丢失)
firewall-cmd --zone=external --change-interface=eth0
# 查看网卡所属 zone
firewall-cmd --get-zone-of-interface=eth03.4 创建自定义 Zone
# 创建自定义 zone(永久)
firewall-cmd --permanent --new-zone=custom-app
# 重载使其可用
firewall-cmd --reload
# 删除自定义 zone
firewall-cmd --permanent --delete-zone=custom-app
firewall-cmd --reload3.5 Zone 目标(Target)
每个 zone 可设置默认目标,决定未匹配流量的处理方式:
# 查看 zone 的 target
firewall-cmd --zone=public --get-target
# 设置 target(DEFAULT / ACCEPT / DROP / %%REJECT%%)
firewall-cmd --permanent --zone=public --set-target=DROP
firewall-cmd --reloadDEFAULT表示沿用该 zone 的默认行为(不操作 chain 策略)。
设置为DROP后,该 zone 下所有未明确放行的流量都会被静默丢弃。
4. 服务(Service)管理
在 firewalld 中,"服务"(Service)不是指正在运行的进程,而是一个预定义的端口/协议组合模板。比如 http 服务等于 80/tcp,https 等于 443/tcp,ssh 等于 22/tcp。使用服务有两个好处:① 可读性强——--add-service=http 比 --add-port=80/tcp 更直观;② 可维护性高——服务定义集中在 XML 文件中,修改一处即可全局生效。系统预置了上百种常见服务(firewall-cmd --get-services 查看全部),你也可以为自有应用创建自定义服务定义。
4.1 查看预定义服务
# 列出所有预定义服务
firewall-cmd --get-services
# 查看某个服务的详细信息(端口、协议、模块等)
firewall-cmd --info-service=ssh输出示例:
ssh
ports: 22/tcp
protocols:
source-ports:
modules:
destination: ipv4: ipv6:4.2 添加 / 移除服务
# 临时添加 HTTP 服务到 public zone
firewall-cmd --zone=public --add-service=http
# 永久添加 HTTPS 服务到 public zone
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --reload
# 同时添加多个服务(永久)
firewall-cmd --permanent --zone=public --add-service={http,https,ssh}
firewall-cmd --reload
# 移除服务
firewall-cmd --permanent --zone=public --remove-service=http
firewall-cmd --reload4.3 服务开放组合示例:Web 服务器
# 开放 Web 服务器所需的全部服务(永久)
firewall-cmd --permanent --zone=public --add-service={http,https,ssh}
firewall-cmd --reload
# 验证配置
firewall-cmd --zone=public --list-services4.4 自定义服务配置文件
预置服务定义文件位于 /usr/lib/firewalld/services/,自定义服务放在 /etc/firewalld/services/。
# 创建自定义服务:my-app(监听 8080 和 8443)
cat > /etc/firewalld/services/my-app.xml << 'EOF'
<?xml version="1.0" encoding="utf-8"?>
<service>
<short>My Application</short>
<description>Custom application service on ports 8080 and 8443</description>
<port protocol="tcp" port="8080"/>
<port protocol="tcp" port="8443"/>
</service>
EOF
# 重载使自定义服务可用
firewall-cmd --reload
# 使用自定义服务
firewall-cmd --permanent --zone=public --add-service=my-app
firewall-cmd --reload
# 验证自定义服务是否存在
firewall-cmd --info-service=my-app5. 端口(Port)管理
端口规则是最直接的放行方式——指定"哪个端口 + 什么协议"就完了,不依赖任何预定义模板。当你要开放的服务不在预置服务列表中(如非标准端口上的自定义应用),或者你只需要临时开一个端口做测试,用端口规则比去写 XML 服务定义快得多。但要注意:端口规则是"裸"的,缺少语义信息,维护起来不如服务规则直观。实用经验:常见标准服务优先用 --add-service;非标准端口或一次性场景用 --add-port。
5.1 查看已开放端口
# 查看当前 zone 下的已开放端口
firewall-cmd --zone=public --list-ports
# 查看永久配置中的端口
firewall-cmd --permanent --zone=public --list-ports5.2 添加 / 移除端口
# 临时开放 8080/TCP 端口
firewall-cmd --zone=public --add-port=8080/tcp
# 永久开放 443/TCP 端口
firewall-cmd --permanent --zone=public --add-port=443/tcp
firewall-cmd --reload
# 开放端口范围
firewall-cmd --permanent --zone=public --add-port=8000-8099/tcp
firewall-cmd --reload
# 同时开放 TCP 和 UDP
firewall-cmd --permanent --zone=public --add-port=53/tcp
firewall-cmd --permanent --zone=public --add-port=53/udp
firewall-cmd --reload
# 移除端口
firewall-cmd --permanent --zone=public --remove-port=8080/tcp
firewall-cmd --reload5.3 常见运维示例
示例 1:Web + SSH 最小化开放
firewall-cmd --permanent --zone=public --add-service={http,https,ssh}
firewall-cmd --reload示例 2:MySQL / PostgreSQL 数据库服务器
# MySQL(仅允许从内网网段访问 —— 见富规则章节)
firewall-cmd --permanent --zone=internal --add-port=3306/tcp
# PostgreSQL
firewall-cmd --permanent --zone=internal --add-port=5432/tcp
firewall-cmd --reload示例 3:Redis 服务器
# Redis 默认端口
firewall-cmd --permanent --zone=internal --add-port=6379/tcp
firewall-cmd --reload示例 4:Docker 常用端口
# Docker 通过 firewalld 管理端口(如果关闭了 docker 的 iptables 接管)
firewall-cmd --permanent --zone=public \
--add-port=2375/tcp \
--add-port=2376/tcp
firewall-cmd --reload示例 5:Kubernetes 控制平面端口
firewall-cmd --permanent --zone=public \
--add-port=6443/tcp \ # kube-apiserver
--add-port=2379-2380/tcp \ # etcd
--add-port=10250/tcp \ # kubelet
--add-port=10257/tcp \ # kube-controller-manager
--add-port=10259/tcp # kube-scheduler
firewall-cmd --reload6. 富规则(Rich Rules)
如果说服务和端口规则是"开关"——要么全开要么全关,那么富规则就是"调节阀"——你可以精确控制谁(源 IP)、访问什么(端口/服务)、怎么处理(接受/拒绝/丢弃)、是否记录日志、甚至限制连接速率。富规则的语言(Rich Language)是 firewalld 中表达能力最强的安全策略层,大多数生产环境的精细化访问控制都靠它实现。富规则的语法乍看复杂,本质就是一条"条件-动作"语句,读完本章的场景示例就能掌握。
富规则是 firewalld 最强大的功能之一,支持比基本服务/端口管理更细粒度的流量控制。
6.1 富规则基本语法
firewall-cmd --zone=<zone> --add-rich-rule='rule [family="ipv4|ipv6"]
[source address="<CIDR>" [invert="true"]]
[destination address="<CIDR>" [invert="true"]]
[service|port|protocol|icmp-block|masquerade|forward-port]
[log [prefix="<text>"] [level="<level>"] [limit value="<rate>/<unit>"]]
[audit]
[accept|reject|drop|mark]
[limit value="<rate>/<unit>"]'6.2 常用场景与示例
场景 1:仅允许特定 IP 访问 SSH
# 只允许 192.168.1.100 访问 SSH(22 端口),拒绝其他所有来源
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.100/32"
service name="ssh"
accept'
firewall-cmd --reload场景 2:允许某网段访问特定端口
# 允许 10.0.0.0/8 内网访问 MySQL
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="10.0.0.0/8"
port port="3306" protocol="tcp"
accept'
firewall-cmd --reload场景 3:拒绝特定 IP 访问 Web 服务
# 拒绝 203.0.113.50 访问 HTTP/HTTPS
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="203.0.113.50/32"
service name="http"
reject'
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="203.0.113.50/32"
service name="https"
reject'
firewall-cmd --reload场景 4:带日志记录的规则
# 记录所有被拒绝的 8080 端口访问尝试,日志前缀 "REJECTED-8080"
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
port port="8080" protocol="tcp"
log prefix="REJECTED-8080: " level="info" limit value="10/m"
reject'
firewall-cmd --reload
# 查看日志
journalctl -f | grep REJECTED-8080场景 5:连接速率限制
# 限制每个 IP 每分钟最多新建 5 个 SSH 连接
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
service name="ssh"
limit value="5/m"
accept'
firewall-cmd --reload场景 6:同时允许 TCP + UDP
# 允许 192.168.1.0/24 网段访问 DNS(TCP+UDP)
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
port port="53" protocol="tcp"
accept'
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="192.168.1.0/24"
port port="53" protocol="udp"
accept'
firewall-cmd --reload场景 7:基于时间的规则(需 firewalld >= 0.4.3)
# 工作时间(周一至周五 09:00-18:00)才允许访问,其他时间拒绝
# 注意:此功能依赖 nftables 支持大多数生产环境建议通过
cron+firewall-cmd组合实现基于时间的控制:# 09:00 开放 0 9 * * 1-5 firewall-cmd --zone=public --add-rich-rule='...' # 18:00 移除 0 18 * * 1-5 firewall-cmd --zone=public --remove-rich-rule='...'
6.3 查看与移除富规则
# 列出所有富规则
firewall-cmd --zone=public --list-rich-rules
# 移除某条富规则(需要与添加时的规则完全一致)
firewall-cmd --permanent --zone=public --remove-rich-rule='
rule family="ipv4"
source address="203.0.113.50/32"
service name="http"
reject'
firewall-cmd --reload7. IP 封禁与访问控制
IP 封禁是运维人员最常用的防御手段之一——当发现某个 IP 在暴力破解 SSH、恶意扫描端口或发起 CC 攻击时,直接将其流量全部丢弃。firewalld 提供了从临时封禁(runtime,不持久化)、永久封禁(permanent)、到批量封禁(IPSet)的完整工具链。本章还会讲解 drop(静默丢弃)与 reject(明确拒绝)的区别——选错的话要么暴露服务存在、要么让合法用户误以为网络不通。
7.1 使用富规则封禁 IP
# 封禁单个 IP(直接 drop,不给任何回应)
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="198.51.100.10/32"
drop'
firewall-cmd --reload7.2 封禁整个网段
# 封禁整个 /24 子网
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="198.51.100.0/24"
drop'
firewall-cmd --reload7.3 使用 reject 还是 drop
| 动作 | 效果 | 适用场景 |
|---|---|---|
drop | 静默丢弃数据包,不回应 | 对外暴露的服务,降低被扫描识别的概率 |
reject | 拒绝并返回 ICMP 不可达 | 内部服务,方便故障排查 |
# drop:静默丢弃
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4" source address="1.2.3.4/32" drop'
# reject:明确拒绝
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4" source address="1.2.3.4/32" reject'7.4 批量管理被封禁 IP —— 使用 IPSet
当需要封禁大量 IP 时,使用 IPSet 比逐条添加富规则更高效(详见 第 10 章)。
7.5 临时封禁(不持久化)
# 直接 drop,不加 --permanent,重载或重启后自动清除
firewall-cmd --zone=public --add-rich-rule='
rule family="ipv4" source address="198.51.100.99/32" drop'
# 查看当前 runtime 中的封禁
firewall-cmd --zone=public --list-rich-rules7.6 使用 fail2ban 配合 firewalld
对于自动化暴力破解防御,推荐使用 fail2ban + firewalld 组合:
# 安装 fail2ban
yum install -y fail2ban-firewalld # RHEL/CentOS 7
dnf install -y fail2ban-firewalld # RHEL 8+/Fedora
# 配置 fail2ban 使用 firewalld
# /etc/fail2ban/jail.local
[sshd]
enabled = true
banaction = firewallcmd-ipset
bantime = 3600
findtime = 600
maxretry = 5
systemctl enable --now fail2ban8. NAT 与端口转发
NAT(Network Address Translation,网络地址转换)是网关/路由场景的核心功能,分为两个方向:SNAT(源地址转换)让内网机器通过防火墙的公网 IP 出站上网——firewalld 中叫 Masquerade(IP 伪装);DNAT(目标地址转换)把外部访问防火墙某个端口的流量转发到内网某台机器的某个端口——这就是端口转发/端口映射。典型场景:公司只有一台公网服务器,通过端口转发将 80/443 端口流量送给内网的 Web 服务器集群。
8.1 启用 IP 伪装(Masquerade)
IP 伪装是源地址 NAT(SNAT),让内网机器通过防火墙访问外网。
# 检查当前是否已启用 masquerade
firewall-cmd --zone=external --query-masquerade
# 启用 masquerade(external zone 常用)
firewall-cmd --permanent --zone=external --add-masquerade
# 如果 external zone 没有绑定网卡,先绑定外网网卡
firewall-cmd --permanent --zone=external --change-interface=eth0
firewall-cmd --reload
# 同时需确保 IP 转发已开启
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p8.2 端口转发(DNAT / Port Forwarding)
将到达防火墙某个端口的流量转发到内网其他主机。
# 语法
firewall-cmd --zone=<zone> --add-forward-port='
port=<port>:proto=<tcp|udp>:toport=<to-port>:toaddr=<to-addr>'
# 示例:将外部 8080 端口的 TCP 流量转发到 192.168.1.10 的 80 端口
firewall-cmd --permanent --zone=external \
--add-forward-port='port=8080:proto=tcp:toport=80:toaddr=192.168.1.10'
# 需要同时启用 masquerade
firewall-cmd --permanent --zone=external --add-masquerade
firewall-cmd --reload8.3 常见端口转发示例
示例 1:同机端口重定向
# 将 80 端口流量重定向到本机 8080(常用于非 root 用户运行应用)
firewall-cmd --permanent --zone=public \
--add-forward-port='port=80:proto=tcp:toport=8080'
firewall-cmd --reload示例 2:多端口转发
# HTTP 转发到内网 Web 服务器
firewall-cmd --permanent --zone=external \
--add-forward-port='port=80:proto=tcp:toport=80:toaddr=10.0.0.5'
# HTTPS 转发到同一台内网服务器
firewall-cmd --permanent --zone=external \
--add-forward-port='port=443:proto=tcp:toport=443:toaddr=10.0.0.5'
# SSH 转发到内网跳板机
firewall-cmd --permanent --zone=external \
--add-forward-port='port=2222:proto=tcp:toport=22:toaddr=10.0.0.10'
firewall-cmd --permanent --zone=external --add-masquerade
firewall-cmd --reload示例 3:端口范围转发
# 将外部 8000-8099 转发到内网同一端口范围
firewall-cmd --permanent --zone=external \
--add-forward-port='port=8000-8099:proto=tcp:toport=8000-8099:toaddr=192.168.1.100'
firewall-cmd --permanent --zone=external --add-masquerade
firewall-cmd --reload8.4 使用富规则进行端口转发
富规则提供更灵活的转发方式:
# 仅转发来自特定来源的流量
firewall-cmd --permanent --zone=external --add-rich-rule='
rule family="ipv4"
source address="203.0.113.0/24"
forward-port port="80" protocol="tcp" to-port="8080" to-addr="192.168.1.10"'
firewall-cmd --reload8.5 查看与删除转发规则
# 查看所有转发规则
firewall-cmd --zone=external --list-forward-ports
# 删除转发规则(语法与添加时一致)
firewall-cmd --permanent --zone=external \
--remove-forward-port='port=8080:proto=tcp:toport=80:toaddr=192.168.1.10'
firewall-cmd --reload9. 直接规则(Direct Rules)
直接规则是 firewalld 的"逃生舱"——当你需要的功能超出了富规则甚至服务/端口规则的表达能力时,可以绕过 firewalld 的抽象层,直接往底层 iptables 或 nftables 写入原生规则。比如自定义链、连接追踪标记(connmark)、复杂的 NAT 逻辑等。代价是你失去了 firewalld 对规则的生命周期管理和冲突检测,需要自行确保不与 firewalld 自带的规则互相干扰。大多数场景用富规则就够了,直接规则应作为最后手段。
直接规则允许你直接操作 iptables / nftables 规则,适合 firewalld 原生功能覆盖不到的场景。
9.1 查看与添加直接规则
# 查看所有直接规则
firewall-cmd --direct --get-all-rules
# 添加一条 iptables raw 表规则(禁用特定 IP 的连接追踪)
firewall-cmd --permanent --direct --add-rule \
ipv4 raw PREROUTING 0 \
-s 192.168.1.100/32 -j NOTRACK
# 添加一条 filter 表规则
firewall-cmd --permanent --direct --add-rule \
ipv4 filter INPUT 0 \
-p tcp --dport 22 -m state --state NEW -m recent --set
firewall-cmd --reload9.2 使用链(Chain)
# 添加自定义链
firewall-cmd --permanent --direct --add-chain ipv4 filter MY_CHAIN
# 向自定义链添加规则
firewall-cmd --permanent --direct --add-rule ipv4 filter MY_CHAIN 0 \
-p tcp --dport 8443 -j ACCEPT
# 将自定义链挂载到 INPUT 链
firewall-cmd --permanent --direct --add-rule ipv4 filter INPUT 10 \
-j MY_CHAIN
firewall-cmd --reload9.3 移除直接规则
firewall-cmd --permanent --direct --remove-rule \
ipv4 raw PREROUTING 0 \
-s 192.168.1.100/32 -j NOTRACK
firewall-cmd --permanent --direct --remove-chain ipv4 filter MY_CHAIN
firewall-cmd --reload注意:直接规则绕过了firewalld的抽象层,需自行确保规则不与firewalld自带规则冲突。
10. IP 集(IPSet)管理
如果只封禁两三个 IP,逐条写富规则没问题;但如果要封禁成百上千个 IP(比如来自威胁情报的恶意 IP 列表),几百条富规则会让规则列表膨胀到不可维护,而且匹配效率低下。IPSet 正是为解决这个问题而生——它像一个"IP 地址容器",你可以把数百个 IP 或网段装进去,然后用一条富规则引用这个容器。底层内核也会对 IPSet 做哈希索引优化,匹配效率远超逐条遍历。配合 fail2ban 等自动化工具,IPSet 是实现动态黑名单的标准方案。
IPSet 可高效管理大量 IP 地址,适合 IP 黑白名单场景。
10.1 创建与管理 IPSet
# 创建一个名为 blacklist 的 IP 集
firewall-cmd --permanent --new-ipset=blacklist --type=hash:ip
# 向 IP 集中添加成员
firewall-cmd --permanent --ipset=blacklist --add-entry=198.51.100.10
firewall-cmd --permanent --ipset=blacklist --add-entry=198.51.100.11
firewall-cmd --permanent --ipset=blacklist --add-entry=203.0.113.0/24
# 查看 IP 集内容
firewall-cmd --permanent --info-ipset=blacklist
firewall-cmd --reload10.2 使用 IPSet 配合富规则
# 使用 IPSet 批量封禁
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source ipset="blacklist"
drop'
firewall-cmd --reload10.3 常见的 IPSet 类型
| 类型 | 说明 | 示例用途 |
|---|---|---|
hash:ip | 单个 IP 地址 | IP 黑白名单 |
hash:net | IP 子网/CIDR | 网段黑白名单 |
hash:ip,port | IP + 端口组合 | 精细访问控制 |
hash:net,port | 子网 + 端口组合 | 区域端口控制 |
10.4 删除 IPSet
firewall-cmd --permanent --ipset=blacklist --remove-entry=198.51.100.10
firewall-cmd --permanent --delete-ipset=blacklist
firewall-cmd --reload11. 辅助与查询命令
除了增删改规则,日常运维中还有大量辅助操作——备份配置、恢复出厂、对比运行时与永久配置差异、提高日志级别排查问题、以及在紧急情况下用 panic-on 一键封死所有入站流量。这些命令虽然不直接涉及规则管理,但在故障排查和灾难恢复时往往是救命稻草。建议:在对防火墙做大改动前,先 cp -a /etc/firewalld 做好备份。
11.1 导出与备份配置
# 备份当前 permanent 配置(整个 firewalld 配置目录)
cp -a /etc/firewalld /etc/firewalld.bak.$(date +%Y%m%d)
# 备份到压缩包
tar czf firewalld-backup-$(date +%Y%m%d).tar.gz -C /etc firewalld/11.2 恢复默认配置
# 恢复到 firewalld 出厂默认配置
\cp -a /usr/lib/firewalld /etc/firewalld
firewall-cmd --reload11.3 查看运行时 vs 永久配置差异
# 方法一:分别查看
echo "=== Runtime ===" && firewall-cmd --list-all
echo "=== Permanent ===" && firewall-cmd --permanent --list-all
# 方法二:将运行时配置同步到永久(相当于让所有临时规则持久化)
firewall-cmd --runtime-to-permanent11.4 查看统计信息
# 查看防火墙统计(需要 firewalld >= 0.6.0)
firewall-cmd --zone=public --get-log-denied11.5 调试模式
# 以更高日志级别运行 firewalld
firewall-cmd --debug=10 # 0-10,越高越详细
# 或直接修改 firewalld 日志级别
vim /etc/firewalld/firewalld.conf
# LogDenied=all
# 重启生效
systemctl restart firewalld11.6 应急开关 —— 紧急关闭防火墙
# 紧急模式:丢弃所有入站流量(除已有连接和 SSH 外)
firewall-cmd --panic-on
# 检查应急模式状态
firewall-cmd --query-panic # yes=开启 / no=未开启
# 关闭应急模式
firewall-cmd --panic-off12. --permanent 与临时规则
这是 firewalld 最容易踩坑的地方。firewalld 维护了两套规则:runtime(当前在内存中生效)和 permanent(存储在 /etc/firewalld/ 的 XML 文件中)。默认不加 --permanent 的操作只影响 runtime——重启或 --reload 后消失;加了 --permanent 的操作写入磁盘,但需要 --reload 才能实际生效。如果你在远程 SSH 操作时改了永久规则但还没 reload 就被踢了,改的规则不会丢;反之,如果你临时加了条规则测试,忘了持久化就 reload,规则就没了。本章的三种工作流覆盖了所有常见操作模式。
12.1 两种规则类型
| 类型 | 存储位置 | 生效时机 | 生命周期 |
|---|---|---|---|
| Runtime(临时) | 内存 | 立即生效 | 服务重启或 --reload 后消失 |
| Permanent(永久) | /etc/firewalld/ | --reload 后生效 | 持久化,重启不丢失 |
12.2 典型工作流
方式一:永久生效(推荐生产环境使用)
# 第一步:写入永久配置
firewall-cmd --permanent --zone=public --add-port=8080/tcp
# 第二步:重载使配置生效(同时也清空了 runtime 临时规则)
firewall-cmd --reload
# 第三步:验证
firewall-cmd --zone=public --list-ports方式二:先临时测试,确认后持久化
# 第一步:临时添加(立即生效,方便测试)
firewall-cmd --zone=public --add-port=8080/tcp
# 第二步:测试服务是否正常
curl -I http://localhost:8080
# 第三步:确认无误后持久化
firewall-cmd --runtime-to-permanent方式三:同时生效(一步到位)
# 同时添加到 runtime 和 permanent
firewall-cmd --permanent --zone=public --add-port=8080/tcp
firewall-cmd --zone=public --add-port=8080/tcp
# 或更简洁的方式:先 permanent,再 reload
firewall-cmd --permanent --zone=public --add-port=8080/tcp
firewall-cmd --reload12.3 注意事项
--reload会丢弃所有仅存在于 runtime 的规则,只保留 permanent 配置。--runtime-to-permanent会将当前所有 runtime 规则写入 permanent 存储。- 部分修改命令(如
--set-default-zone)只修改 permanent 配置,需要显式--reload。 - 添加 permanent 规则时如果忘了
--permanent并执行--reload,刚加的临时规则会丢失。
13. 注意事项
firewalld 不是孤立运行的——它需要与 Docker、Podman、NetworkManager 等组件和平共处。这些组件各自都可能操作底层的 iptables/nftables 规则,稍有不慎就会产生冲突,导致"明明 firewalld 放行了,流量还是过不去"。本章汇总了常见兼容性场景的解决方案,以及 IPv6、日志记录、规则优先级、安全操作顺序等容易被忽视的细节。尤其注意远程操作时要用 at 设置自动回滚,防止把自己锁在服务器外面。
13.1 与 Docker 的兼容性
Docker 默认会直接操作 iptables,可能与 firewalld 产生冲突:
# 方案一:让 Docker 使用 firewalld 管理的 zone
# /etc/docker/daemon.json
{
"iptables": false
}
# 方案二:将 docker0 网桥绑定到 trusted zone
firewall-cmd --permanent --zone=trusted --change-interface=docker0
firewall-cmd --reload
# 方案三:在 firewalld 中为 Docker 所需的端口显式放行
firewall-cmd --permanent --zone=public --add-port=80/tcp
firewall-cmd --permanent --zone=public --add-port=443/tcp
firewall-cmd --reload推荐:不要让 Docker 直接修改 iptables,改用 firewalld 统一管理所有规则。13.2 与 Podman 的兼容性
Podman 与 firewalld 兼容性较好,但仍需注意:
# 安装 podman-plugins 以支持 firewalld
dnf install -y podman-plugins # RHEL 8+
# 确保 CNI 网络使用 firewalld 后端13.3 与 NetworkManager 的交互
NetworkManager 可以与 firewalld 集成,自动根据连接类型切换 zone:
# 查看当前连接
nmcli connection show
# 为某个连接指定 firewalld zone
nmcli connection modify "Wired connection 1" connection.zone external
# 重启连接使其生效
nmcli connection down "Wired connection 1"
nmcli connection up "Wired connection 1"13.4 日志记录配置
默认情况下 firewalld 不记录被拒绝的连接,建议在生产环境开启:
# 编辑 firewalld 配置
# /etc/firewalld/firewalld.conf
# LogDenied=all # all / unicast / broadcast / multicast / off
systemctl restart firewalld
# 查看被拒绝的日志
journalctl -u firewalld -f13.5 IPv6 注意事项
firewalld 支持 IPv4 和 IPv6,但部分规则需分别配置:
# 同时配置 IPv4 和 IPv6 的富规则
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4" service name="http" accept'
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv6" service name="http" accept'
firewall-cmd --reload部分命令(如 --add-service)会同时影响 IPv4 和 IPv6,无需分别操作。
13.7 规则优先级
在 firewalld 中,规则评估顺序如下:
- 直接规则(Direct Rules)—— 最高优先级
- 富规则(Rich Rules)
- 服务/端口规则(Service / Port Rules)
- Zone 的 target(默认策略)
同一类别中,规则按添加顺序依次匹配(先匹配先生效)。
13.8 执行顺序建议
在修改防火墙规则时,始终遵循以下顺序以降低把自己锁在外面的风险:
- 先在测试环境验证,或使用临时规则(不加
--permanent) - 如果是远程操作,使用
at或cron设置回滚任务 - 确认无误后再
--permanent+--reload
# 安全操作 SSH 远程时的回滚方案
at now + 2 minutes << 'EOF'
firewall-cmd --zone=public --remove-service=ssh
EOF
# 现在放心修改规则,如果被锁,2 分钟后自动恢复14. 常见问题排查
防火墙出问题的表现通常一致——"端口不通",但根因千差万别:可能是规则没加对 zone、可能是 --reload 丢了临时规则、可能是 Docker 绕过了 firewalld、可能只是服务根本没监听……本章按"症状 → 排查 → 修复"的结构,把运维中最头疼的几种防火墙故障整理成了标准化排障流程。如果你赶时间,直接跳到 14.7 诊断工具速查 拿命令就走。
14.1 命令行报错
错误 1:FirewallD is not running
# 症状
firewall-cmd --state
# not running
# 排查与修复
systemctl status firewalld
systemctl start firewalld
systemctl enable firewalld错误 2:ALREADY_ENABLED
# 症状:添加规则时报此错误
# 原因:规则已存在于 permanent 配置中
# 解决:先查看已有规则
firewall-cmd --permanent --zone=public --list-all
# 确认后忽略即可,或先移除再添加错误 3:INVALID_ZONE
# 症状:使用了不存在的 zone 名称
# 排查
firewall-cmd --get-zones
# 确保 zone 名称拼写正确错误 4:INVALID_PORT
# 常见错误写法
firewall-cmd --zone=public --add-port=8080 # 缺少协议
firewall-cmd --zone=public --add-port=8080/TCP # 协议必须小写
# 正确写法
firewall-cmd --zone=public --add-port=8080/tcp14.2 规则已添加但服务仍不可达
排查步骤
# 1. 确认规则已生效
firewall-cmd --zone=public --list-all | grep <port-or-service>
# 2. 确认服务是否在监听
ss -tlnp | grep <port>
# 或
netstat -tlnp | grep <port>
# 3. 确认 zone 是否正确
# 检查流量入口网卡所属的 zone
firewall-cmd --get-active-zones
firewall-cmd --get-zone-of-interface=eth0
# 4. 检查 NAT/端口转发是否启用 IP 转发
sysctl net.ipv4.ip_forward
# 5. 检查是否有其他防火墙(如 iptables)也在运行
systemctl status iptables
systemctl status nftables14.3 Docker 容器端口无法访问
# 常见场景:Docker 使用 iptables,绕过 firewalld
# 排查
iptables -L DOCKER -n -v # 查看 Docker 链
firewall-cmd --zone=public --list-all # 对比 firewalld 配置
iptables -L FORWARD -n -v # 检查 FORWARD 链
# 修复:确保 FORWARD 链没有 DROP
firewall-cmd --permanent --zone=public --add-masquerade
firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 \
-i docker0 -o docker0 -j ACCEPT
firewall-cmd --reload14.4 --reload 后规则丢失
# 原因:规则仅添加到了 runtime,未写入 permanent
# 排查
diff <(firewall-cmd --list-all) <(firewall-cmd --permanent --list-all)
# 修复:将 runtime 规则持久化
firewall-cmd --runtime-to-permanent14.5 NAT/端口转发不生效
# 必备检查清单:
# 1. masquerade 是否已启用
firewall-cmd --zone=external --query-masquerade
# 2. IP 转发是否已开启
sysctl net.ipv4.ip_forward
# 如果为 0,执行:
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
# 3. 转发规则是否已正确添加到正确的 zone
firewall-cmd --zone=external --list-forward-ports
# 4. 检查 iptables nat 表
iptables -t nat -L -n -v | grep DNAT
# 5. 确保转发目标可达
ping -c 3 192.168.1.1014.6 富规则语法错误
# 常见错误 1:引号不匹配
# 错误
firewall-cmd --add-rich-rule='rule family="ipv4" source address="1.2.3.4" drop'
# 问题:外层单引号与属性单引号冲突
# 正确:多层引号
firewall-cmd --add-rich-rule='rule family="ipv4" source address="1.2.3.4" drop'
# 通常建议将富规则写在多行(使用换行)以避免引号错误
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4"
source address="1.2.3.4/32"
port port="80" protocol="tcp"
accept'14.7 诊断工具速查
| 命令 | 用途 |
|---|---|
firewall-cmd --list-all-zones | 列出所有 zone 的完整配置 |
firewall-cmd --zone=public --list-all | 查看特定 zone 的全部配置 |
ss -tlnp | 查看所有监听中的 TCP 端口 |
iptables -L -n -v | 查看 iptables 规则(底层) |
nft list ruleset | 查看 nftables 规则(底层,新版) |
journalctl -u firewalld -f | 实时查看 firewalld 日志 |
firewall-cmd --check-config | 检查配置文件语法 |
nc -zv <host> <port> | 测试端口连通性 |
tcpdump -i any port <port> -n | 抓包分析流量 |
附录 A:快速参考卡片
常用操作速查
# === 服务管理 ===
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --remove-service=http
# === 端口管理 ===
firewall-cmd --permanent --zone=public --add-port=8080/tcp
firewall-cmd --permanent --zone=public --remove-port=8080/tcp
# === 富规则 ===
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4" source address="10.0.0.0/8" port port="3306" protocol="tcp" accept'
# === IP 封禁 ===
firewall-cmd --permanent --zone=public --add-rich-rule='
rule family="ipv4" source address="1.2.3.4/32" drop'
# === 端口转发 ===
firewall-cmd --permanent --zone=external \
--add-forward-port='port=80:proto=tcp:toport=8080:toaddr=192.168.1.10'
firewall-cmd --permanent --zone=external --add-masquerade
# === 重载 ===
firewall-cmd --reload
# === 查看 ===
firewall-cmd --list-all
firewall-cmd --zone=public --list-all
firewall-cmd --list-rich-rules
# === 应急 ===
firewall-cmd --panic-on # 紧急封锁
firewall-cmd --panic-off # 解除封锁配置文件路径
| 路径 | 用途 |
|---|---|
/etc/firewalld/firewalld.conf | 主配置文件 |
/etc/firewalld/zones/ | 自定义 zone 配置 |
/usr/lib/firewalld/zones/ | 系统默认 zone 配置 |
/etc/firewalld/services/ | 自定义服务定义 |
/usr/lib/firewalld/services/ | 系统默认服务定义 |
/etc/firewalld/ipsets/ | 自定义 IPSet |
/etc/firewalld/direct.xml | 直接规则配置 |
评论已关闭