Nftables 防火墙

Nftables 详细笔记

本文是一份可直接上手的 nftables 实战手册:从安装、启用、规则编写到常见场景(仅放行必要端口、KDE Connect、端口转发/NAT、VPN/WireGuard、速率限制、日志)与排错

快速上手:

1
2
3
4
5
6
7
8
9
10
11
# 查看当前规则集
sudo nft list ruleset

# 载入规则文件(不会保存到磁盘以外位置)
sudo nft -f /etc/nftables.conf

# 语法检查(只检查,不应用)
sudo nft -c -f /etc/nftables.conf

# 清空所有规则(危险,远程时当心)
sudo nft flush ruleset

服务与持久化(systemd):

1
2
sudo systemctl enable --now nftables.service
sudo systemctl status nftables.service

1、安装与启用(按发行版)

1.1、Arch Linux
1
2
3
4
5
6
# 大多数 Arch 已内置,若未安装:
sudo pacman -S nftables
# 查看是否安装
sudo pacman -Q nftables
# 启用服务并开机自启
sudo systemctl enable --now nftables.service
1.2、Debian / Ubuntu / Linux Mint
1
2
3
sudo apt update
sudo apt install nftables
sudo systemctl enable --now nftables.service

提示(Ubuntu/UFW):Ubuntu 的 UFW 默认已经基于 nft 后端。如果你要直接写 nft 规则,不建议同时启用/使用 UFW,以免冲突。要么只用 UFW,要么停用 UFW 转用纯 nft

1.3、Fedora / RHEL / CentOS / Rocky / AlmaLinux

这些系统默认启用 firewalld(其后端也是 nft)二选一:

  • 继续用 firewalld(推荐给新手)
  • 停用 firewalld,改用纯 nftables(适合熟悉 nft 的用户)
1
2
3
4
# 选择纯 nft:
sudo dnf install nftables
sudo systemctl disable --now firewalld
sudo systemctl enable --now nftables.service

远程服务器请谨慎:停用 firewalld 前先准备好等效的 nft 规则,避免把自己锁在门外

1.4、openSUSE
1
2
sudo zypper install nftables
sudo systemctl enable --now nftables.service

2、规则集结构与写法

nftables 结构:ruleset → table → chain → rule

  • family:ip(仅 IPv4), ip6(仅 IPv6), inet(IPv4+IPv6 同写),arp,bridge 等
  • 常用 family:inet(推荐,双栈统一书写)
  • hook(挂载点):input/forward/output(filter),prerouting/postrouting(nat)
  • policy:链的默认策略,常用 accept 或 drop

3、最小安全模板(建议默认)

将以下内容保存到 /etc/nftables.conf:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
chain input {
type filter hook input priority filter; policy drop;

ct state invalid drop comment "早丢无效连接"
ct state { established, related } accept comment "允许已跟踪连接"
iif lo accept comment "允许本机环回"
ip protocol icmp accept comment "允许 IPv4 ICMP"
meta l4proto ipv6-icmp accept comment "允许 IPv6 ICMP"

tcp dport ssh accept comment "开放 SSH 22/TCP(建议配合密钥/端口变更)"
# 示例:开放 Web
tcp dport {80,443} accept

# 其它需要的端口在此按需添加:
# tcp dport { 8080, 9090 } accept
# udp dport 51820 accept # WireGuard 示例
}

chain forward {
type filter hook forward priority filter; policy drop;
}

chain output {
type filter hook output priority filter; policy accept;
}
}

应用:

1
2
3
sudo nft -c -f /etc/nftables.conf   # 先检查
sudo systemctl restart nftables.service
sudo nft list ruleset

