iptables 与 nftables:防火墙到底在干什么
ufw 够用,但遇到「Docker 绕过防火墙」「规则不生效」这类问题,还是得懂底层。
一、结构:表 → 链 → 规则
iptables
├─ filter 表(默认,做放行/拒绝)
│ ├─ INPUT 进本机的包
│ ├─ FORWARD 经过本机转发的包
│ └─ OUTPUT 从本机发出的包
├─ nat 表(地址转换)
│ ├─ PREROUTING / POSTROUTING / OUTPUT
└─ mangle 表(改包头,较少用)日常 90% 的操作都在 filter 表的 INPUT 链。
二、包怎么走
包到达网卡
→ PREROUTING (nat) # 改目标地址(端口转发在这)
→ 路由判断:是给我的吗?
├─ 是 → INPUT (filter) → 本机进程
└─ 否 → FORWARD (filter) → POSTROUTING (nat) → 转发出去
本机发出:OUTPUT (filter) → POSTROUTING (nat)三、常用规则
# 查看(-n 不反解域名,-v 详细,--line-numbers 带行号)
sudo iptables -L -n -v --line-numbers
sudo iptables -t nat -L -n -v
# 允许已建立的连接(这条几乎必须有)
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# 允许回环
sudo iptables -A INPUT -i lo -j ACCEPT
# 放行端口
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# 允许 ping(可选)
sudo iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
# 限制来源 IP
sudo iptables -A INPUT -p tcp --dport 3306 -s 10.0.0.5 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 3306 -j DROP
# 限流:每分钟最多 25 个新连接(防暴力破解)
sudo iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m limit --limit 25/minute --limit-burst 100 -j ACCEPT
# 默认策略:拒绝所有进来的
sudo iptables -P INPUT DROP插入与删除:
sudo iptables -I INPUT 1 -p tcp --dport 8080 -j ACCEPT # 插到第 1 条
sudo iptables -D INPUT 3 # 删第 3 条
sudo iptables -F # 清空所有规则(危险)修改默认策略为 DROP 之前,一定要先放行 SSH,否则立刻把自己锁在外面。
四、保存规则
iptables 规则默认在内存里,重启就没了:
# Debian/Ubuntu
sudo apt install -y iptables-persistent
sudo netfilter-persistent save
# 规则存到 /etc/iptables/rules.v4
# 手动保存/恢复
sudo iptables-save > /etc/iptables/rules.v4
sudo iptables-restore < /etc/iptables/rules.v4五、nftables 是新一代
Debian 11+ / Ubuntu 22.04+ 默认后端已经是 nftables,iptables 命令是兼容层。
sudo nft list ruleset# /etc/nftables.conf 片段
table inet filter {
chain input {
type filter hook input priority 0;
policy drop;
iif lo accept
ct state established,related accept
tcp dport { 22, 80, 443 } accept
icmp type echo-request accept
}
}nftables 的优势:语法更简洁、支持集合({ 22, 80, 443 } 一条规则搞定)、IPv4/IPv6 统一管理(inet 族)。
六、ufw 其实是个包装器
sudo ufw allow 22/tcp
sudo ufw deny 3306
sudo ufw status numbered
sudo ufw delete 3它生成的规则最终还是落到 iptables/nftables:
sudo iptables -L -n | head -20 # 能看到 ufw 创建的链七、经典坑:Docker 绕过防火墙
现象:ufw deny 8080 了,但容器映射的 8080 端口外网照样能访问。
原因:Docker 直接往 iptables 的 PREROUTING 和 FORWARD 里插规则,数据包在到达 ufw 的链之前就被转发走了。
解法几种:
- 只监听本机(最推荐):
ports:
- "127.0.0.1:8080:80" # 只有本机和 Nginx 反代能访问- 用
DOCKER-USER链(Docker 专门留给用户插规则的地方):
sudo iptables -I DOCKER-USER -i eth0 ! -s 10.0.0.0/8 -p tcp --dport 8080 -j DROP- 关闭 Docker 的 iptables 操作(
/etc/docker/daemon.json里"iptables": false),代价是容器网络要自己管。
我的习惯:容器端口一律只映射 127.0.0.1,对外统一由 Nginx 反代。这样防火墙规则就是唯一入口,也少一个暴露面。
八、检查清单
# 对外暴露了哪些端口
sudo ss -lntp
sudo iptables -L INPUT -n -v
# 从外网扫一遍(用另一台机器或在线工具)
nmap -Pn your-server-ip- 默认策略是 DROP
- 只放行必要端口
- 数据库、缓存端口不对外
- 容器映射只绑 127.0.0.1
- 规则已持久化
防火墙的核心思路就一句:默认拒绝,按需放行。
