☰
iptables防火墙实战指南:从四表五链到规则集维护
2026/11/2 12:10:48 网站建设 项目流程

防火墙这东西,刚接触运维那会儿我总觉得它离我很远,直到有天凌晨两点被业务告警叫醒——一台对外服务的机器被人扫端口扫到飞起,日志里全是各种畸形包。那次之后我才老老实实把 iptables 从头啃了一遍。这篇就聊聊 iptables 防火墙这套东西,它本质上是什么、能干什么、适合谁来啃。简单说,iptables 是 Linux 内核里 netfilter 框架的用户态配置工具,负责数据包的过滤、转发、地址转换和端口映射。它解决的问题很直接:谁能进、谁能出、谁能穿过我这台机器。适合谁看?刚上手 Linux 运维的朋友、需要给服务器做基础加固的后端开发、以及想搞明白"为什么我的服务明明起来了却连不上"的排查型选手。下面这些内容都是我这些年踩坑踩出来的,不是照本宣科念手册。

1. 先搞清楚 iptables 到底在管什么

1.1 四表五链不是背出来的,是理解出来的

很多人一上来就被"四表五链"劝退,其实你把它想成一个快递分拣中心就通了。数据包就是包裹,链就是分拣流水线上的几个检查站,表就是不同职责的检查员。包裹从进站到出站,会依次经过不同的检查站,每个站点的检查员只关心自己那摊事。

filter 表是最常用的,负责放行还是丢弃,绝大多数"防火墙规则"说的就是它。nat 表管地址转换,做端口映射、内网共享上网靠它。mangle 表改数据包的一些标记字段,普通场景基本用不上,但做策略路由、打连接标记时会用到。raw 表优先级最高,用来在连接跟踪之前做处理,一般只在特殊需求下碰。

链这块,记住数据包的走向比死记名字有用得多。一个从外部进来、发给本机的包,走的是PREROUTING → INPUT;本机发出去的包走OUTPUT → POSTROUTING;而需要转发的包走PREROUTING → FORWARD → POSTROUTING。这个流向图在脑子里过一遍,后面写规则时该往哪条链上挂,自然就清楚了。

提示:新手最容易犯的错是把本该挂 FORWARD 的规则挂到 INPUT 上,结果转发流量死活不通。先判断这个包是"给本机的"还是"路过的",再决定链。

1.2 规则匹配的顺序逻辑,决定了你的规则怎么写

iptables 的规则是从上往下逐条匹配,命中即停。这个特性决定了规则顺序极其重要。你把一条 DROP 规则放在 ACCEPT 前面,那后面的 ACCEPT 就永远轮不上了。我见过有人把"拒绝所有"写在最上面,然后下面写了一堆放行规则,结果全废——因为第一个包就被拒了,根本走不到下面。

所以写规则的基本心法是:具体的、范围小的放前面,宽泛的、兜底的放后面。比如先放行已建立的连接,再放行特定端口,最后才是默认策略。这个顺序不是随便定的,是匹配机制逼出来的。

另外要理解状态匹配(conntrack)。加了-m state --state ESTABLISHED,RELATED的规则,能让已经建立的连接的回包自动放行,不用为每个方向都写规则。这是让规则集保持精简的关键技巧,后面实操部分会详细展开。

1.3 默认策略:那道最后的闸门

每条链都有一个默认策略(policy),当所有规则都没匹配上时,就按这个策略处理。常见做法是把 INPUT 和 FORWARD 的默认策略设成 DROP,OUTPUT 设成 ACCEPT。为什么?因为进来的和路过的流量风险更高,出去的一般是自家程序发起的,限制太死反而容易把自己坑了。

但这里有个大坑:你在远程连着的机器上,千万别在规则没配好之前就把默认策略改成 DROP。一旦改完发现自己把自己关在门外,那就只能去机房或者走带外管理了。正确姿势是先写好放行规则(尤其是放行你当前 SSH 端口和已建立连接),确认无误,最后再动默认策略。这个顺序我强调一百遍都不嫌多。

