1. 项目概述为什么iptables依然是Linux网络安全的基石在今天的网络环境中无论你是运维工程师、开发者还是对服务器安全有要求的个人用户只要你的服务跑在Linux上防火墙就是你绕不开的一道坎。很多人一提到Linux防火墙可能会想到firewalld觉得它更现代、更友好。但如果你真的深入到生产环境、容器网络或者一些特定的网络调试场景你会发现那个看似“古老”的iptables依然牢牢占据着核心地位。它就像Linux内核网络栈里的“汇编语言”直接、强大理解它你才能真正掌控网络数据包的命运。我见过不少新手在配置了firewalld后遇到Docker网络不通、或者某些特定端口转发失效的问题查了半天才发现根源在于底层的iptables规则被其他工具比如Docker修改了而firewalld只是在前端做了一层管理。直接操作iptables能让你穿透表象直击问题的本质。这个项目就是带你从零开始彻底搞懂iptables命令配置防火墙规则的每一个细节。我们不只讲命令更要讲清楚每条命令背后的网络协议栈原理、数据包流向以及在实际操作中那些容易踩坑的地方。无论你是想保护你的Web服务器还是想搭建一个安全的网关或是解决容器网络的疑难杂症这套知识都能让你游刃有余。2. iptables核心架构与数据包流向解析要玩转iptables死记硬背命令是行不通的你必须先理解它的设计哲学。iptables不是一个单一的“墙”而是一个由表Tables、链Chains、规则Rules和目标Targets构成的精密规则框架。数据包就像旅客而iptables是海关表是不同职能的检查大厅链是检查流程中的不同关卡规则是具体的检查条目目标则是检查后的处置决定放行、扣留、遣返。2.1 四张核心表与它们的职责iptables默认内置了四张表每张表负责处理特定类型的数据包filter表这是最常用、也是默认的表。它的核心职能就是“过滤”决定一个数据包是允许通过ACCEPT还是拒绝DROP/REJECT。我们日常说的“配置防火墙规则”大部分工作都是在操作filter表。nat表负责网络地址转换。当你的服务器需要做端口转发DNAT、或者让内网机器通过本机共享上网SNAT时就需要用到这张表。Docker等容器工具也大量依赖nat表来管理容器网络。mangle表这张表用于对数据包进行“修饰”比如修改IP头部的TOS服务类型字段、给数据包打标记MARK以供后续处理。普通防火墙配置很少直接用到它但在高级路由策略如策略路由或流量整形中至关重要。raw表它的优先级最高作用是在连接跟踪conntrack机制处理数据包之前对数据包进行标记决定是否让该数据包进入连接跟踪系统。对于追求极致性能或需要绕过NAT连接跟踪的场景如高速转发会用到此表。注意不是所有链都存在于每张表中。例如filter表只有INPUT、FORWARD、OUTPUT链而nat表则有PREROUTING、POSTROUTING、OUTPUT等链。理解表和链的对应关系是正确配置规则的前提。2.2 五条关键链与数据包的生命周期链是规则的容器数据包会依次流经不同的链。理解数据包的流向是诊断网络问题的关键。我们以一个发送到本机服务的请求包为例PREROUTING链存在于raw、mangle、nat表这是数据包进入内核网络栈后遇到的第一个关卡。它发生在路由决策之前也就是说系统还不知道这个包是发给本机的还是要转发的。在这里通常进行的是DNAT目的地址转换比如将访问公网IP:80的包转发到内网服务器的192.168.1.100:8080。路由决策内核根据目标IP地址判断这个包是发给本机进程的INPUT路径还是需要转发给其他机器的FORWARD路径。INPUT链存在于mangle、filter表如果路由决策判定数据包是发给本机的那么它将流入INPUT链。在这里我们配置的绝大多数防护规则生效比如只允许特定IP访问SSH端口。本机进程通过INPUT链检查后数据包被递交给本机的相应应用程序如Nginx、SSHD。OUTPUT链存在于raw、mangle、nat、filter表当本机进程发出数据包时这些包会首先经过OUTPUT链。你可以在这里控制本机发出去的流量。POSTROUTING链存在于mangle、nat表这是数据包离开本机前的最后一道关卡发生在路由决策之后。这里主要进行SNAT源地址转换比如让内网机器通过本机网关上网时将内网源IP替换为网关的公网IP。FORWARD链存在于mangle、filter表如果路由决策判定数据包需要被转发即本机充当路由器或网关那么它将流过FORWARD链。这是实现内部网络隔离、或作为透明代理的关键链。一个简单的记忆口诀是PREROUTING最先POSTROUTING最后想过滤找INPUT和FORWARD要转发改地址找nat表。2.3 规则匹配与目标动作每条规则由两部分组成匹配条件Matches和目标动作Target。匹配条件用来筛选数据包。可以是源/目标IP-s, -d、协议-p tcp/udp/icmp、端口--sport, --dport、网络接口-i, -o、连接状态-m state --state NEW,ESTABLISHED等等。-m参数用于加载扩展模块以支持更复杂的匹配如-m multiport匹配多个端口。目标动作决定匹配的数据包命运。常见的有ACCEPT接受数据包允许其通过。DROP丢弃数据包没有任何回应。对客户端来说就像连接超时。REJECT拒绝数据包并返回一个错误响应如ICMP port-unreachable或TCP RST。对客户端更友好能立即知道被拒绝。LOG将数据包信息记录到系统日志如/var/log/messages或/var/log/kern.log然后继续匹配下一条规则。用于调试。SNAT/DNAT在nat表中进行地址转换。RETURN在当前链中停止匹配返回上一级调用链继续匹配。一个极其重要的原则规则是按顺序从上到下依次匹配的一旦匹配成功就执行对应的目标动作并停止后续匹配LOG目标除外。因此规则的顺序至关重要。通常我们把具体的、允许的规则放在前面把宽泛的、拒绝的规则如默认的DROP策略放在最后。3. 从零开始iptables基础命令与规则配置实战理论讲完我们上手操作。请确保你是在一个测试环境或已有安全连接如通过控制台的服务器上操作错误的规则可能导致你把自己关在门外。3.1 查看与清除现有规则在配置任何新规则前先看看现状。# 查看filter表的所有规则默认表就是filter所以-t filter可省略 iptables -L -n -v # -L: 列出规则 # -n: 以数字形式显示IP和端口不进行DNS反向解析速度更快 # -v: 显示详细信息如匹配的数据包计数和字节数 # 查看nat表的规则 iptables -t nat -L -n -v # 以更清晰的链结构查看规则推荐 iptables -S iptables -t nat -S如果系统已有一些规则或者你之前实验过建议先备份然后清空所有规则从一个干净的状态开始。# 备份当前规则到文件 iptables-save /root/iptables.backup.$(date %Y%m%d) # 清空所有表中的所有规则 iptables -F # 清空filter表规则 iptables -t nat -F # 清空nat表规则 iptables -t mangle -F iptables -X # 删除所有用户自定义的链 iptables -Z # 将所有链的计数器归零 # 设置默认策略非常重要 iptables -P INPUT ACCEPT # 先将INPUT链默认策略设为ACCEPT避免操作中断连接 iptables -P FORWARD ACCEPT iptables -P OUTPUT ACCEPT实操心得在生产服务器上千万不要一开始就把默认策略设为DROP。你应该先配置好允许的规则如SSH端口并确保当前会话不会中断最后再设置默认拒绝策略。一个安全的做法是写一个脚本或者使用iptables-apply工具它会在应用新规则后给你一个确认窗口如果超时未确认比如你被踢出去了会自动回滚到旧规则。3.2 配置一个基础的服务器防护规则集假设我们有一台Web服务器IP是192.168.1.10需要开放SSH22、HTTP80、HTTPS443端口并允许本机对外发起任何连接同时禁止其他所有入站访问。# 1. 设置默认策略INPUT链默认拒绝FORWARD和OUTPUT默认允许。 # 注意执行前请确保你已通过不会被阻断的方式如控制台连接服务器。 iptables -P INPUT DROP iptables -P FORWARD DROP iptables -P OUTPUT ACCEPT # 2. 允许本地回环接口(lo)的通信许多本地服务依赖它。 iptables -A INPUT -i lo -j ACCEPT # 3. 允许已建立的连接和相关的连接。这是关键它保证了对外请求的回应能回来。 iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # 4. 允许来自特定IP如管理机192.168.1.100的SSH连接。 iptables -A INPUT -s 192.168.1.100 -p tcp --dport 22 -m state --state NEW -j ACCEPT # 如果你想允许整个网段可以用 -s 192.168.1.0/24 # 5. 允许所有人访问Web服务80, 443。 iptables -A INPUT -p tcp --dport 80 -m state --state NEW -j ACCEPT iptables -A INPUT -p tcp --dport 443 -m state --state NEW -j ACCEPT # 6. 允许ICMP协议即ping便于网络诊断。出于安全考虑有些环境会关闭。 iptables -A INPUT -p icmp -j ACCEPT # 7. 可选记录被拒绝的尝试连接用于监控和调试。 iptables -A INPUT -j LOG --log-prefix IPTABLES-DROPPED: --log-level 4命令参数详解-A INPUT在INPUT链的末尾追加一条规则。-s 192.168.1.100匹配源IP地址。-p tcp匹配TCP协议。--dport 22匹配目标端口22。-m state --state NEW使用state扩展模块匹配新建的连接。-j ACCEPT跳转到ACCEPT目标即允许。现在使用iptables -L -n -v查看你的规则应该按配置的顺序排列。只有匹配到规则1-6的流量会被允许其他所有入站流量在匹配最后一条LOG规则如果配置了后将命中默认的DROP策略而被丢弃。3.3 规则的插入、删除与修改规则顺序错了怎么办我们需要学会管理规则编号。# 查看规则时显示编号 iptables -L -n --line-numbers # 假设我们看到INPUT链如下 # num target prot opt source destination # 1 ACCEPT all -- 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED # 2 ACCEPT tcp -- 192.168.1.100 0.0.0.0/0 tcp dpt:22 state NEW # 3 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:80 state NEW # 4 ACCEPT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:443 state NEW # 如果我们想在规则2SSH之前插入一条允许来自另一个IP 192.168.1.200的SSH规则 iptables -I INPUT 2 -s 192.168.1.200 -p tcp --dport 22 -m state --state NEW -j ACCEPT # -I INPUT 2 表示在INPUT链的第2个位置插入原有规则依次后移。 # 删除一条规则。可以通过匹配条件删除但更稳妥的方式是通过链名和编号删除。 iptables -D INPUT 3 # 删除INPUT链的第3条规则原来的允许80端口的规则现在变成了第4条 # 替换一条规则较少用通常删除后重插 # iptables -R INPUT 规则编号 [新的匹配条件] -j [目标]4. 高级应用场景与复杂规则配置掌握了基础我们来解决一些更实际、更复杂的问题。4.1 实现端口转发DNAT场景你的公网服务器IP是203.0.113.10内部有一台Web服务器192.168.1.100:8080。你想让用户访问203.0.113.10:80时流量被转发到内网服务器。# 1. 首先确保内核已开启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 80 -j DNAT --to-destination 192.168.1.100:8080 # 3. 由于转发后的包源IP还是客户端的内网服务器回包需要经过网关所以网关需要做SNAT或在POSTROUTING做MASQUERADE iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.100 -p tcp --dport 8080 -j SNAT --to-source 192.168.1.10 # 更常用的简化方法是使用MASQUERADE适用于动态IP或出接口IP不确定的情况 iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # 这条规则会让所有从eth0接口出去的、源地址是内网的包其源IP都被替换为eth0的当前IP。 # 4. 在filter表的FORWARD链中允许转发的流量 iptables -A FORWARD -d 192.168.1.100 -p tcp --dport 8080 -j ACCEPT iptables -A FORWARD -s 192.168.1.100 -p tcp --sport 8080 -j ACCEPT4.2 限制连接速率与防御简单洪水攻击使用limit和recent模块可以一定程度上缓解CC攻击或扫描。# 限制SSH每分钟最多接受3个新连接超过的将被丢弃 iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m limit --limit 3/min --limit-burst 3 -j ACCEPT # --limit 3/min: 平均每分钟不超过3个 # --limit-burst 3: 初始允许的突发连接数为3 # 使用recent模块防御ICMP洪水Ping洪水 iptables -N ICMP_FLOOD # 新建一个自定义链 iptables -A ICMP_FLOOD -m recent --set --name ICMP --rsource iptables -A ICMP_FLOOD -m recent --update --seconds 60 --hitcount 50 --name ICMP --rsource -j LOG --log-prefix ICMP_FLOOD: iptables -A ICMP_FLOOD -m recent --update --seconds 60 --hitcount 50 --name ICMP --rsource -j DROP iptables -A ICMP_FLOOD -j ACCEPT # 将ICMP流量导向自定义链处理 iptables -A INPUT -p icmp -j ICMP_FLOOD这段规则的意思是创建一个名为ICMP_FLOOD的链。当有ICMP包进来时将其源IP记录到“ICMP”列表。如果在60秒内同一个源IP发送了超过50个ICMP包则更新记录并执行DROP。否则接受。这比简单的-j DROP要智能。4.3 与Docker共存的iptables策略这是最常见的坑之一。Docker守护进程启动时会修改iptables规则插入自己的DOCKER、DOCKER-USER等链。这常常会与你自己配置的规则冲突导致端口不通。关键点Docker的规则通常被插入在FORWARD链的末尾并且其默认策略是DROP。如果你需要自定义容器网络的访问策略不要在FORWARD链里直接加规则而应该修改DOCKER-USER链。Docker保证在规则处理中DOCKER-USER链的规则会先于Docker自己的规则被执行。# 查看Docker创建的链 iptables -L -n | grep -i docker # 假设你想允许宿主机所在网络192.168.1.0/24访问所有容器的Web服务80端口 iptables -I DOCKER-USER 1 -s 192.168.1.0/24 -d 172.17.0.0/16 -p tcp --dport 80 -j ACCEPT iptables -I DOCKER-USER 2 -s 192.168.1.0/24 -d 172.17.0.0/16 -p tcp --sport 80 -j ACCEPT # 注意-d 地址是Docker容器的网段默认是172.17.0.0/16请根据实际情况调整。 # 如果你想完全禁止宿主机外网访问容器但允许宿主机本机访问可以 iptables -I DOCKER-USER 1 -i eth0 ! -s 192.168.1.0/24 -j DROP # 这条规则表示从外网接口eth0进来且源IP不是内网段的流量在DOCKER-USER链中直接丢弃。踩过的坑重启Docker服务或宿主机后Docker会重建自己的规则但DOCKER-USER链中的规则会被保留。然而你通过iptables命令手动添加的其他规则可能会丢失。因此所有iptables规则包括对DOCKER-USER的修改都必须有持久化机制。5. 规则持久化、管理与故障排查实录5.1 规则的保存与持久化通过命令行配置的规则仅存在于内存中重启就会消失。必须将其保存到文件并设置开机自动加载。# 保存当前规则推荐使用iptables-save它保存的是可被iptables-restore直接读取的格式 iptables-save /etc/iptables/rules.v4 # 对于IPv6使用 ip6tables-save /etc/iptables/rules.v6 # 在Debian/Ubuntu及其衍生系统上通常可以安装iptables-persistent包 sudo apt-get install iptables-persistent # 安装过程中会询问是否保存当前规则。之后规则会自动在启动时加载。 # 手动触发保存sudo netfilter-persistent save # 在RHEL/CentOS 7/8 及 Fedora 上 # 保存规则 iptables-save /etc/sysconfig/iptables ip6tables-save /etc/sysconfig/ip6tables # 启用服务firewalld可能与iptables冲突请先禁用firewalldsystemctl disable --now firewalld systemctl enable iptables systemctl start iptables # 注意该服务会从上述文件加载规则。 # 通用方法编辑 /etc/rc.local确保有执行权限在exit 0前加入 iptables-restore /etc/iptables/rules.v45.2 常见问题与排查技巧问题1配置完规则后SSH连接突然断开再也连不上了。原因极有可能INPUT链的默认策略被设为DROP而允许SSH的规则没有生效顺序错误、IP写错、端口写错或者没有配置-m state --state ESTABLISHED,RELATED -j ACCEPT这条“保命”规则。排查如果还有控制台访问立即检查规则顺序iptables -L -n --line-numbers。确保允许SSH的规则在默认DROP策略之前。检查是否允许了已建立连接iptables -L -n | grep ESTABLISHED。临时将默认策略改回ACCEPT在控制台操作iptables -P INPUT ACCEPT。然后仔细检查并修正你的规则。预防永远通过脚本或iptables-apply来应用可能阻断连接的规则集。脚本应首先刷新规则然后立即添加允许当前管理会话的规则例如从你的IP允许SSH再配置其他规则最后设置默认策略。问题2端口转发DNAT配置了但内网服务就是不通。排查步骤确认IP转发已开启cat /proc/sys/net/ipv4/ip_forward应为1。检查nat表规则iptables -t nat -L -n -v确认PREROUTING和POSTROUTING规则存在且计数器在增加。检查filter表FORWARD链iptables -L FORWARD -n -v。这是最容易被遗忘的一步必须允许数据包在FORWARD链中通过。确保有类似iptables -A FORWARD -d 内网IP -j ACCEPT和iptables -A FORWARD -s 内网IP -j ACCEPT的规则或者直接设置iptables -P FORWARD ACCEPT仅限测试环境生产环境应细化规则。检查内网服务器的网关内网服务器的默认网关必须指向这台做转发的Linux主机。使用tcpdump抓包在转发主机上抓包看包是否按预期到达和转发。tcpdump -i eth0 host 客户端IP and port 80 -n tcpdump -i 内网接口如eth1 host 内网服务器IP and port 8080 -n问题3Docker容器内的服务宿主机能访问但外部网络无法访问。原因大概率是iptables的FORWARD链策略被设为DROP或者Docker的规则被意外清除了。排查检查FORWARD链默认策略iptables -L FORWARD -n。如果第一行是Chain FORWARD (policy DROP)而Docker的规则没有允许转发就会导致问题。检查DOCKER和DOCKER-USER链iptables -L DOCKER -n和iptables -L DOCKER-USER -n。确保有允许流量转发到容器的规则。一个常见错误手动执行iptables -F会清空所有链包括Docker创建的但不会改变链的默认策略。Docker服务运行时它会重新插入部分规则但可能不完整。最稳妥的方法是重启Docker服务systemctl restart docker。Docker会重新配置它需要的iptables规则。根本解决避免在运行Docker的宿主机上随意清空iptables规则。如果必须修改优先操作DOCKER-USER链。问题4看到错误提示iptables: No chain/target/match by that name.原因你使用的模块如state、limit、recent没有加载到内核中。解决手动加载对应内核模块。modprobe ip_conntrack # 对于连接跟踪state模块依赖它 modprobe ipt_limit modprobe ipt_recent为了永久生效可以将模块名添加到/etc/modules-load.d/下的配置文件中。不过在大多数现代发行版中当iptables命令使用到这些模块时系统会自动尝试加载。5.3 性能优化与最佳实践规则顺序优化将最频繁匹配的规则放在链的前面。例如-m state --state ESTABLISHED,RELATED -j ACCEPT这条规则应该放在INPUT和FORWARD链的很靠前的位置因为大多数流量都属于已建立的连接这样能快速放行减少后续规则匹配的开销。使用IP集ipset处理大量IP如果你需要屏蔽成百上千个IP为每个IP写一条-s规则效率极低。应该使用ipset创建一个IP集合然后一条iptables规则引用这个集合。# 创建一个名为blocklist的IP集合哈希网络类型 ipset create blocklist hash:net # 向集合中添加要屏蔽的网段 ipset add blocklist 203.0.113.0/24 ipset add blocklist 198.51.100.0/24 # 在iptables中引用这个集合 iptables -I INPUT -m set --match-set blocklist src -j DROP尽量减少日志记录LOG目标-j LOG规则会生成大量内核日志在高流量环境下可能影响性能并塞满磁盘。仅在调试时使用并考虑使用--limit模块限制日志频率。明确拒绝而非全部丢弃对于明确的恶意流量使用-j DROP。对于需要告知客户端被拒绝的服务如向未知用户关闭的端口可以使用-j REJECT。将默认策略设为DROP但在链末尾添加一条-j REJECT --reject-with icmp-host-prohibited对于TCP/UDP或-j REJECT对于其他协议可以让网络扫描工具更快地知道端口被管理性关闭而不是超时。iptables的深度远超这一篇文章所能涵盖它涉及内核网络栈的方方面面。但掌握了以上核心概念、配置方法和排查思路你已经能够应对90%以上的日常防火墙配置需求。真正的熟练来自于实践和踩坑建议你在实验环境中多搭建几种网络拓扑进行测试。记住在操作生产服务器前备份规则和制定回滚方案是必须的仪式。