4、进阶模板(含多端口放行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#!/usr/sbin/nft -f
flush ruleset

table inet filter {
chain input {
type filter hook input priority filter; policy drop;

ct state invalid drop comment "早丢无效连接"
ct state { established, related } accept comment "允许已跟踪连接"
iif lo accept comment "允许 loopback"
ip protocol icmp accept comment "允许 IPv4 ICMP"
meta l4proto ipv6-icmp accept comment "允许 IPv6 ICMP"

# SSH
tcp dport ssh accept comment "允许 SSH"

# 你需要的端口(TCP/UDP)
tcp dport { 80, 443, 8080, 8090, 1090, 1080, 33612, 23361, 5000, 2017, 10170, 1314 } accept comment "允许指定 TCP"
udp dport { 80, 443, 8080, 8090, 1090, 1080, 33612, 23361, 5000, 2017, 10170, 1314 } accept comment "允许指定 UDP"

# KDE Connect
tcp dport 1716-1764 accept comment "KDE Connect TCP"
udp dport 1716-1764 accept comment "KDE Connect UDP"

# 基础抗扫描:限制主机发来的包速率(非严格防护,仅示例)
pkttype host limit rate 5/second counter reject with icmpx type admin-prohibited

counter comment "统计所有被拒"
}

chain forward {
type filter hook forward priority filter; policy drop;
}

chain output {
type filter hook output priority filter; policy accept;
}
}

保存为 /etc/nftables.conf 并重载:

1
sudo systemctl restart nftables.service

5、常见场景配置

1.1、仅放行指定服务端口
  • 规则放在 table inet filter 的 input 链里
  • 常用:SSH(22)、HTTP(80)、HTTPS(443)、WireGuard(51820/UDP) 等
  • 出站(output)默认一般 accept 即可
1.2、出站流量说明:为什么没放行端口也能访问外网
  • 浏览器访问网页属于出站(output)连接,服务器回复会匹配 ct state established,related 放行,不依赖 input 端口放行
  • 别人访问你的机器是入站(input)连接,才会命中 input 链的端口判断

对照:

  • 你本机 curl -x 127.0.0.1:2017 https://example.com → 出站,不受 input 限制
  • 别人手机连你 你的IP:2017 → 入站,若未 tcp dport 2017 accept 会被拦
1.3、NAT 上网共享(Masquerade)

用途:你的主机作为网关,让内网通过它访问外网

1)先开启内核转发:

1
2
3
4
5
# IPv4
echo 'net.ipv4.ip_forward=1' | sudo tee /etc/sysctl.d/99-nftables-forward.conf
# IPv6(如需)
echo 'net.ipv6.conf.all.forwarding=1' | sudo tee -a /etc/sysctl.d/99-nftables-forward.conf
sudo sysctl --system

2)在 nftables 里新增 nat 表(把 define wan 改成你的外网网卡名,如 eth0/enp3s0/wlan0):

1
2
3
4
5
6
7
8
9
10
11
12
table inet nat {
define wan = "eth0"

chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
}

chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
oifname $wan masquerade comment "源 NAT:内网经 $wan 出口上网"
}
}

与 filter 表并存:把这个 table inet nat { … } 加到 /etc/nftables.conf 中即可。

1.4、端口转发(DNAT)

把外网的 80 端口转发到内网 192.168.1.10:8080:

1
2
3
4
5
6
7
8
9
10
11
12
table inet nat {
chain prerouting {
type nat hook prerouting priority dstnat; policy accept;
tcp dport 80 dnat to 192.168.1.10:8080
}

chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
# 若需回流 SNAT:
ip saddr 192.168.1.0/24 ip daddr 192.168.1.10 tcp dport 8080 masquerade
}
}
1.5、WireGuard 常用规则

WireGuard 默认 UDP 端口(示例 51820):

1
2
# filter 表 input 链里
udp dport 51820 accept comment "WireGuard"
1.6、基础抗扫描/限速与日志

限速示例(SYN 新建连接每 IP 每秒 25 次):

1
tcp flags & (syn|ack) == syn limit rate over 25/second drop comment "limit syn flood"

记录被拒包到日志(需内核日志支持,配合 journalctl):

1
2
3
4
reject with icmpx type admin-prohibited
# 或记录:
log prefix "nft-drop: " group 0
drop

查看:

1
sudo journalctl -k | grep nft-drop
1.7、临时调试与持久化

临时添加规则(重启服务后丢失):

1
sudo nft add rule inet filter input tcp dport 9000 accept

Nftables 防火墙
http://huishao.net/2025/09/20/nftables详细笔记/
作者
huishao
发布于
2025年9月20日
许可协议