2. 规则写法与核心参数拆解

2.1 一条规则由哪些部分组成

一条完整的 iptables 规则,拆开看就是几个要素:哪张表、哪条链、匹配什么条件、匹配后做什么动作。举个最常见的例子:

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

逐段读:-t filter指定表(不写默认就是 filter);-A INPUT表示追加到 INPUT 链末尾;-p tcp匹配协议;--dport 22匹配目标端口;-j ACCEPT是动作,放行。这一条的意思就是"允许外部访问本机的 22 端口"。

动作(target)常用的就几个:ACCEPT放行、DROP静默丢弃(不给对方任何回应)、REJECT拒绝并回一个错误包、LOG记日志但不影响后续匹配、SNAT/DNAT做地址转换。DROP 和 REJECT 的区别值得说一下:DROP 是对外"装死",扫描器会觉得这个端口没开;REJECT 会明确告诉对方"此路不通"。做安全加固时我更倾向 DROP,减少信息暴露。

2.2 常用匹配条件速查

匹配条件是规则的"筛子",筛得越准,规则越安全。下面这张表是我平时写规则时脑子里过的清单:

匹配维度参数写法典型用途
协议-p tcp/udp/icmp区分 TCP、UDP、ICMP
源地址-s 192.168.1.0/24限制来源网段
目标地址-d 10.0.0.5限定目标
源端口--sport 1024:65535匹配高端口来源
目标端口--dport 80放行具体服务
入接口-i eth0限定从哪块网卡进
出接口-o eth1限定从哪块网卡出
连接状态-m state --state NEW/ESTABLISHED/RELATED状态跟踪
多端口-m multiport --dports 80,443,8080一次匹配多个端口
限速-m limit --limit 10/min防暴力破解、防日志刷屏

端口范围用冒号表示,比如--dport 1000:2000表示 1000 到 2000 这个区间。多端口匹配用 multiport 模块比写多条规则清爽得多,性能上也更友好。

2.3 状态匹配为什么是规则集的心脏

如果只能记住一个进阶技巧,那就是状态匹配。没有它,你得为每个服务写"进"和"出"两条规则,规则集臃肿且容易漏。有了它,一条ESTABLISHED,RELATED就能兜住所有已建立连接的回包。

iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

这条规则的含义是:只要是已建立连接的一部分,或者是与之相关的连接(比如 FTP 的数据连接、ICMP 的错误回包),一律放行。它通常放在 INPUT 链靠前的位置,作为"老朋友免检通道"。这样你只需要为 NEW 状态的新连接写放行规则,规则数量能砍掉一大半。

注意:状态匹配依赖内核的 conntrack 模块,连接跟踪表有容量上限。高并发场景下要关注nf_conntrack_max这个值,表满了会导致新连接被丢,表现为"服务时好时坏"。这个坑我在压测时踩过,排查了半天才发现是连接跟踪表爆了。

3. 从零搭一套可用的防火墙规则

3.1 动手前的准备与清场

正式写规则前,先看看现状。iptables -L -n -v列出当前所有规则,-n不解析域名(快),-v显示包计数(能看出哪条规则在生效)。如果机器上已经有别的防火墙管理工具在跑,先确认它们不会互相打架,否则你改的规则可能被覆盖。

清场用iptables -F清空所有链的规则,iptables -X删除自定义链。但清场前务必确认你有带外管理手段,或者本地终端在手,别在纯远程会话里一把梭。我一般会先开一个screen或tmux会话再操作,万一断线规则还在,不至于失联。

3.2 一套最小可用规则集的完整落地

下面这套规则是我给一台普通对外服务器做基础加固时常用的模板,逻辑清晰、够用、不易把自己锁死。按顺序执行:

# 1. 清空现有规则和自定义链 iptables -F iptables -X # 2. 放行本地回环,这条永远第一条 iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT # 3. 放行已建立连接和相关连接 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 4. 放行 ICMP(ping),按需可关 iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT # 5. 放行 SSH,建议限定来源网段 iptables -A INPUT -p tcp --dport 22 -s 203.0.113.0/24 -j ACCEPT # 6. 放行 Web 服务 iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT # 7. 设置默认策略(最后做!) iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT

