Q先生的世界

面朝大海,春暖花开

关于iptables那些你必须知道的

很多人第一次接触 iptables,感受通常都差不多:

  1. 命令很长
  2. 选项很多
  3. 一旦写错,可能直接把自己锁在服务器外面

于是大家要么机械记忆几条命令,要么直接复制网上的脚本,却始终不明白 iptables 到底在做什么。

这篇文章想解决的,就是这个问题。

我会站在初学者视角,把 iptables 拆成几个最核心的问题来讲:

  1. iptables 到底是什么,和 netfilter 是什么关系
  2. table、chain、rule 分别是什么意思
  3. 一个包进入机器后,规则到底按什么顺序匹配
  4. 最常用的命令该怎么写、怎么看、怎么删
  5. 常见实战场景怎么配置
  6. 为什么规则明明写了却不生效,以及如何排查

如果你读完后能自己写出一套基础防火墙规则,并且知道每一条为什么这么写,这篇文章就达到目的了。


1. iptables 到底是什么

先说结论:

iptables 不是内核里的防火墙本体,它更像是一个用户态管理工具。

真正做包过滤、NAT、连接跟踪这些工作的,是 Linux 内核里的 netfilter 框架;而 iptables 只是你用来向 netfilter 下发规则的命令行工具。

可以把它理解成:

  1. netfilter 是发动机
  2. iptables 是方向盘和仪表盘

你平时写的这些命令:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

本质上就是在告诉内核:

如果进入本机的包是 TCP,目标端口是 22,那么允许它通过。

1.1 iptables 和 nftables 的关系

顺手提一句,现代 Linux 里很多发行版已经逐步转向 nftables。

但这并不意味着 iptables 过时到不能学,原因很简单:

  1. 大量线上环境仍然在使用 iptables
  2. 很多云主机、容器环境、旧脚本和运维文档仍然围绕 iptables
  3. 学懂 iptables 之后,再学 nftables 会更容易

所以本文聚焦 iptables,但你需要知道:

  1. iptables 是老牌主流方案
  2. nftables 是更新一代的规则框架
  3. 有些系统上的 iptables 命令,底层可能已经映射到 nft 兼容层

2. 先建立一个最重要的心智模型

初学 iptables,最容易混乱的地方是术语太多。

这里先只记住这三层:

  1. table:规则表,按功能分类
  2. chain:规则链,按流量经过的位置分类
  3. rule:规则,真正的匹配条件和动作

可以类比成:

  1. table 是一个部门
  2. chain 是部门里的处理队列
  3. rule 是队列中的具体检查项

一个网络包到来时,会进入某张表中的某条链,然后按顺序逐条匹配规则。匹配到了,就执行对应动作;没有匹配到,就继续往后走。

这句话非常重要:

iptables 规则通常是按顺序自上而下匹配的,先匹配到的规则先执行。

也就是说,规则顺序本身就是逻辑的一部分。


3. 五张常见的表

iptables 里最常见的是下面几张表。

3.1 filter

这是最常用、也是默认使用的表。

它的职责就是:包过滤

大多数人日常说“防火墙规则”,通常就是在操作 filter 表。

它最常见的三条链是:

  1. INPUT:处理进入本机的数据包
  2. OUTPUT:处理从本机发出的数据包
  3. FORWARD:处理经过本机转发的数据包

3.2 nat

负责地址转换,也就是 NAT。

最常见用途:

  1. 源地址转换,SNAT/MASQUERADE
  2. 目标地址转换,DNAT/端口转发

常见链有:

  1. PREROUTING
  2. POSTROUTING
  3. OUTPUT

3.3 mangle

用于修改数据包的一些特殊字段,比如 TOS、TTL、MARK 等。

它更偏高级玩法,很多人长时间都用不到。初学阶段知道它存在即可。

3.4 raw

主要用于在连接跟踪之前做特殊处理,比如决定某些包不进入 conntrack。

这张表也不属于入门高频内容。

3.5 security

和 SELinux 等安全模块联动,普通运维场景中不算常用。

3.6 入门建议

如果你刚开始学,只需要优先掌握两张表:

  1. filter
  2. nat

只要这两张表吃透,已经能解决大多数主机防火墙和端口转发问题。


4. 三条最核心的链

先只盯住 filter 表中的三条链:

4.1 INPUT

凡是“发给这台机器自己”的流量,都会走这里。

例如:

  1. SSH 登录这台服务器
  2. 访问这台服务器上的 Nginx 80/443 端口
  3. 访问本机监听的数据库端口

4.2 OUTPUT

