防火墙是服务器上最基础也最容易出事的一层:配对了没人注意到它的存在,配错了立刻失联。尤其是远程配置云服务器时,一条 policy drop 就可能把自己挡在门外,然后只能靠控制台的 VNC 救场。
这篇文章从 nftables 的基础概念讲起,给出真实可用的命令和持久化方法,说明 nftables 与 firewalld、ufw 的关系,重点讲"放行 SSH 前先放行自己"的风险控制和回滚手段;然后讲 Windows 侧 Defender 防火墙的入站规则配置,包括按程序还是按端口、以及如何限制来源 IP。
nftables 取代 iptables 的背景
iptables 从 2001 年起就是 Linux 防火墙的事实标准,但它有几个结构性问题:IPv4、IPv6、ARP、桥接分别要用 iptables、ip6tables、arptables、ebtables 四套工具和四套规则,配置重复且容易不一致;规则语法不统一,添加、插入、删除的写法各不相同;规则集是线性的,规模大时匹配性能下降明显。
nftables 从 Linux 内核 3.13 开始合入主线,设计目标就是解决这些问题:
- 用统一的
inet地址族同时处理 IPv4 和 IPv6,一套规则覆盖双栈。 - 语法统一,规则用表达式描述,可读性和可维护性更好。
- 引入集合(set)与映射(map),几千个 IP 的黑名单用一条规则加一个集合搞定,匹配复杂度接近常数。
- 内核态提供原子提交,规则集要么整体生效要么整体不生效,不会出现更新到一半的中间状态。
- 规则集可以用文件描述,便于版本管理和批量下发。
目前主流发行版的现状是:RHEL 8 及以后、Debian 10 及以后、Ubuntu 20.04 及以后都默认使用 nftables 作为后端。需要注意的是,很多系统上 iptables 命令仍然存在,但它实际上是一个兼容层,真正生效的后端是 nftables。用 iptables -L 和 nft list ruleset 对比一下就清楚了:
sudo nft list ruleset | head -40
sudo iptables -L -n -v # 可能显示为空或由 nft 转换而来
不要混用 iptables 和 nft 命令管理同一套规则,两套工具操作的是同一个内核子系统,混用会造成规则相互覆盖、行为难以预测。选定一套坚持用。
表、链、规则三个概念
nftables 的结构是三层嵌套,理解它就理解了一大半:
表(table)是规则的容器,同时指定地址族(family)。地址族决定这个表能处理什么流量:
| 地址族 | 处理的协议 | 常用场景 |
|---|---|---|
| ip | IPv4 | 只管 IPv4 |
| ip6 | IPv6 | 只管 IPv6 |
| inet | IPv4 + IPv6 | 推荐,一套规则管双栈 |
| arp | ARP | 特殊场景 |
| bridge | 桥接二层 | 虚拟化、容器网络 |
| netdev | 网卡入口 | 早期过滤,高性能场景 |
链(chain)挂在表下面,分两类:
基础链(base chain)挂接到内核的某个钩子点(hook),真正接收流量。常用钩子有 input(发往本机)、forward(转发)、output(本机发出)、prerouting、postrouting。创建基础链时必须指定 type、hook、priority 和 policy。
常规链(regular chain)不挂接钩子,只能被 jump 调用,用于把规则分组,类似函数。
规则(rule)是链里的具体判断,由匹配表达式和动作组成。匹配部分如 tcp dport 22、ip saddr 192.168.1.0/24、ct state established;动作部分如 accept、drop、reject、log、counter。
数据流经的顺序是:包进入网卡 → prerouting → 路由判断 → input(发往本机)或 forward(转发)→ 本机进程 → output → postrouting → 出去。规则在链内按顺序匹配,命中即执行动作并停止,所以顺序很重要。
nft 基本命令
先看现状和地址族支持:
sudo nft list ruleset # 查看全部规则集
sudo nft list tables # 列出所有表
sudo nft list table inet filter # 查看指定表
创建一个表、一条基础链和几条规则:
# 创建 inet 族的表(同时管 IPv4 和 IPv6)
sudo nft add table inet filter
# 创建 input 基础链,默认策略 accept
sudo nft add chain inet filter input '{ type filter hook input priority 0; policy accept; }'
# 允许已建立的连接和相关连接(这条通常要放在前面)
sudo nft add rule inet filter input ct state established,related accept
# 允许回环接口
sudo nft add rule inet filter input iif lo accept
# 允许 SSH(端口按实际修改)
sudo nft add rule inet filter input tcp dport 22 ct state new accept
# 允许 HTTP/HTTPS
sudo nft add rule inet filter input tcp dport { 80, 443 } ct state new accept
# 允许 ICMP(便于排障,可按需限制类型)
sudo nft add rule inet filter input ip protocol icmp icmp type echo-request accept
# 记录并丢弃其余未匹配流量
sudo nft add rule inet filter input log prefix 'nft-drop: ' counter drop
几个容易踩的语法细节:
shell 转义。 规则里有大括号、分号、空格,在 bash 里会被解释。用单引号把整段规则包起来是最省事的做法。上面的 add chain 语句必须加引号,否则报语法错误。
ct state established,related 这一条非常重要。 没有它,本机主动发起的连接(比如 apt 更新、curl 外网)的返回包会被 input 链挡掉,表现为"能 ping 通但 apt 卡住"。加上它等于实现了有状态防火墙。
inet 表里的 ICMP 写法要用 ip protocol icmp 或 meta nfproto ipv4,因为 IPv6 的 ICMP 是另一个协议号。
查看规则带句柄(handle),删除和插入都要用到:
sudo nft -a list chain inet filter input # -a 显示 handle 号
sudo nft delete rule inet filter input handle 12
sudo nft insert rule inet filter input index 0 ct state established,related accept
sudo nft add rule inet filter input index 2 tcp dport 8080 accept
add 是追加到末尾(或指定 index 之后),insert 是插入到开头(或指定 index 之前)。想让新规则先生效就用 insert。
使用集合管理 IP 列表,这是 nftables 相对 iptables 最大的优势:
# 命名集合,interval 支持网段
sudo nft add set inet filter ssh_allow '{ type ipv4_addr; flags interval; }'
sudo nft add element inet filter ssh_allow '{ 203.0.113.10, 198.51.100.0/24 }'
sudo nft add rule inet filter input tcp dport 22 ip saddr @ssh_allow accept
sudo nft list set inet filter ssh_allow
# 匿名集合,直接在规则里写
sudo nft add rule inet filter input tcp dport { 80, 443, 8080 } accept
集合里的元素可以动态增删,不需要重建规则,几千上万个 IP 的匹配性能远好于等长的线性规则链。
临时调试与清空:
sudo nft monitor # 实时观察规则匹配情况,排障利器
sudo nft flush chain inet filter input # 清空某条链的规则
sudo nft flush table inet filter # 清空某张表
sudo nft flush ruleset # 清空全部规则集(危险,等于全放行)
持久化配置
用 nft 命令加的规则在内存中,重启就没了,必须持久化。
主流发行版的做法是导出到 /etc/nftables.conf,然后启用 nftables 服务:
# 导出当前规则集(会覆盖已有文件,先备份)
sudo cp /etc/nftables.conf /etc/nftables.conf.bak 2>/dev/null
sudo nft list ruleset > /etc/nftables.conf
# RHEL、Rocky、CentOS
sudo systemctl enable --now nftables
sudo systemctl restart nftables
# Debian、Ubuntu
sudo systemctl enable --now nftables
sudo systemctl status nftables
Debian、Ubuntu 的 /etc/nftables.conf 通常自带一个基础模板,第一行是 #!/usr/sbin/nft -f,内容是完整的规则集声明格式(用 table ip filter { ... } 这样的块结构,而不是一条条 add)。推荐直接编辑这个文件的块结构写法,可读性更好:
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
set ssh_allow {
type ipv4_addr
flags interval
elements = { 203.0.113.10, 198.51.100.0/24 }
}
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif lo accept
tcp dport 22 ip saddr @ssh_allow accept
tcp dport { 80, 443 } accept
ip protocol icmp icmp type echo-request accept
log prefix "nft-drop: " counter drop
}
chain forward {
type filter hook forward priority 0; policy drop;
}
chain output {
type filter hook output priority 0; policy accept;
}
}
文件开头的 flush ruleset 表示每次加载时清空旧规则再重建,好处是配置幂等,不会出现重复规则堆积;风险是如果文件有语法错误,nftables 服务启动失败,此时规则集可能是空的状态(具体行为取决于服务配置)。所以修改这个文件前先备份,改完先做语法检查:
sudo nft -c -f /etc/nftables.conf # -c 只检查不加载
风险提示:永远不要直接 systemctl restart nftables 而不先 nft -c -f 检查。语法错误会导致规则加载失败,如果此时默认策略又没生效,你可能会在毫无察觉的情况下失去访问控制,也可能把自己关在门外。
与 firewalld、ufw 的关系
这一点很多人搞不清楚:firewalld 和 ufw 都不是独立的防火墙,它们是 nftables(或 iptables)的前端管理工具。关系类似于 apt 和 dpkg:底层是同一个内核子系统,上层是不同的操作界面。
| 工具 | 定位 | 默认发行版 | 适合场景 |
|---|---|---|---|
| nft | 直接操作 nftables | 全部 | 需要精细控制、批量规则、高性能场景 |
| firewalld | 前端,zone 模型 | RHEL、Rocky、CentOS | RHEL 系日常管理 |
| ufw | 前端,简化语法 | Ubuntu | Ubuntu 简单场景、新手 |
firewalld 用 zone 的概念组织规则,比如 public、internal、trusted,网卡和来源可以归入不同 zone,各有不同的放行策略:
sudo firewall-cmd --state
sudo firewall-cmd --get-active-zones
sudo firewall-cmd --list-all
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --permanent --remove-service=cockpit
sudo firewall-cmd --reload # 必须 reload 才生效
sudo firewall-cmd --list-all
注意 firewalld 的 --permanent 和运行时规则是分开的,改了永久配置必须 --reload。
ufw 语法最简单,适合 Ubuntu 上手:
sudo ufw status verbose
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp
sudo ufw allow from 203.0.113.10 to any port 22 proto tcp
sudo ufw allow 80,443/tcp
sudo ufw delete allow 80/tcp
sudo ufw enable
sudo ufw status numbered # 带序号,便于删除
重要原则:同一台机器上只用一个前端。 如果 firewalld 或 ufw 在运行,就不要用 nft 命令手工加规则,否则会被前端的规则重载覆盖掉,或者相互冲突。要么停掉前端用 nft 直接管理,要么用前端不管底层。
# 决定用 nft 直接管理时,先停掉前端
sudo systemctl disable --now firewalld # RHEL 系
sudo systemctl disable --now ufw # Ubuntu
远程配置防火墙的风险控制
这是本文最重要的部分。远程改防火墙的经典事故是:设了 policy drop 但忘了放行 SSH,或者放行 SSH 时写错了自己的 IP,导致再也连不上。
风险控制的四条规则:
第一,先放行再收紧。 顺序永远是:先加放行 SSH 的规则(或先确认已有规则),再设置默认策略为 drop。反着做等于先把自己锁外面。
第二,保留一个已登录的会话。 在整个操作过程中不关闭当前 SSH 连接,所有验证都在新窗口做。这是最可靠的保险。
第三,确认带外通道可用。 云控制台的 VNC 或串口终端不经过网络,是最后的救命通道。动手前先登录一次验证可用。
第四,用定时任务做自动回滚保险。 这是进阶技巧,非常实用:
# 先设一个 10 分钟后自动恢复的保险
echo 'nft flush ruleset' | sudo at now + 10 minutes 2>/dev/null
# 确认没问题后取消
sudo atq
sudo atrm 任务号
at 需要先安装并启动 atd 服务。如果不用 at,也可以用 sleep 600 && nft flush ruleset & 配合 disown,但不如 at 清晰。做完验证记得取消,否则 10 分钟后你的规则会被清空。
失联后的回滚方法:
| 通道 | 操作 |
|---|---|
| 还有会话 | 直接 nft flush ruleset 或改回配置 |
| 已断连但有 VNC | 控制台登录,清空规则集或还原配置文件 |
| firewalld 场景 | firewall-cmd --panic-off 紧急解除 |
| 云安全组误配 | 控制台改回安全组规则,不依赖主机 |
| 完全无通道 | 联系云厂商技术支持,或重装系统保留数据盘 |
firewalld 提供了紧急模式,一键开启或关闭全部流量:
sudo firewall-cmd --panic-on # 全部拒绝(紧急止血)
sudo firewall-cmd --panic-off # 恢复正常
sudo firewall-cmd --query-panic
需要提醒的是 --panic-on 会连你自己的连接也断掉,所以只应该在已经确认有带外通道时使用,不要作为常规操作。
Windows Defender 防火墙
Windows Server 侧的防火墙是 Windows Defender 防火墙(带高级安全),它是有状态防火墙,默认阻止入站未请求的流量、允许出站流量。管理方式有图形界面和 PowerShell 两种,批量配置推荐 PowerShell。
查看当前状态与规则:
Get-NetFirewallProfile | Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction
Get-NetFirewallRule -Direction Inbound -Enabled True |
Select-Object DisplayName, Direction, Action, Profile |
Sort-Object DisplayName | Format-Table -AutoSize
创建入站规则,推荐按程序而不是按端口:
# 按程序放行,只影响指定可执行文件
New-NetFirewallRule -DisplayName "允许 Nginx 入站" `
-Direction Inbound -Action Allow -Protocol TCP `
-Program "C:\nginx\nginx.exe" -Profile Any
# 按端口放行,并限制来源 IP(作用域)
New-NetFirewallRule -DisplayName "允许 RDP 仅办公网" `
-Direction Inbound -Action Allow -Protocol TCP -LocalPort 3389 `
-RemoteAddress 203.0.113.10,198.51.100.0/24 -Profile Any
# 允许 ping,便于排障
New-NetFirewallRule -DisplayName "允许 ICMPv4 Echo" `
-Direction Inbound -Action Allow -Protocol ICMPv4 -IcmpType 8
按程序 vs 按端口的选择: 按程序(-Program)的好处是规则与具体可执行文件绑定,即使端口变化或程序被替换,规则不会误放行其他程序;缺点是程序路径变更时规则失效,且对多进程或动态端口的服务支持不友好。按端口(-LocalPort)配置简单稳定,但任何能在本机启动该端口监听的程序都会被放行。服务类应用建议按程序,标准服务(如 RDP、WinRM)按端口并严格限制来源。
作用域限制来源 IP(-RemoteAddress) 是 Windows 防火墙最实用也最容易被忽略的参数。把 3389 只对办公网出口放行,能挡掉绝大部分远程桌面爆破。修改已有规则的作用域:
# 收紧已有的 RDP 规则
Get-NetFirewallRule -DisplayGroup "远程桌面" | Where-Object { $_.Direction -eq 'Inbound' } |
Set-NetFirewallRule -RemoteAddress 203.0.113.10,198.51.100.0/24
# 禁用不需要的默认规则(比删除安全,便于回滚)
Get-NetFirewallRule -DisplayName "*文件和打印机共享*" |
Set-NetFirewallRule -Enabled False
风险提示:修改远程桌面相关规则前,先确认自己当前的来源 IP 在放行范围内,并确认云控制台有 VNC 或救援通道。改完立刻开一个新连接验证,不要关闭当前会话。
规则的管理与清理:
# 导出配置备份
netsh advfirewall export "C:\fw-backup.wfw"
# 恢复
netsh advfirewall import "C:\fw-backup.wfw"
# 重置为默认(危险,会清除全部自定义规则)
netsh advfirewall reset
# 删除规则
Remove-NetFirewallRule -DisplayName "允许 Nginx 入站"
# 查看某条规则的完整配置
Get-NetFirewallRule -DisplayName "允许 RDP 仅办公网" | Get-NetFirewallAddressFilter
netsh advfirewall export 导出的文件是重要备份手段,批量修改规则前先导出,出错可一键还原。
常见问题
nft 加了规则,重启后没了,为什么?
nft 命令只改内存中的规则集,持久化要导出到 /etc/nftables.conf 并启用 nftables 服务。执行 sudo nft list ruleset > /etc/nftables.conf 后确认服务已 enable。
为什么加了默认 drop 之后 apt 或 curl 就卡住了?
因为没有放行 ct state established,related,本机主动发起的连接其返回包被 input 链挡掉了。加上这条规则即可,它应该放在 input 链靠前的位置。
firewalld 和 nft 能一起用吗?
技术上能,但不建议。firewalld 是 nftables 的前端,它重载规则时会覆盖手工加的 nft 规则。选一个坚持用:要么用 firewalld 管理一切,要么停掉 firewalld 直接用 nft。
修改防火墙配置时怎么保证不失联?
四条措施:先加放行规则再收紧默认策略;保留一个已登录会话不关;提前确认云控制台 VNC 可用;用 at now + 10 minutes 设置一个自动清空规则的保险,验证通过后取消。
Windows 上配了入站规则还是连不上?
按三层排查:云安全组是否放行、Windows 防火墙是否放行、服务是否真的在监听。用 netstat -ano | findstr "3389" 确认监听,用 Test-NetConnection 目标IP -Port 3389 从外部测试区分是网络问题还是服务问题。
总结
- nftables 用统一语法和
inet地址族取代了 iptables 的四套工具,引入集合提升海量 IP 的匹配性能,主流发行版已默认切换;不要混用 iptables 与 nft 命令。 - 三层结构是表(指定地址族)、链(基础链挂内核钩子、常规链用于分组)、规则(匹配加动作);规则在链内按顺序匹配,命中即停。
- 有状态放行是必配项:
ct state established,related accept放在 input 链靠前位置,否则本机主动外连的返回包会被挡掉。 - 持久化靠
/etc/nftables.conf加 nftables 服务,改配置前先备份、nft -c -f检查语法再重启;firewalld 与 ufw 都是 nftables 的前端,同机只用其一。 - 远程改防火墙必须遵守"先放行后收紧、保留会话、确认 VNC、设定时回滚保险"四条,失联时按 VNC、
--panic-off、安全组、厂商支持顺序抢救;Windows 侧用New-NetFirewallRule的-RemoteAddress严格限制来源,并按程序而非端口授权服务。
企业QQ咨询