这套规则读下来,逻辑是:回环必通 → 老朋友免检 → 必要服务放行 → 其余全拒。第 5 步限定来源网段是个好习惯,SSH 暴露在公网被爆破是常态,能限来源就限。如果 SSH 端口改过,记得把 22 换成实际端口。

执行完立刻验证:另开一个终端测试 SSH 能否连上、Web 端口是否可达、ping 是否通。验证这一步绝对不能省,规则写错导致服务不可达是家常便饭。确认无误后,再考虑持久化。

3.3 规则持久化:重启不丢才是真落地

iptables 的规则默认存在内存里,重启就没了。持久化方式因发行版而异,常见的有iptables-save配合iptables-restore,或者用iptables-persistent这类工具。核心思路就一句:把当前规则导出成文件,开机时再导回去。

# 导出当前规则 iptables-save > /etc/iptables/rules.v4 # 开机恢复(可写入启动脚本或对应服务的配置) iptables-restore < /etc/iptables/rules.v4

我习惯在每次改完规则、验证通过后立刻iptables-save一次,形成"改-测-存"的肌肉记忆。有次改完规则忘了存,第二天机器重启,加固全白做,那种感觉相当酸爽。

4. 实战排查:那些让人抓狂的典型问题

4.1 服务起来了却连不上,先怀疑防火墙

这是最高频的场景。服务进程在跑、端口在监听(ss -tlnp能看到),但外部就是连不上。排查顺序我总结成一条链:先看本机能不能连自己(curl 127.0.0.1:端口),能连说明服务没问题;再看防火墙规则有没有放行这个端口(iptables -L -n逐条看);最后看云厂商的安全组(如果是在云上)。这三层任何一层没放行,表现都是"连不上"。

有个细节容易被忽略:规则里的-i入接口写错了。比如机器有多块网卡,规则限定了-i eth0,但流量实际从eth1进来,那规则永远匹配不上。排查时用iptables -L -n -v看规则的包计数,如果某条本该命中的规则计数一直是 0,八成是匹配条件写错了。

4.2 常见问题速查表

现象可能原因排查与解决
改完规则 SSH 断了默认策略先于放行规则生效带外恢复,重来一遍注意顺序
转发流量不通规则挂错链或未开 ip_forward检查 FORWARD 链,确认net.ipv4.ip_forward=1
服务时好时坏conntrack 表满调大nf_conntrack_max,观察表使用率
规则不生效被其他管理工具覆盖检查是否有别的防火墙服务在跑
端口映射不工作nat 表规则链挂错DNAT 挂 PREROUTING,SNAT 挂 POSTROUTING
日志刷屏拖垮磁盘LOG 规则无限速加-m limit限速

4.3 几个我踩过的坑和私房技巧

坑一:DROP 和 REJECT 混用导致排查困难。早期我图省事全用 REJECT,结果对外服务被扫描时回了一堆拒绝包,反而暴露了端口存在。后来统一改成 DROP,扫描器扫过去一片"无响应",信息暴露少了很多。但内部排查时又希望有明确反馈,所以我的做法是:对外 DROP,对内网调试临时用 REJECT 并配合 LOG。

坑二:LOG 规则放错位置。LOG 是"记录但不拦截",匹配到 LOG 后会继续往下走。所以 LOG 规则要放在对应 DROP 规则的前面,才能记录到被拒的包。放后面就永远轮不到。而且 LOG 一定要限速,-m limit --limit 5/min是标配,否则被扫时日志能把磁盘写满。

技巧:用注释给规则打标签。-m comment --comment "allow-ssh-from-office"能给规则加备注,iptables -L时能直接看到。规则一多,没注释的规则集就是天书,过俩月自己都看不懂当初为啥这么写。

技巧:改规则前先备份。iptables-save > backup.rules,出问题一条iptables-restore < backup.rules回滚。这个习惯救过我无数次,尤其是批量改规则的时候。