凡是“这台机器主动发出去”的流量,都会走这里。

例如:

  1. 服务器主动请求外部 API
  2. 服务器执行 curl
  3. 服务器发 DNS 查询

4.3 FORWARD

凡是“不是发给本机,而是要经过本机转发”的流量,都会走这里。

例如:

  1. 这台机器是路由器
  2. 这台机器做网关/NAT 转发
  3. 容器网络或虚拟机网络经过本机转发

很多人一开始学 iptables 会把 INPUTFORWARD 搞混。

你只要记住一句:

  1. 给我自己的,走 INPUT
  2. 借我这台机器过路的,走 FORWARD

5. 一个包到底怎么走

这部分是 iptables 最关键的“地图感”。

5.1 发往本机的包

一个外部包进入网卡,目标就是本机服务,大致路径是:

  1. 先进入 PREROUTING
  2. 路由判断发现目标是本机
  3. 进入 INPUT
  4. 交给本机进程

5.2 本机发出的包

本机进程主动发包,大致路径是:

  1. OUTPUT 出发
  2. 经过路由选择
  3. 必要时进入 POSTROUTING
  4. 从网卡发出

5.3 经过本机转发的包

一个包进来后发现目标不是本机,而是别的机器,大致路径是:

  1. 先进入 PREROUTING
  2. 路由判断发现要转发
  3. 进入 FORWARD
  4. 再进入 POSTROUTING
  5. 发往下一跳

如果你理解这三条路径,很多规则就不会乱写了。

比如:

  1. 你想限制别人 SSH 到本机,改 INPUT
  2. 你想让本机做公网出口 NAT,改 POSTROUTING
  3. 你想控制内网流量是否允许穿过网关,改 FORWARD

6. 规则长什么样

一个典型规则通常由三部分构成:

  1. 匹配条件
  2. 所在链
  3. 目标动作

例如:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

这条规则可以拆成:

  1. -A INPUT:追加到 INPUT
  2. -p tcp:匹配 TCP 协议
  3. --dport 22:目标端口是 22
  4. -j ACCEPT:匹配后执行允许动作

再比如:

iptables -A INPUT -s 192.168.1.10 -p tcp --dport 22 -j ACCEPT

意思就是:

只允许来源 IP 为 192.168.1.10 的主机访问本机 SSH 端口。


7. 最常见的动作 target

匹配到规则后,最常见的动作就是 -j 指定的 target。

7.1 ACCEPT

允许通过。

iptables -A INPUT -p tcp --dport 80 -j ACCEPT

7.2 DROP

直接丢弃,不给对方任何响应。

iptables -A INPUT -p tcp --dport 23 -j DROP

从攻击者视角看,这种方式像“石沉大海”。

7.3 REJECT

拒绝,并返回一个错误响应。

iptables -A INPUT -p tcp --dport 23 -j REJECT

这相当于明确告诉对方:这个请求不被接受。

7.4 LOG

记录日志,常用于调试。

iptables -A INPUT -p tcp --dport 2222 -j LOG --log-prefix "IPTABLES DROP: "

注意,LOG 只负责记日志,不会自动丢包。通常要搭配后续的 DROPREJECT 规则一起使用。

7.5 DNAT / SNAT / MASQUERADE

这些多见于 nat 表:

  1. DNAT:改目标地址
  2. SNAT:改源地址
  3. MASQUERADE:一种动态 SNAT,常用于出口 IP 会变化的场景

8. 你最该记住的常用命令

这部分是上手最有用的内容。

8.1 查看规则

iptables -L

这会列出默认 filter 表的规则,但通常不够好用。

更常见的是:

iptables -L -n -v

参数含义:

  1. -L:列出规则
  2. -n:数字显示 IP 和端口,不做 DNS 反查
  3. -v:显示更详细信息,比如命中计数、字节数、网卡

如果你想看行号,方便删除:

iptables -L -n -v --line-numbers

8.2 查看指定表

iptables -t nat -L -n -v

如果不写 -t,默认查看的是 filter 表。

8.3 追加规则

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

-A 是 append,表示追加到链尾。

8.4 插入规则

iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT

这条命令表示把规则插到 INPUT 链第 1 条。

这在远程维护服务器时尤其重要,因为顺序决定匹配结果。

8.5 删除规则

有两种常用删法。

按完整规则删除:

iptables -D INPUT -p tcp --dport 22 -j ACCEPT

按行号删除:

iptables -D INPUT 3

通常我更推荐先看带行号的列表,再按行号删。

8.6 替换规则

