Linux防火墙基石:iptables四表五链架构与实战配置详解 📅 2026/7/5 14:16:02 1. 项目概述为什么iptables依然是Linux防火墙的基石在云原生和容器化大行其道的今天你可能听过很多关于新一代防火墙、云安全组、服务网格安全策略的讨论。但如果你深入到任何一台Linux服务器无论是物理机、虚拟机还是容器宿主机最终兜底的那个网络流量管控层十有八九还是iptables。这个诞生于Linux内核2.4时代2001年的工具至今仍是Linux网络安全事实上的标准。很多人觉得它命令行复杂、规则链抽象远不如firewalld或者一些Web管理界面直观。但我想说的是真正理解并掌握iptables是你从“系统使用者”迈向“系统掌控者”的关键一步。它让你能清晰地看到数据包在你服务器里的“行走路径”能精准地定位网络问题能实现从端口开放到复杂流量整形、从NAT转发到DDoS简易防护等一系列高级功能。更重要的是它是理解Kubernetes的kube-proxy、Docker的网络模型乃至众多云平台底层网络实现的基础。今天我就以一个老运维的视角带你从零开始彻底搞懂iptables并分享那些手册里不会写的实战技巧和踩坑经验。2. iptables核心架构与四表五链深度解析很多人学iptables一上来就记命令结果规则一多就晕了。我的建议是先花时间把它的“世界观”建立起来。iptables的核心是“表”Table、“链”Chain和“规则”Rule。2.1 四张表各司其职的规则容器你可以把“表”理解为不同用途的规则集合。iptables默认有四个内置表但最常用的是前三个filter表这是默认表也是最核心的表。它负责过滤数据包决定是放行ACCEPT还是丢弃DROP/REJECT。我们常说的“开防火墙端口”主要就是在操作这个表。nat表网络地址转换表。当你的数据包需要改变源或目标地址时就用到它。比如做路由器、做端口映射DNAT、让内网机器通过本机上网SNAT都离不开它。mangle表修改表。这个表功能强大且“危险”它可以修改数据包的内容比如修改TTL生存时间、设置MARK标记用于后续的路由或流量控制。一般初学者接触较少但在做策略路由、QoS时很有用。raw表原始表。主要用于配置数据包不被连接跟踪机制处理。在需要极高性能或者处理某些特殊协议如VPN时可能会用到。注意不是所有链都能挂载所有表。例如FORWARD链通常只用于filter表和mangle表而PREROUTING和POSTROUTING链主要用于nat表和mangle表。理解这个对应关系很重要。2.2 五条链数据包的必经关卡“链”是数据包传输路径上的检查点。数据包会像过安检一样依次经过这些链。五条内置链对应了数据包的生命周期PREROUTING链数据包刚进入网络接口网卡在路由决策之前。这里适合做DNAT改变目标地址和标记数据包。INPUT链数据包经过路由决策目标是本机例如SSH连接到这台服务器。我们保护服务器主要就是在INPUT链上设置过滤规则。FORWARD链数据包经过路由决策目标是其他机器本机充当路由器或网关。如果你的服务器开启了IP转发功能net.ipv4.ip_forward1就需要在这里管理转发的流量。OUTPUT链由本机进程产生的数据包在离开本机之前。POSTROUTING链数据包即将离开网络接口在路由决策之后。这里适合做SNAT改变源地址比如让内网机器共享一个公网IP上网。2.3 数据包流向全景图这是理解iptables的钥匙。一个数据包从进入网卡到离开其旅程如下来自外部目标为本机PREROUTING-INPUT-本机应用程序来自本机发往外部本机应用程序-OUTPUT-POSTROUTING来自外部穿越本机发往另一台外部主机本机是网关PREROUTING-FORWARD-POSTROUTING把这个流程图刻在脑子里。当你写一条规则时必须非常清楚我这个规则是想在数据包的哪个“人生阶段”链做什么“类型”的处理表比如你想做端口映射那是在数据包进入时、路由前改变它的目标地址所以你应该在nat表的PREROUTING链上写一条DNAT规则。3. iptables基础语法与规则管理实战理解了架构我们来看怎么操作。iptables命令的基本格式是iptables [-t 表名] 命令选项 链名 匹配条件 -j 目标动作-t 表名指定操作哪张表省略时默认为filter表。命令选项告诉iptables你要做什么比如添加-A、插入-I、删除-D、查看-L等。链名指定操作哪条链。匹配条件用来筛选数据包比如源IP、目标IP、协议、端口等。-j 目标动作匹配后执行的动作如ACCEPT接受、DROP丢弃无响应、REJECT拒绝返回拒绝包、DNAT、SNAT等。3.1 规则管理核心命令查看规则这是最常用的命令之一。# 查看filter表所有链的规则默认就是filter表 iptables -L -n # 加上-v查看更详细信息数据包和字节计数 iptables -L -n -v # 查看nat表规则 iptables -t nat -L -n -v # 以更清晰的格式、带行号查看便于后续删除 iptables -L -n --line-numbers添加规则# 在INPUT链末尾添加一条规则允许来自192.168.1.0/24网段的TCP流量访问本机22端口 iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT # 在INPUT链开头插入一条规则优先级最高允许本地回环接口(lo)的所有流量 iptables -I INPUT 1 -i lo -j ACCEPT实操心得-A是追加到链尾-I是插入到指定位置不指定位置则默认为链首。防火墙规则是从上到下顺序匹配的第一条匹配到的规则就会生效后面的不再检查。所以通常会把允许的、范围精确的规则放在前面把拒绝的、范围宽泛的规则如默认策略放在最后。-i lo -j ACCEPT这条规则务必放在最前面很多本地服务如MySQL、Redis本地连接依赖回环接口如果被误拦排查起来很头疼。删除规则# 方法1通过完整的规则描述来删除必须和添加时完全一致 iptables -D INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT # 方法2推荐通过链名和行号删除先用--line-numbers查看 iptables -D INPUT 3修改链的默认策略 链的默认策略Policy是指当数据包不匹配任何一条规则时采取的动作。# 将INPUT链的默认策略设置为DROP严格安全模式 iptables -P INPUT DROP # 将FORWARD链的默认策略设置为ACCEPT在作为网关时常用 iptables -P FORWARD ACCEPT重要警告在远程连接如SSH的服务器上千万不要直接执行iptables -P INPUT DROP除非你已经提前在INPUT链里添加了允许SSH的规则。否则你会立刻断开连接并再也连不上去正确的做法是先添加允许规则再设置默认拒绝策略。清空所有规则与计数器# 清空指定表所有链的规则 iptables -F # 清空nat表所有规则 iptables -t nat -F # 删除所有用户自定义的链 iptables -X # 将所有链的包和字节计数器归零 iptables -Z3.2 常用匹配条件详解匹配条件是规则的灵魂决定了规则作用的范围。基于网络接口-i eth0 # 数据包进入的网卡是eth0仅用于PREROUTING, INPUT, FORWARD链 -o eth1 # 数据包出去的网卡是eth1仅用于FORWARD, OUTPUT, POSTROUTING链基于IP地址-s 192.168.1.100 # 源IP地址 -s 192.168.1.0/24 # 源IP网段 -d 10.0.0.1 # 目标IP地址 ! -s 192.168.1.100 # 非192.168.1.100的源IP感叹号表示取反基于协议和端口-p tcp # TCP协议 -p udp # UDP协议 -p icmp # ICMP协议如ping --dport 80 # 目标端口常用 --sport 1024:65535 # 源端口范围 -p tcp --dport 22:25 # 目标端口范围22到25 -p icmp --icmp-type 8 # 匹配ping请求type 8基于连接状态state这是iptables最强大的特性之一实现了“有状态检测”。-m state --state RELATED,ESTABLISHED -j ACCEPTNEW新建连接的第一个包。ESTABLISHED已建立的连接。RELATED与已有连接相关的连接如FTP的数据连接。INVALID无效的包。 这条规则的含义是允许所有属于已建立连接或相关连接的数据包通过。把它放在允许规则的开头可以极大地简化规则集。因为一旦内网主机主动发起一个对外请求比如浏览网页其回来的流量状态就是ESTABLISHED会被这条规则直接放行而无需为每个服务单独设置回包规则。4. 经典实战场景配置指南光说不练假把式下面我们通过几个最常见的场景把上面的知识串联起来。4.1 场景一配置一台安全的Web服务器假设你有一台公网服务器IP: 203.0.113.10上面运行着Nginx80/443端口和SSH服务22端口。你需要允许所有人访问Web服务但只允许来自办公室IP例如 198.51.100.0/24的SSH连接。配置思路清空旧规则设置默认策略。允许本地回环。允许状态为ESTABLISHED,RELATED的包这是关键。允许访问80和443端口。允许来自特定IP段的SSH连接。拒绝其他所有入站流量INPUT链默认策略设为DROP。允许所有出站流量OUTPUT链默认策略设为ACCEPT通常服务器主动对外访问是需要的。操作步骤# 1. 设置默认策略先设ACCEPT防止被踢生产环境请谨慎 iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT # 2. 清空所有规则 iptables -F iptables -t nat -F iptables -t mangle -F # 3. 允许本地回环 iptables -A INPUT -i lo -j ACCEPT # 4. 允许已建立和相关连接至关重要 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 5. 允许HTTP和HTTPS iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT # 6. 允许来自办公室IP段的SSH iptables -A INPUT -s 198.51.100.0/24 -p tcp --dport 22 -j ACCEPT # 7. 配置默认策略 iptables -P INPUT DROP # 不匹配以上规则的入站流量全部丢弃 iptables -P FORWARD DROP # 不转发任何流量 iptables -P OUTPUT ACCEPT # 允许所有出站流量 # 8. 保存规则根据发行版不同 # CentOS/RHEL 6: service iptables save # CentOS/RHEL 7/Ubuntu: 需要安装iptables-persistent或使用其他方法见下文“规则持久化”章节。现在你的服务器只开放了80、443端口并且22端口只对办公室IP开放其他所有入站连接都会被静默丢弃DROP安全性大大提升。4.2 场景二实现端口转发DNAT你的服务器有公网IP203.0.113.10内网有一台IP为192.168.1.100的机器上面运行着Web服务80端口。你想让外网用户访问203.0.113.10:8080时流量被转发到内网的192.168.1.100:80。配置思路在nat表的PREROUTING链上做DNAT改变目标地址和端口。因为数据包是“穿过”本机目标不是本机所以还需要filter表的FORWARD链允许该流量通过。确保服务器已开启IP转发功能。操作步骤# 1. 开启Linux内核的IP转发功能临时生效 echo 1 /proc/sys/net/ipv4/ip_forward # 永久生效编辑 /etc/sysctl.conf设置 net.ipv4.ip_forward 1然后执行 sysctl -p # 2. 在nat表的PREROUTING链添加DNAT规则 iptables -t nat -A PREROUTING -d 203.0.113.10 -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.100:80 # 3. 在filter表的FORWARD链允许此转发流量根据需要细化规则 # 允许从外网接口到内网接口的转发 iptables -A FORWARD -d 192.168.1.100 -p tcp --dport 80 -j ACCEPT # 允许从内网返回的流量 iptables -A FORWARD -s 192.168.1.100 -j ACCEPT # 4. 可选如果内网服务器需要主动访问外网还需要做SNAT伪装 iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE # MASQUERADE是SNAT的一种自动形式适用于动态获取公网IP的情况如家庭宽带、拨号上网。完成以上设置后外网访问http://203.0.113.10:8080的请求就会被透明地转发到内网的Web服务器上。4.3 场景三限制连接速率与防简单CC攻击iptables不仅可以做静态的允许/拒绝还能通过limit和recent模块实现简单的流量整形和攻击防护。示例1限制SSH每分钟最多连接3次新连接超过则拒绝# 使用limit模块限制速率 iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m limit --limit 3/min --limit-burst 3 -j ACCEPT iptables -A INPUT -p tcp --dport 22 -m state --state NEW -j DROP--limit 3/min平均每分钟最多允许3个新连接。--limit-burst 3初始的“令牌桶”容量为3允许短时间内突发连接。第一条规则符合速率限制的新连接被接受。第二条规则超出速率限制的新连接被丢弃。示例2使用recent模块防止对Web端口的暴力访问# 创建一个“黑名单”60秒内对80端口发起超过10次新连接的IP将被加入黑名单并拒绝5分钟 iptables -N HTTP_FLOOD # 新建一个自定义链 iptables -A HTTP_FLOOD -m recent --set --name BADGUY --rsource iptables -A HTTP_FLOOD -m recent --update --seconds 300 --hitcount 1 --name BADGUY --rsource -j DROP iptables -A HTTP_FLOOD -j ACCEPT # 在INPUT链中引用这个自定义链 iptables -A INPUT -p tcp --dport 80 -m state --state NEW -m recent --update --seconds 60 --hitcount 10 --name BADGUY --rsource -j DROP iptables -A INPUT -p tcp --dport 80 -m state --state NEW -j HTTP_FLOOD这个规则集稍微复杂一些但效果很好。它记录了每个IP在60秒内对80端口新建连接的次数超过10次就将该IP标记为“BADGUY”并在接下来的300秒内直接丢弃其所有到80端口的新连接。这能有效缓解简单的CC攻击或扫描器。5. 高级技巧与性能优化5.1 规则的优化与排序规则顺序直接影响性能。iptables是线性匹配所以最常用的规则放前面比如那条-m state --state ESTABLISHED,RELATED -j ACCEPT应该放在很靠前的位置因为服务器上大部分流量都是回包。匹配范围最小的规则放前面比如“允许某个特定IP访问SSH”的规则应该放在“允许整个网段访问SSH”的规则前面。使用多端口匹配减少规则数量。# 不推荐为每个端口写一条规则 iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT iptables -A INPUT -p tcp --dport 8080 -j ACCEPT # 推荐使用multiport模块 iptables -A INPUT -p tcp -m multiport --dports 80,443,8080 -j ACCEPT5.2 连接跟踪conntrack的坑与解决state模块依赖内核的conntrack连接跟踪表。这个表有大小限制。在高连接数的服务器如负载均衡器、NAT网关上可能会遇到conntrack table full的错误导致新连接无法建立。查看当前状态cat /proc/sys/net/netfilter/nf_conntrack_count当前连接数cat /proc/sys/net/netfilter/nf_conntrack_max最大限制。调整最大值编辑/etc/sysctl.conf增加net.netfilter.nf_conntrack_max 655350或更大然后sysctl -p。调整超时时间对于某些协议可以缩短连接跟踪的超时时间让条目更快释放。例如在/etc/sysctl.conf中设置net.netfilter.nf_conntrack_tcp_timeout_established 1200将ESTABLISHED状态的TCP连接超时从默认的5天改为1200秒。5.3 规则持久化让配置在重启后依然生效这是新手最容易踩的坑。用iptables命令配置的规则是保存在内存中的重启服务器就会丢失。CentOS 6 / RHEL 6使用service iptables save命令规则会保存到/etc/sysconfig/iptables。CentOS 7 / RHEL 7默认使用firewalld。如果你想继续用iptables需要先禁用firewalld安装iptables-services。systemctl stop firewalld systemctl disable firewalld yum install iptables-services -y systemctl start iptables systemctl enable iptables # 配置好规则后使用以下命令保存 service iptables save # 或 /usr/libexec/iptables/iptables.init saveUbuntu / Debian安装iptables-persistent包。apt-get update apt-get install iptables-persistent -y # 安装过程中会询问是否保存当前规则。之后每次用iptables命令修改规则后需要手动保存 netfilter-persistent save # 或 iptables-save /etc/iptables/rules.v4 ip6tables-save /etc/iptables/rules.v66. 故障排查与日常维护命令当网络不通时按以下思路排查iptables查看所有规则和计数器iptables -L -n -v。重点看对应链的包计数pkts和bytes如果某个拒绝规则的计数器在增长说明有流量被它挡住了。查看NAT规则iptables -t nat -L -n -v。查看规则顺序iptables -L -n --line-numbers。临时放行所有流量进行测试危险仅在测试环境或确定影响后操作iptables -P INPUT ACCEPT iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT iptables -F iptables -t nat -F如果此时网络通了问题就在iptables规则上。然后一条条规则加回去直到问题复现。使用日志记录被拒绝的包在关键的DROP规则前插入一条LOG规则帮助定位。# 记录被丢弃的SSH新连接尝试日志前缀为“SSH-DROP” iptables -I INPUT 5 -p tcp --dport 22 -m state --state NEW -j LOG --log-prefix SSH-DROP: 日志默认会输出到/var/log/messages或/var/log/kern.log你可以用tail -f命令实时查看。7. 从iptables到nftables未来的方向虽然iptables依然强大但Linux社区已经推出了它的继任者nftables。从Linux内核3.13开始引入旨在替代iptables/ip6tables/arptables/ebtables等一系列工具提供统一的配置框架和更高效的性能。它的语法更简洁规则集处理效率更高。主流发行版的新版本都已支持。例如在CentOS 8/RHEL 8上iptables命令只是一个兼容层底层已经是nftables了。学习nftables是未来的趋势但理解iptables的概念表、链、规则、状态跟踪对于学习nftables有巨大的帮助因为核心思想是相通的。当你彻底玩转了iptables再去看nftables的语法会有一种“豁然开朗”的感觉。iptables就像Linux系统工程师的一把瑞士军刀看起来其貌不扬但用熟了几乎能解决所有网络层面的管控问题。它的价值不在于界面有多花哨而在于给你了对网络数据包最底层的、最直接的控制力。这份控制力是构建稳定、安全、可调试的服务器环境的基石。希望这篇长文能帮你把这把刀磨得更亮一些。