5. 进阶场景:NAT 与端口转发

5.1 SNAT 与 DNAT 的区别与选择

NAT 这块,SNAT 改的是源地址,典型场景是内网机器共享一个公网出口上网;DNAT 改的是目标地址,典型场景是把公网请求转发到内网某台机器。两者方向相反,挂的链也不同:DNAT 在 PREROUTING(包刚进来就改目标),SNAT 在 POSTROUTING(包要出去时改源)。

做端口转发(比如把公网 8080 转到内网 80)用的是 DNAT:

# 开启转发 sysctl -w net.ipv4.ip_forward=1 # 公网 8080 转到内网 10.0.0.5 的 80 iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 10.0.0.5:80 # 放行转发流量 iptables -A FORWARD -p tcp -d 10.0.0.5 --dport 80 -j ACCEPT

这里有个高频遗漏点:只写了 DNAT 规则,忘了放行 FORWARD 链。DNAT 只改了目标地址,包还是要经过 FORWARD 链的过滤,FORWARD 默认 DROP 的话转发照样不通。这个坑几乎每个做端口转发的人都踩过。

5.2 内网共享上网的 SNAT 配置

内网机器通过一台网关机上网,网关机上配 SNAT:

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

MASQUERADE是 SNAT 的一种特殊形式,会自动把源地址改成出口网卡的地址,适合出口 IP 不固定的场景(比如拨号)。如果出口 IP 固定,用-j SNAT --to-source 公网IP性能更好,因为不用每次查网卡地址。同样别忘了ip_forward和 FORWARD 链放行。

提示:做 NAT 的机器,net.ipv4.ip_forward必须为 1,否则内核根本不转发包,规则写得再对也没用。这个参数是 NAT 和转发类场景的总开关。

6. 规则集维护与性能意识

6.1 规则顺序影响性能,别不当回事

iptables 是逐条匹配的,规则越多,每个包要过的"关卡"越多。一台高流量机器上堆几百条规则,性能损耗是实打实的。优化思路有两条:一是把命中率高的规则往前放(比如 ESTABLISHED 那条),让大部分包尽早命中;二是合并同类规则,用 multiport、ipset 这类工具减少规则条数。

ipset 是个好东西,把大量 IP 或网段存成一个集合,规则里引用集合名,匹配效率比逐条写高得多。比如要封禁几千个恶意 IP,用 ipset 一条规则搞定,而不是写几千条。这个在防大规模扫描、做黑名单时特别有用。

6.2 定期审计规则集

规则集是会"腐烂"的。临时加的调试规则、过期的放行、没人记得用途的条目,时间一长就堆成垃圾场。我习惯每隔一段时间做一次审计:iptables -L -n -v看每条规则的包计数,计数长期为 0 的规则要么删掉要么查清楚为什么没命中;对照业务梳理哪些端口还需要开放;把注释补全。

审计时特别关注那些"范围过大"的规则,比如-s 0.0.0.0/0全放行某端口,确认是不是真的需要全网开放。很多安全事故的根源就是一条图省事写下的宽泛规则。

6.3 关于这套东西的定位

iptables 这套工具能力很强,但它的规则语法确实不算友好,维护复杂规则集时容易出错。现在也有 nftables 这类新一代工具在逐步替代它,语法更清晰、性能更好。但 iptables 的存量极大,大量现网机器还在用,理解它的表链模型和匹配逻辑,对看懂任何一代 Linux 防火墙都有帮助——因为底层的 netfilter 框架是共通的,换的只是上层配置工具。

我个人在实际操作中的体会是:iptables 的难点从来不在语法,而在"想清楚数据包该走哪条链、规则该按什么顺序排"。把这两件事想明白了,剩下的就是查参数。每次改规则前问自己三个问题——这个包是给谁的、它走哪条链、我的规则会不会误伤自己,能避开绝大多数坑。最后再分享一个小习惯:任何一次规则变更,先在测试机或者用tmux会话里演练一遍,验证通过再上生产,这个习惯比任何技巧都值钱。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询