iptables -R INPUT 2 -p tcp --dport 22 -s 10.0.0.10 -j ACCEPT

这表示替换 INPUT 链第 2 条规则。

8.7 清空规则

iptables -F

这会清空默认 filter 表中的所有链规则。

清空指定表:

iptables -t nat -F

这个命令风险很大,线上机器慎用。

8.8 修改默认策略

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

-P 是 policy,用来设置链的默认策略。

这表示:

  1. INPUT 默认丢弃
  2. FORWARD 默认丢弃
  3. OUTPUT 默认允许

它的思想是典型的“默认拒绝,按需放行”。


9. 先学会看输出

很多人会写命令,但不会读规则列表。

例如:

iptables -L INPUT -n -v --line-numbers

可能看到这样的输出:

Chain INPUT (policy DROP 120 packets, 9000 bytes)
num   pkts bytes target     prot opt in  out source          destination
1     100  8000  ACCEPT     all  --  lo  *   0.0.0.0/0       0.0.0.0/0
2      15  1200  ACCEPT     all  --  *   *   0.0.0.0/0       0.0.0.0/0    ctstate RELATED,ESTABLISHED
3       2   120  ACCEPT     tcp  --  *   *   10.0.0.10       0.0.0.0/0    tcp dpt:22
4       1    60  ACCEPT     tcp  --  *   *   0.0.0.0/0       0.0.0.0/0    tcp dpt:80
5       0     0  ACCEPT     tcp  --  *   *   0.0.0.0/0       0.0.0.0/0    tcp dpt:443

重点关注这几列:

  1. num:规则序号
  2. pkts / bytes:命中次数和流量大小
  3. target:动作
  4. prot:协议
  5. source / destination:源地址和目标地址

如果某条规则一直命中数为 0,往往说明:

  1. 流量根本没经过这里
  2. 前面已经被别的规则匹配掉了
  3. 你写错了条件

10. conntrack 是 iptables 的半壁江山

如果只学静态端口放行,你会觉得 iptables 很笨;但真正让它变得“像现代防火墙”的关键,是 连接跟踪

最经典的一条规则是:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

这条规则的意义非常大。

10.1 什么叫 ESTABLISHED

比如你从服务器主动访问外部网站:

  1. 请求包从 OUTPUT 发出去
  2. 响应包回来时,属于一个已建立连接
  3. 这时可以通过 ESTABLISHED 规则放行

表示和已有连接相关联的连接,比如某些 FTP 场景或 ICMP 错误响应。

10.3 为什么这条规则几乎总要写

因为它可以让你:

  1. 保持已有会话不断开
  2. 不必为返回流量一条条手写对称规则
  3. 让默认拒绝策略仍然可用

一个非常经典的最小可用防火墙写法就是:

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

这里每一条都很有代表性:

  1. 回环接口必须放行
  2. 已建立连接必须放行
  3. 明确开放 SSH / HTTP / HTTPS
  4. 其余入站流量默认丢弃

11. 为什么一定要先放行 lo

很多服务之间会通过本机回环地址 127.0.0.1::1 通信。

例如:

  1. Nginx 反向代理本机应用
  2. 本地 agent 和 daemon 通信
  3. 某些数据库或缓存只监听本地地址

因此常见规则是:

iptables -A INPUT -i lo -j ACCEPT

如果你把回环接口都误伤了,很多本地服务会表现得非常诡异。


12. 常见匹配条件怎么写

这一节专门讲命令拼装。

12.1 按协议匹配

iptables -A INPUT -p tcp --dport 443 -j ACCEPT
iptables -A INPUT -p udp --dport 53 -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT

12.2 按源地址匹配

iptables -A INPUT -s 10.0.0.10 -j ACCEPT
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT

12.3 按目标地址匹配

iptables -A OUTPUT -d 8.8.8.8 -p udp --dport 53 -j ACCEPT

12.4 按网卡匹配

iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -o eth0 -p tcp --dport 443 -j ACCEPT
  1. -i 表示入接口
  2. -o 表示出接口

12.5 按源端口和目标端口匹配

iptables -A INPUT -p tcp --sport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

实际中更常用 --dport,因为服务监听的是目标端口。

12.6 按连接状态匹配

iptables -A INPUT -m conntrack --ctstate NEW -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

12.7 按多个端口匹配

iptables -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPT

12.8 按速率限制匹配

例如限制 ping 洪泛:

iptables -A INPUT -p icmp -m limit --limit 5/second --limit-burst 10 -j ACCEPT

超过速率的流量可以在后续规则中 DROP


