Linux 防火墙
Linux 防火墙
目录
- 软件包安装
- 防火墙基本概念:firewalld 与 iptables
- 区域(zone)概念:理解放行/拒绝的前提
- firewall-cmd 常用操作:开放/关闭端口,临时 vs 永久
- Ubuntu 系统的防火墙:UFW
- 踩坑排查:开放端口却连不上
- 常见问题排查清单
- 总结与对比
- 参考资料
软件包安装
Rocky/RHEL 默认安装了 firewalld(Minimal 安装也可能自带);Ubuntu/Debian 默认安装的是 ufw。若未安装,按下面方法安装并启动。
Rocky / RHEL / CentOS:firewalld
# 安装 firewalld
sudo dnf install -y firewalld
# 启动并设置开机自启
sudo systemctl enable --now firewalld
# 查看状态
sudo systemctl status firewalld
firewall-cmd --state # 输出 running / not running
firewalld 自带基于 nftables 的过滤,无需再单独启用 iptables 服务。
Ubuntu / Debian:UFW
# UFW 通常已安装;若没有
sudo apt install -y ufw
其他工具(可选)
# 在 RHEL 系上也可安装 iptables 命令行工具(一般无需)
sudo dnf install -y iptables
# 在 Ubuntu 上也可安装 firewalld(与 ufw 二选一,别同时乱配)
sudo apt install -y firewalld
建议:RHEL 系用 firewalld,Ubuntu 用 UFW,不要在同一个系统上同时启用两套防火墙管理工具,以免规则互相覆盖、难以排查。
一、防火墙基本概念:firewalld 与 iptables
1.1 它们到底在管什么
Linux 内核里真正做数据包过滤的是 netfilter 框架。iptables 和 firewalld 都是"往 netfilter 里写规则"的工具,只是管理方式不同。
| 工具 | 定位 | 特点 |
|---|---|---|
iptables |
直接面向内核 netfilter 的命令行工具 | 基于表(table)→ 链(chain)→ 规则(rule),每改一条规则都要手动执行命令,规则是静态的 |
firewalld |
一个守护进程 + D-Bus 服务,是更高层的管理框架 | 基于区域(zone)和服务(service)抽象,规则可动态生效、可运行时/永久保存,改动不丢已建立的连接 |
- iptables 是"底层、静态、手写规则"。
- firewalld 是"上层、动态、按区域管理"。RHEL 7/8/9 和 Rocky Linux 默认用 firewalld,且 RHEL 8/9 的 firewalld 底层已改用 nftables 作为后端(不再是老式 iptables 命令)。
1.2 为什么有了 iptables 还要 firewalld
- iptables 改一条规则就是一条命令,规则多、杂时难以管理和维护;重启后规则默认不会自动保存(需要手动
iptables-save)。 - firewalld 提供区域和预定义服务(如
http、ssh),用一条命令就能放行某个服务;规则可以持久化(--permanent),改动即时生效且不中断现有连接(通过--reload热加载)。
1.3 相关命令/文件
| 命令 / 文件 | 作用 |
|---|---|
firewall-cmd |
firewalld 的命令行客户端 |
firewalld |
firewalld 守护进程(服务名) |
/etc/firewalld/ |
系统自定义配置目录(优先于内置默认) |
/usr/lib/firewalld/ |
内置默认配置目录 |
iptables、nft |
底层过滤工具(firewalld 后台调用) |
参考:Red Hat - Using and configuring firewalld(RHEL 8)
二、区域(zone)概念:理解放行/拒绝的前提
2.1 什么是 zone
区域(zone) 是一组命名好的信任等级与规则集合,firewalld 把每个网络接口(或来源 IP)归属到某个区域。规则是挂在区域上的,而不是挂在接口上。理解这一点是放行/拒绝的前提:
- 一个接口(如
ens160)属于某个区域; - 要放行某个端口,必须把规则加在该接口所在的那个区域上,否则不生效;
- 没显式归属的接口会落到默认区域(default zone)。
2.2 查看区域
# 查看默认区域(RHEL/Rocky 通常是 public)
firewall-cmd --get-default-zone
# 查看当前"有接口/来源绑定"的活动区域
firewall-cmd --get-active-zones
# 列出所有可用区域
firewall-cmd --get-zones
# 查看某个接口属于哪个区域
firewall-cmd --get-zone-of-interface=ens160
2.3 预定义区域(9 个)与信任等级
firewalld 自带 9 个预定义区域,从最严格到最宽松:
| 区域 | 目标(target) | 说明 |
|---|---|---|
drop |
DROP | 丢弃所有入站包,不回复(对方无法感知主机存在) |
block |
REJECT | 拒绝所有入站,但回 ICMP(主机禁止) |
public |
REJECT | 默认区域,拒绝其他入站,信任度低,适合公共网络 |
external |
REJECT | 外网区域,启用 masquerade(NAT 伪装),适合网关 |
dmz |
REJECT | 隔离区,只放行选定服务 |
work |
REJECT | 工作网络,信任度较高 |
home |
REJECT | 家庭网络,信任度较高 |
internal |
REJECT | 内部网络,信任度较高 |
trusted |
ACCEPT | 接受所有入站,最宽松,仅用于完全可信环境 |
- target 决定"未明确放行的入站流量"怎么处理:
ACCEPT全放、REJECT拒绝并回 ICMP、DROP直接丢弃。 - 每个区域里再通过
--add-port/--add-service单独放行特定端口/服务。 - 对默认区域 public 来说:默认拒绝其他入站,只放行显式允许的端口/服务。
2.4 修改接口所属区域(一般不推荐直接改,了解即可)
# 把接口 ens160 移到 home 区域
sudo firewall-cmd --zone=home --change-interface=ens160
# 永久生效
sudo firewall-cmd --permanent --zone=home --change-interface=ens160
sudo firewall-cmd --reload
大多数场景不需要换区域,直接在默认区域 public 里加规则即可。
参考:firewalld.org - Predefined Zones、Default Zone
三、firewall-cmd 常用操作:开放/关闭端口,临时 vs 永久
3.1 临时(runtime)与永久(permanent)
这是 firewall-cmd 最容易踩的坑,务必先理解:
| 类型 | 命令 | 生效时机 | 持久性 |
|---|---|---|---|
| 临时(runtime) | 不带 --permanent |
立即生效 | 重启 firewalld 或重启机器后丢失 |
| 永久(permanent) | 带 --permanent |
写入配置文件,需要 --reload 才应用到运行中 |
重启后保留 |
- 临时规则:改完立刻生效,适合临时调试,重启即失效。
- 永久规则:写进
/etc/firewalld/,但不会立即生效,需要--reload(或重启 firewalld)才会作用到当前运行配置。
参考:firewalld.org - Runtime versus Permanent
3.2 开放端口
# 临时放行 8080/tcp(立即生效,重启丢失)
sudo firewall-cmd --add-port=8080/tcp
# 永久放行 8080/tcp(写入配置,需 reload 生效)
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
# 指定区域放行(默认加在 --get-default-zone 所在区域)
sudo firewall-cmd --zone=public --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
- 端口要写
端口/协议,如8080/tcp、53/udp。 - 协议必须对:TCP 服务放
/tcp,UDP 服务放/udp,写错协议照样连不上。
3.3 放行服务(service)
firewalld 内置很多预定义服务(如 http、https、ssh),一条命令即可:
# 永久放行 http 服务(对应 80/tcp)
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --reload
# 查看所有可用服务
firewall-cmd --get-services
# 查看服务对应的端口
firewall-cmd --permanent --service=http --get-ports
3.4 查看、查询、关闭
# 查看默认区域放行内容(端口、服务、源等)
firewall-cmd --list-all
# 查看某区域的完整规则
firewall-cmd --zone=public --list-all
# 查询某个端口是否已放行
firewall-cmd --query-port=8080/tcp
# 移除端口(临时/永久,与添加对应)
sudo firewall-cmd --remove-port=8080/tcp
sudo firewall-cmd --permanent --remove-port=8080/tcp
sudo firewall-cmd --reload
3.5 把临时规则固化为永久
想把已经在跑的一堆临时规则保存下来:
# 把当前所有运行时规则复制为永久规则
sudo firewall-cmd --runtime-to-permanent
3.6 reload 与 complete-reload 的区别
sudo firewall-cmd --reload # 保留运行时规则,重新加载永久配置(热加载,不中断连接)
sudo firewall-cmd --complete-reload # 丢弃运行时规则,完全按配置文件重建(可能中断)
- 通常用
--reload即可。 - 改完永久配置后忘了
--reload,是"开放端口却连不上"的高频原因之一。
参考:firewalld.org - Reload firewalld
四、Ubuntu 系统的防火墙:UFW
Ubuntu/Debian 默认的防火墙管理工具是 UFW(Uncomplicated Firewall),它是对 iptables/nftables 的简单封装,底层仍是 netfilter。
4.1 启用与查看状态
sudo ufw enable # 启用(会提示确认)
sudo ufw status # 查看状态与规则
sudo ufw status verbose # 详细(含默认策略)
- UFW 默认策略是 默认拒绝入站(deny incoming)、默认允许出站(allow outgoing)——即默认拒绝外部访问,但本机可以自由对外访问。
4.2 放行与关闭端口/服务
# 放行某端口
sudo ufw allow 22/tcp
sudo ufw allow 8080
# 放行服务名
sudo ufw allow ssh
sudo ufw allow http
# 允许特定来源 IP 访问某端口
sudo ufw allow from 192.168.1.0/24 to any port 3306
# 删除规则(按编号或按规则内容)
sudo ufw status numbered # 先列出编号
sudo ufw delete 3 # 删除编号 3 的规则
sudo ufw delete allow 22/tcp # 按内容删除
4.3 重置
sudo ufw reset # 清空所有规则(慎用)
4.4 注意事项
- 先放行 SSH 再启用 UFW,否则可能把自己锁在外面(
sudo ufw allow ssh或22/tcp先做)。 - UFW 规则也是写进
/etc/ufw/配置文件,ufw命令改完即生效并持久保存,不需要额外 reload。
参考:Ubuntu - Firewall(官方文档)、ufw man 手册
五、踩坑排查:开放端口却连不上
这是运维中最常见的场景:明明 --add-port 放行了,外面还是连不上。 下面按"从内到外"的顺序排查。
5.1 排查清单(按顺序走一遍)
① 服务真的在监听吗?监听的地址和端口对不对?
ss -tlnp # 查看 TCP 监听端口
ss -ulnp # 查看 UDP 监听端口
- 看服务是不是根本没起来,或监听在别的端口。
- 看是不是只监听了 127.0.0.1(本机回环),那样外部永远连不上——应监听
0.0.0.0或具体网卡 IP。 - 应用本身如果没起来,防火墙放不放行都没用。
② 防火墙规则是临时还是永久?永久规则 reload 了吗?
firewall-cmd --query-port=8080/tcp # 运行中是否真的放行了
firewall-cmd --list-all # 看当前生效内容
- 只加了
--permanent --add-port却没--reload,运行中并没有放行(规则只在配置文件里)。 - 只加了临时规则(没
--permanent),重启后丢失,表现为"之前能连、重启后连不上"。
③ 规则加对区域了吗?接口在哪个区域?
firewall-cmd --get-active-zones
firewall-cmd --get-zone-of-interface=ens160
- 规则要加在接口实际所属的区域。如果接口在
public,你把端口加到了home,就不生效。 - 确认默认区域:
firewall-cmd --get-default-zone。
④ 协议对不对?TCP 还是 UDP?
- 服务是 TCP 就放
8080/tcp,是 UDP 就放8080/udp,别混。
⑤ 是 SELinux 在拦吗?(RHEL/Rocky 特有)
getenforce # Enforcing / Permissive / Disabled
sudo ausearch -m avc -ts recent # 查看被拒绝记录
- RHEL/Rocky 默认启用 SELinux,即使防火墙放行,SELinux 也可能拦截非标准端口的服务。
- 若确认是 SELinux 拦,可用
sudo semanage port -a -t http_port_t -p tcp 8080放行该端口(需安装policycoreutils-python-utils)。
⑥ 是不是云平台/外部防火墙在拦?
- 阿里云/腾讯云/AWS 等安全组是云平台层面的独立防火墙,即使操作系统放行了,安全组没放行一样连不上。去云控制台检查安全组/网络安全组。
⑦ 本机先自测连通性
curl http://127.0.0.1:8080 # 本机测
ss -tlnp | grep 8080 # 确认在监听
- 本机能通、外部不通,多半是防火墙/安全组/SELinux;本机也不通,多半是服务本身没起来或监听地址不对。
5.2 一个完整的排查例子
假设要对外放行 8080 端口的 Web 服务:
# 1. 确认服务在监听且监听地址正确
ss -tlnp | grep 8080 # 期望看到 0.0.0.0:8080 或具体网卡 IP:8080
# 2. 永久放行并 reload
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
# 3. 确认运行中已生效
firewall-cmd --query-port=8080/tcp # 期望输出 yes
# 4. 本机测通
curl http://127.0.0.1:8080
# 5. 若本机通而外部不通:查 SELinux、云安全组、接口所属区域
getenforce
firewall-cmd --get-active-zones
排查思路:先服务后防火墙,先本机后外网,先运行时后永久,先系统后云平台。 按这个顺序,绝大多数"放行了却连不上"都能定位。
六、常见问题排查清单
- 放行了还是连不上 → 先看服务是否监听、监听地址是否正确(
ss -tlnp)。 - 永久规则没生效 → 加了
--permanent后忘记--reload。 - 重启后规则丢了 → 加的是临时规则,改用
--permanent。 - 规则加错区域 → 用
--get-active-zones/--get-zone-of-interface核对接口所在区域。 - TCP/UDP 写错 → 服务是 TCP 放
/tcp,UDP 放/udp。 - SELinux 拦截(RHEL 系)→
getenforce、ausearch -m avc、必要时semanage port。 - 云安全组没放行 → 操作系统防火墙之外,还要在云控制台安全组放行。
- Ubuntu 连不上 → 检查
sudo ufw status是否已ufw allow;确认先放行了 SSH 再 enable。
七、总结与对比
7.1 firewalld / UFW / iptables 速查
| 需求 | firewalld(RHEL/Rocky) | UFW(Ubuntu) |
|---|---|---|
| 查看状态 | firewall-cmd --state |
sudo ufw status |
| 放行端口(临时) | firewall-cmd --add-port=8080/tcp |
(UFW 直接持久生效) |
| 放行端口(永久) | firewall-cmd --permanent --add-port=8080/tcp; firewall-cmd --reload |
sudo ufw allow 8080/tcp |
| 删除 | --remove-port=8080/tcp |
sudo ufw delete allow 8080/tcp |
| 放行服务 | --add-service=http |
sudo ufw allow http |
| 查看当前放行 | --list-all |
sudo ufw status |
7.2 工具选择
| 场景 | 工具 |
|---|---|
| RHEL/Rocky/CentOS 服务器 | firewalld(默认、动态、区域化管理) |
| Ubuntu/Debian 服务器 | UFW(默认、简单) |
| 需要底层精细规则、脚本化 | iptables / nftables(底层,手工管理) |
| 现代 RHEL 8/9 底层 | firewalld 已基于 nftables |
7.3 动手练习建议
# 1. RHEL/Rocky:放行一个端口并验证
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
firewall-cmd --query-port=8080/tcp
firewall-cmd --list-all
# 2. 体验临时 vs 永久
sudo firewall-cmd --add-port=9090/tcp # 临时
firewall-cmd --query-port=9090/tcp # yes
sudo systemctl restart firewalld # 重启后
firewall-cmd --query-port=9090/tcp # no(临时规则丢失)
# 3. Ubuntu:先放行 SSH 再启用
sudo ufw allow ssh
sudo ufw enable
sudo ufw status
提示:练习在虚拟机进行。改防火墙前先确认放行了 SSH,避免把自己锁在机器外;云服务器还要同步检查安全组。
参考资料
- firewalld.org - Predefined Zones:https://firewalld.org/documentation/zone/predefined-zones.html
- firewalld.org - Default Zone:https://firewalld.org/documentation/zone/default-zone
- firewalld.org - Runtime versus Permanent:https://firewalld.org/documentation/configuration/runtime-versus-permanent.html
- firewalld.org - Reload firewalld:https://firewalld.org/documentation/howto/reload-firewalld
- Red Hat - Using and configuring firewalld(RHEL 8):https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/8/html/configuring_and_managing_networking/using-and-configuring-firewalld_configuring-and-managing-networking
- Ubuntu - Firewall(官方文档):https://ubuntu.com/server/docs/how-to/security/firewalls
- Ubuntu - ufw man 手册:https://manpages.ubuntu.com/manpages/focal/en/man8/ufw.8.html
- 菜鸟教程 - Linux 教程:https://www.runoob.com/linux/linux-tutorial.html