这次我们来看 Linux 防火墙的日常管理,重点拆解 ufw 和 firewalld 这两套最常见的工具。防火墙这个主题在 Linux 运维里绕不开:新机器要开放端口、做安全加固、限制外部访问,最后基本都会落到 ufw 或者 firewalld 上。很多人平时只用云厂商安全组,但到了自建机房、内网穿透、本地虚拟机或者容器主机,就必须学会在系统层面直接控制流量。这篇文章会把 ufw 和 firewalld 从安装、启动、规则配置到批量管理完整过一遍,最后给出面试和实战中容易踩的坑。
先给结论:ufw 适合单机、配置简单、追求快速上手,Ubuntu/Debian 默认自带;firewalld 适合多网卡、多区域、需要精细控制信任级别的服务器,RHEL/CentOS/Rocky 系列默认自带。两者底层数据都走 netfilter/iptables,区别在于管理方式和持久化策略。下面我会分别演示两套工具的核心命令,再对比它们的配置模型,这样你换任何一台 Linux 发行版,都能快速找到对应的防火墙开放方法。
1. 核心能力速览
先用一张表格把两套工具的规格和定位对齐:
| 能力项 | ufw | firewalld |
|---|---|---|
| 默认发行版 | Ubuntu / Debian | RHEL / CentOS / Rocky / AlmaLinux |
| 配置模型 | 简单命令规则 | 区域(zone)+ 服务(service)+ 富规则 |
| 启用方式 | ufw enable | systemctl start firewalld |
| 规则持久化 | 默认持久化 | 需要--permanent或--runtime-to-permanent |
| 动态生效 | 添加即生效 | 运行时即时生效,永久配置需 reload |
| 多网卡场景 | 支持较弱 | 原生支持区域绑定 |
| 日志位置 | /var/log/ufw.log | journalctl -u firewalld |
| 适用场景 | 单机、简易安全策略 | 多网卡、多信任级别、企业级服务器 |
从这张表能看出,ufw 把复杂的防火墙逻辑简化成了“允许/拒绝某端口、某 IP”的语义,适合日常快速改规则;firewalld 则把不同网络接口划分到不同区域,比如外网接口用 public,内网接口用 trusted,规则按区域隔离,适合网络拓扑相对固定的服务器。二者不是互斥关系,实际环境中常有 Ubuntu 和 CentOS 混用的情况,所以两套命令都值得掌握。
2. 适用场景与使用边界
先说场景。ufw 最常见的用途是:新装 Ubuntu 云服务器后,打开 SSH、Nginx、MySQL 等端口,再把默认策略改成拒绝入站,这样对外只暴露指定服务。firewalld 最常见的用途是:CentOS 服务器上运行 Web 服务、数据库、内网应用,需要按网卡或来源 IP 做精细放行,或者把整段内网网段标记为可信来源。理解场景之后,再去背命令就顺理成章,不会出现“明明加了规则却不知道它会拦截什么”的困惑。
使用边界这里要特别强调。防火墙只是网络层的第一道防线,它管的是“哪些包能进、哪些包能出”,不负责应用层认证和业务逻辑安全。规则写错会导致两种后果:一种是放行过宽,把数据库、Redis 这类端口直接暴露到公网;另一种是策略过严,把自己 SSH 断掉,只能去云控制台 VNC 恢复。所以这篇博文里的每一条命令,建议先在测试环境验证,再上生产机。
另外,云服务器有一个容易被忽略的层面:系统防火墙和云平台安全组是两层独立控制。如果安全组没放行 8080 端口,即使系统里放行了也不通;反过来,如果系统防火墙没放行,安全组放行了也白搭。排查网络问题时,要同时检查这两个层面,不要只盯着一个方向。
3. 环境准备与前置条件
3.1 系统与权限检查
动手之前先确认当前机器是什么发行版和权限状态。查看系统版本:
cat /etc/os-release确认当前用户是否有 sudo 权限:
sudo -v如果是 Ubuntu/Debian 系,优先使用 ufw;如果是 CentOS/RHEL/Rocky 系,优先使用 firewalld。两者通常随系统默认安装,但也存在精简安装不带的情况,后面会给出对应的安装命令。
前置条件还包括:准备一个测试环境,不要直接在核心业务服务器上做规则实验。本地虚拟机、临时云主机都是很好的选择。测试时建议记录当前时间点已有的监听端口和服务,方便规则变更后对比。
3.2 远程连接安全确认
如果你是远程 SSH 登录操作,必须提前确认 22 端口已经被放行,否则ufw enable或 firewalld 重启后可能直接失联。更稳妥的顺序是:先写放行 SSH 的规则,再启动防火墙服务。
检查当前监听端口:
ss -lntp如果没有 ss 命令,用netstat -tlnp也可以。确认sshd在监听 0.0.0.0:22 或者对应端口后,再做后续操作。
4. 安装部署与服务启动
4.1 ufw 的安装与启用
Ubuntu 一般自带 ufw,如果没有,用 apt 安装:
sudo apt update sudo apt install ufw -y启用前先放行 SSH:
sudo ufw allow 22/tcp然后启用防火墙:
sudo ufw enable启用后查看状态:
sudo ufw status verbose输出里会出现Status: active,以及默认入站、出站策略。默认情况下入站是 deny,出站是 allow。如果看到Status: inactive,说明服务还没启用,需要执行sudo ufw enable。
ufw 的规则默认持久化,不用额外保存。规则存储在/etc/ufw/user.rules,重启后依然生效。这是 ufw 相比 firewalld 更省心的一点,新手不容易丢规则。
4.2 firewalld 的安装与启动
CentOS/Rocky 系统如果没有 firewalld,用 dnf 安装:
sudo dnf install firewalld -y启动并设置开机自启:
sudo systemctl start firewalld sudo systemctl enable firewalld查看运行状态:
systemctl status firewalld firewall-cmd --statefirewall-cmd --state输出 running 表示服务运行中。默认区域一般是 public,可以通过firewall-cmd --get-default-zone确认。
firewalld 的持久化和 ufw 不一样:直接执行--add-port只对当前运行生效,重启后会丢失。需要加上--permanent参数,或在确认规则无误后执行--runtime-to-permanent改为永久规则。这个区别是面试高频考点,也是自己踩坑最多次的地方。
5. 功能测试与效果验证
5.1 ufw 端口放行与应用配置
测试场景:放行 Web 服务的 80/443 端口。
sudo ufw allow 80/tcp sudo ufw allow 443/tcp查看当前规则:
sudo ufw status numbered撤销规则可以用编号或完整规则:
sudo ufw delete allow 80/tcpufw 还支持应用配置文件方式,查看当前系统可用应用:
sudo ufw app list在 Ubuntu 上通常会看到 OpenSSH,可以直接放行:
sudo ufw allow 'OpenSSH'这种方式的好处是不用自己去记端口号,应用配置会定义好协议和端口,适合系统自带的服务。
验证方式:从另一台机器访问http://IP,或者在本机执行:
curl -I http://127.0.0.1如果 curl 通,说明端口在监听;如果 curl 不通但端口已放行,问题通常在服务本身,防火墙只是背锅了。
5.2 firewalld 端口放行与服务配置
同样场景,用 firewalld 放行 80/443:
sudo firewall-cmd --permanent --zone=public --add-port=80/tcp sudo firewall-cmd --permanent --zone=public --add-port=443/tcp sudo firewall-cmd --reload查看区域规则:
sudo firewall-cmd --zone=public --list-all删除规则:
sudo firewall-cmd --permanent --zone=public --remove-port=80/tcp sudo firewall-cmd --reloadfirewalld 也支持按服务名放行,比如 HTTP 服务:
sudo firewall-cmd --permanent --zone=public --add-service=http sudo firewall-cmd --reload服务名对应的定义在/usr/lib/firewalld/services/下的 XML 文件里,一个服务可以包含多个端口和协议。比起逐条加端口,直接放行业务使用的服务名更直观,也更方便统一管理。
这里的--reload会把永久配置重新加载,让改动生效。注意--reload不会中断当前已有连接,但会重新应用全部规则,所以生产环境变更时也要选择低峰期。
5.3 IP 黑白名单配置
这是关键词“防火墙黑白名单”对应的核心部分。ufw 封禁某个来源 IP:
sudo ufw deny from 203.0.113.55ufw 放行特定 IP 访问本机任意端口:
sudo ufw allow from 192.168.1.100只放行特定 IP 的 SSH:
sudo ufw allow from 192.168.1.100 to any port 22 proto tcpfirewalld 封禁来源 IP,用富规则更精确:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="203.0.113.55" drop' sudo firewall-cmd --reloadfirewalld 信任某个来源 IP:
sudo firewall-cmd --permanent --zone=trusted --add-source=192.168.1.100 sudo firewall-cmd --reload黑名单与白名单的核心逻辑是:黑名单是“默认放行,指定来源拒绝”,白名单是“默认拒绝,指定来源放行”。ufw 默认入站拒绝时,allow from就是白名单思路;firewalld 里把来源加入 trusted 区域也是白名单思路。生产环境建议先拒绝全部入站,再按业务需要逐个放行,规则越少越容易审计。
验证黑白名单是否生效,可以在被封禁的 IP 上尝试连接目标主机,观察是否超时或收到拒绝;或者在目标主机上用ufw status和firewall-cmd --list-all确认规则确实存在。更严谨的做法是查看防火墙日志,ufw 的日志在/var/log/ufw.log,firewalld 的日志在journalctl -u firewalld中。
5.4 firewalld 区域与富规则
firewalld 的 zone 设计是它和 ufw 最大的差异。默认区域有 drop(丢弃)、block(拒绝)、public(公共)、external(外部)、internal(内部)、trusted(信任)。一个网卡同时只能属于一个区域,区域决定该网卡上流量默认放行还是拒绝。
查看网卡和区域绑定:
sudo firewall-cmd --get-active-zones把 eth1 绑定到 internal:
sudo firewall-cmd --permanent --zone=internal --add-interface=eth1 sudo firewall-cmd --reload如果需要在指定网段访问指定端口,可以用富规则同时限制来源和端口:
sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port port="3306" protocol="tcp" accept' sudo firewall-cmd --reload这条规则的实际含义是:允许 192.168.1.0/24 网段访问本机 3306 端口。相比直接把 3306 暴露给所有来源,这样安全得多。富规则能覆盖绝大多数复杂的 ACL 需求,而且语法本身不复杂,掌握来源地址、端口、协议、动作这几个关键字就够了。
6. 批量管理与自动化集成
6.1 批量封禁 IP 的脚本化实现
运维中经常出现恶意 IP 列表,需要批量加进防火墙。ufw 用 shell 循环:
#!/bin/bash for ip in 203.0.113.10 198.51.100.20 192.0.2.30; do sudo ufw deny from "$ip" donefirewalld 批量添加富规则:
#!/bin/bash for ip in 203.0.113.10 198.51.100.20 192.0.2.30; do sudo firewall-cmd --permanent --add-rich-rule="rule family=ipv4 source address=${ip} drop" done sudo firewall-cmd --reload批量操作最容易踩的坑:一是 firewalld 批量后忘记 reload,导致规则只在内存里、重启丢失;二是脚本中途报错导致部分 IP 没加成功。稳妥的做法是把待封禁 IP 放到独立的文本文件,脚本执行后打印日志,最后统一 reload 并核对规则数量。
6.2 从文件读取 IP 批量添加
准备blocked_ips.txt,每行一个 IP,然后:
while read -r ip; do [ -z "$ip" ] && continue sudo ufw deny from "$ip" done < blocked_ips.txtfirewalld 版本同理,把循环里的命令替换成firewall-cmd --permanent --add-rich-rule即可。这类脚本建议加入执行日志:
echo "$(date '+%F %T') blocked $ip" >> /var/log/firewall_block.log有日志才能在出问题时回溯到某条规则是否真正添加成功。批量场景下,规则变更的审计比规则本身更重要。
6.3 配置管理与自动化编排
ufw 和 firewalld 的规则本质上都是文本配置。ufw 的规则文件在/etc/ufw/user.rules,firewalld 的区域配置在/etc/firewalld/zones/public.xml等文件。生产环境可以把这些目录纳入 Git 管理,规则变更先走 review 再应用。
如果需要接入自动化编排,firewalld 支持 D-Bus 接口,适合配置管理工具对接。比如用 Ansible 管理端口规则:
- name: 放行 8080 端口 ansible.posix.firewalld: port: 8080/tcp permanent: true immediate: true state: enabled这种方式的好处是规则状态可声明、可回溯、可快速回滚。对于几百台机器来说,手动逐台执行firewall-cmd并不现实,配置管理工具是更可靠的方向。
7. 资源占用与性能观察
ufw 和 firewalld 本身是用户态配置工具,数据包的实际过滤由内核 netfilter 完成。规则加得再多,只要服务正常,CPU 占用通常都很低。真正需要关注的是连接跟踪表(conntrack)和高并发下的规则匹配效率。
查看连接跟踪表占用:
cat /proc/net/nf_conntrack | wc -l查看最大连接跟踪数:
sysctl net.netfilter.nf_conntrack_max如果连接数逼近上限,会出现“连接建立很慢”“部分请求超时”的现象。此时可以临时调大上限:
sudo sysctl -w net.netfilter.nf_conntrack_max=65535持久化可以写入/etc/sysctl.conf,但要注意不同内核版本和内存大小的默认值不一样,调参需要结合本机实际负载,不要盲目设置大值。
性能观察的另一个重点是 DROP 和 REJECT 的区别。DROP 不返回任何信息,客户端表现为连接超时;REJECT 给客户端返回拒绝原因,比如icmp-port-unreachable。从资源角度看,DROP 会让客户端等待更久;从信息暴露角度看,REJECT 会告诉扫描者端口存在或路由可达。不同场景选不同策略,内网可以多用 REJECT,公网建议 DROP,能减少暴露面。
8. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
ufw enable后 SSH 断开 | 未放行 22 端口 | 登录云控制台 VNC | 先执行ufw allow 22/tcp |
| firewalld 重启后规则丢失 | 加规则时没用--permanent | 查看/etc/firewalld/zones/ | 用--runtime-to-permanent后 reload |
| 端口已放行但访问不通 | 服务未监听或安全组未放行 | ss -lntp | 检查服务进程和云安全组 |
| 封禁 IP 未生效 | 规则顺序排在放行规则后面 | iptables -L -n | 用富规则 drop,保证优先级 |
| firewalld 与 iptables 规则冲突 | 同时使用两套管理工具 | 检查服务列表 | 统一从 firewalld 管理 |
| reload 后业务中断 | 持久配置里包含错误规则 | 查看 journalctl 日志 | 修正 XML 后重载 |
| 规则数量巨大导致操作卡顿 | 脚本重复添加未去重 | 查看规则文件 | 用--remove-清理重复项 |
除了表里的问题,最常见的还是“云服务器端口怎么都不通”。这时候按顺序排查:先ss -lntp确认服务监听,再ufw status或firewall-cmd --list-all确认防火墙放行,最后到云控制台单独放行该端口。排查顺序不要乱,一层层排除,很快能定位。
这里也补充一个面试常考问题:防火墙里 DROP 和 REJECT 有什么区别,生产环境选哪个。答案是 DROP 直接丢包,看起来像超时;REJECT 返回拒绝信息,能更快感知端口状态。公网建议 DROP,减少暴露;内网可以用 REJECT,便于调试。
9. 最佳实践与使用建议
第一,新装服务器的防火墙策略应该是“默认拒绝入站,按需放行”。ufw 可以这样设置:
sudo ufw default deny incoming sudo ufw default allow outgoingfirewalld 把默认区域改成 drop 可以间接实现同样的效果:
sudo firewall-cmd --set-default-zone=drop sudo systemctl restart fire