13. 从零写一套安全一点的主机规则

下面给一套适合单机 Web 服务器的基础规则,并解释原因。

13.1 适用场景

假设服务器用途如下:

  1. 允许 SSH 运维
  2. 提供 HTTP / HTTPS 服务
  3. 拒绝其他所有入站访问
  4. 允许本机主动访问外部网络

13.2 规则示例

iptables -F

iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

iptables -A INPUT -p tcp -s 10.0.0.10 --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

iptables -A INPUT -p icmp -m limit --limit 5/second --limit-burst 10 -j ACCEPT

iptables -A INPUT -j LOG --log-prefix "iptables denied: "
iptables -A INPUT -j DROP

13.3 逐条解释

  1. -F 先清空旧规则,避免叠加污染
  2. 默认策略把未显式允许的流量都拒掉
  3. 放行 lo,确保本地通信正常
  4. 放行已建立连接,避免正常返回流量被拦截
  5. SSH 只允许办公机 10.0.0.10 登录
  6. 80/443 对外开放
  7. ICMP 做基本限速
  8. 最后记录日志并丢弃其他流量

13.4 远程操作时的顺序建议

如果你是通过 SSH 远程连上去改规则,最安全的顺序不是上面这样一股脑执行,而是:

  1. 先插入允许当前 SSH 的规则
  2. 再放行 ESTABLISHED,RELATED
  3. 再设置默认策略为 DROP
  4. 最后补充其他业务端口规则

否则你可能在第 2 步就把自己踢下线。


14. NAT 到底在做什么

NAT 是另一个非常高频的 iptables 用法。

14.1 SNAT / MASQUERADE

典型场景:

  1. 一台 Linux 主机作为内网出口
  2. 内网机器通过它访问公网

假设:

  1. 内网网卡是 eth1
  2. 外网网卡是 eth0
  3. 内网网段是 192.168.10.0/24

常见写法:

echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -P FORWARD DROP
iptables -A FORWARD -i eth1 -o eth0 -s 192.168.10.0/24 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -d 192.168.10.0/24 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j MASQUERADE

这里最核心的是最后一条:

把内网源地址伪装成出口网卡地址,再发往公网。

如果公网 IP 固定,也可以用 SNAT

iptables -t nat -A POSTROUTING -s 192.168.10.0/24 -o eth0 -j SNAT --to-source 203.0.113.10

14.2 DNAT / 端口转发

典型场景:

  1. 公网访问网关的 8080 端口
  2. 实际转发到内网主机 192.168.10.20:80
echo 1 > /proc/sys/net/ipv4/ip_forward

iptables -t nat -A PREROUTING -p tcp -d 203.0.113.10 --dport 8080 -j DNAT --to-destination 192.168.10.20:80

iptables -A FORWARD -p tcp -d 192.168.10.20 --dport 80 -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -p tcp -s 192.168.10.20 --sport 80 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

这就是很经典的“公网端口映射到内网服务”。


15. 自定义链能让规则更清晰

当规则多起来后,全塞进 INPUT 会越来越难维护。

这时可以定义自己的链。

iptables -N TCP_SERVICES
iptables -A TCP_SERVICES -p tcp --dport 22 -j ACCEPT
iptables -A TCP_SERVICES -p tcp --dport 80 -j ACCEPT
iptables -A TCP_SERVICES -p tcp --dport 443 -j ACCEPT

iptables -A INPUT -p tcp -j TCP_SERVICES

这相当于把 TCP 服务相关规则拆到一个单独模块里。

好处是:

  1. 结构清晰
  2. 便于复用
  3. 后续排障更容易

查看自定义链也一样:

iptables -L TCP_SERVICES -n -v

16. 保存规则,不然重启就没了

这是初学者最容易踩的坑之一。

很多系统上,你执行 iptables 命令只是改了当前内核运行时规则,机器一重启可能就消失。

16.1 导出当前规则

iptables-save

保存到文件:

iptables-save > /etc/iptables.rules

16.2 从文件恢复

iptables-restore < /etc/iptables.rules

16.3 持久化方式和发行版有关

不同系统做法不一样,比如:

  1. Debian/Ubuntu 常见 iptables-persistent
  2. CentOS/RHEL 早期常见 service iptables save
  3. 新系统可能配合 systemd 或转向 nftables

所以你在生产环境里,不能只会写规则,还要确认:

规则是如何随开机自动恢复的。


17. 非常实用的排障方法

iptables 的问题,很多时候不是“规则不会写”,而是“看不出来到底卡在哪”。

下面这些方法很实用。

17.1 先看有没有命中

iptables -L -n -v --line-numbers

先看 pktsbytes 是否增长。

如果不增长,说明流量没匹配到这条规则。

17.2 检查规则顺序

iptables 是顺序匹配。

如果你前面先写了:

iptables -A INPUT -j DROP

那后面再写允许 SSH 的规则基本就没意义了,因为流量在前面已经被丢掉了。

17.3 用 LOG 看看到底是谁被拦了

iptables -I INPUT 1 -p tcp --dport 22 -j LOG --log-prefix "ssh debug: "

然后去看系统日志,比如 dmesgjournalctl -k 或 rsyslog 落盘文件。

17.4 确认服务真的在监听

iptables 没问题,不代表服务就通。

例如:

ss -lntp

如果服务压根没监听在对应端口,再怎么放行也没用。

17.5 确认云环境还有一层安全组

在云服务器上,经常有两层防护:

  1. 云厂商安全组
  2. 主机内 iptables

你在主机里放行了 80 端口,但安全组没放,也一样访问不了。

17.6 确认是不是 firewalld / ufw 在管理规则

某些发行版上,真正的规则入口可能是:

  1. firewalld
  2. ufw
  3. 容器运行时自动注入的链

这时你手工写的规则可能会被覆盖,或者根本不是你以为的那套链路。

17.7 确认内核转发开关

如果你在做路由/NAT/端口转发,别忘了:

sysctl net.ipv4.ip_forward

如果值是 0,说明内核没有打开 IPv4 转发。


18. 新手最常犯的错误

这里专门总结一下常见坑。

18.1 忘了放行已有连接

没有这条:

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

很多返回流量会异常。

18.2 默认策略设成 DROP 之前没留 SSH 生路

这会导致远程把自己锁死。

18.3 分不清 INPUT 和 FORWARD

  1. 访问本机服务,用 INPUT
  2. 经过本机转发,用 FORWARD

18.4 只写 nat,不写 FORWARD

很多人做端口转发时只写了 DNAT,却忘了配合 FORWARD 放行,结果仍然不通。

18.5 忘了持久化

机器一重启,规则全没。

18.6 规则越写越多,却没有自定义链

最后自己都看不懂。


19. 一组值得收藏的常用命令清单

19.1 查看当前 filter 规则

iptables -L -n -v --line-numbers

19.2 查看 nat 规则

iptables -t nat -L -n -v --line-numbers

19.3 放行 SSH

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

19.4 只允许某个 IP SSH

iptables -A INPUT -p tcp -s 10.0.0.10 --dport 22 -j ACCEPT

19.5 放行 HTTP/HTTPS

iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT

19.6 放行已建立连接

iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

19.7 丢弃某个 IP

iptables -A INPUT -s 203.0.113.55 -j DROP

19.8 删除第 3 条规则

iptables -D INPUT 3

19.9 插入规则到最前面

iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT

19.10 保存规则

iptables-save > /etc/iptables.rules

19.11 恢复规则

iptables-restore < /etc/iptables.rules

20. 给初学者的学习顺序建议

如果你现在还觉得 iptables 有点乱,不要试图一次把所有表、所有模块、所有 target 全背下来。

推荐学习顺序是:

  1. 先搞清楚 INPUTOUTPUTFORWARD
  2. 再理解 filternat
  3. 学会看规则列表和命中计数
  4. 学会 ACCEPTDROPREJECT
  5. 学会 conntrackESTABLISHED,RELATED
  6. 最后再去看 DNAT、SNAT、自定义链、限速、打标等进阶内容

只要这个顺序不乱,iptables 其实没有看起来那么可怕。


21. 总结

iptables 真正难的地方,不是命令本身,而是你必须在脑子里有一张“包路径地图”。

你可以把这篇文章压缩成下面这几个关键点:

  1. iptables 是管理工具,底层是 netfilter
  2. 重点先学 filter 表和 nat
  3. 重点先学 INPUTOUTPUTFORWARD
  4. 规则按顺序匹配,顺序非常重要
  5. ESTABLISHED,RELATED 是最常见的基础规则之一
  6. 做 NAT 时,不要忘了转发链和内核转发开关
  7. 写完规则后,一定确认持久化方式

如果你是第一次系统学习 iptables,我建议你找一台测试机,亲手做三件事:

  1. 只开放 SSH 和 80/443
  2. 限制 SSH 只能从你的办公 IP 登录
  3. 做一次简单的端口转发

当这三件事你都能自己完成,并且知道每条命令为什么这么写,iptables 就算真正入门了。