理解 iptables:你真正需要掌握的不是规则,而是数据包的流向
本文最后更新于 168 天前,其中的信息可能已经有所发展或是发生改变,如有失效可到评论区留言。
文章摘要
文章通过真实VPS被攻击案例揭示传统iptables教程的局限性,指出单纯记忆规则无法应对实际问题。核心在于理解数据包在内核中的完整路径:从PREROUTING到FORWARD再到INPUT的流转逻辑,以及Docker、Kubernetes等系统在不同链插入规则的协同机制。作者强调,正确配置需基于流量路径认知,而非机械堆砌命令,通过分析真实事故(如Docker端口映射绕过INPUT链)与系统交互原理,最终实现精准控制防火墙策略,避免因规则位置错误导致的安全漏洞。
Qwen3-14B · 2026-06-18

1 前言

其实我很早就想写一篇关于 iptables 的文章,因为虽然平时用不上,但是每次真正需要用到的时候总是发现相关知识点被忘得干干净净,又要从头来看一遍,这就是学习某个知识点而没有通过写作强化记忆的悲催下场。

但为什么一直想写,又总是下不了决心动笔呢?原因也很简单:iptables 的文章真的很难写。一不小心就会写成网上那种“使用手册式”的教程,堆一堆链、表、规则,读的时候云里雾里,看完脑袋全是浆糊——我之前就是这样,被各种解释绕得没方向。

所以悲剧也就发生了——我刚买 Racknerd 芝加哥 VPS的时候,原本把安全策略规划得非常清晰:只开放两个高位端口(密钥登录的 SSH 和 Transmission),所有入向请求全部drop,管理所有内部服务都走 tailscale IP,看起来固若金汤。所以我的mairadb的数据库用户名和密码都直接用了最简单的(wordpress/wordpress),毕竟VPS没对外开放3306的端口,随便用什么都安全,结果第二天,mariadb 的 wordpress 库就被删了,这脸真被打肿了~~~。

排查之后发现罪魁祸首是一个不起眼的 docker 创建参数:-p 3306:3306。就是这么随手一敲,直接把数据库暴露给了全世界。那一瞬间我整个人都不好了:我明明把系统级防火墙锁得死死的,为什么 docker 能轻松绕开?

直到那时我才真正意识到——我以为自己懂 iptables,其实只是懂了些“命令”,但完全没有理解流量到底是怎么走、为什么会这样、系统和 docker 在背后悄悄做了什么。

传统的 iptables 教程最大的问题也就在这里:它会告诉你有哪些表、有哪些链、各种规则是什么意思,但它不会告诉你发生事情的顺序,也不会告诉你真正影响实际行为的是“流量路径”。

比如:包是从哪里进来的?先经过哪个链?哪些规则是系统自带的?哪些是 docker 暗搓搓插进去的?为什么辛苦写的 DROP 根本没有机会生效?

这些东西传统教程都默认你“自己会理解”,但现实是大多数人根本不会,就像当时的我一样——docker 在宿主机上自动加了一条 DNAT,把外网的 3306 转发进来,再配上一条 ACCEPT,我的输入防火墙等于完全被绕开。我原本自信满满的“无懈可击”安全方案,实际上根本没跑到 Docker 插的规则前面。

这次事故让我彻底意识到:iptables 根本不是一个“命令工具”,而是一张“流量路由图”。真正重要的不是你写了哪些规则,而是数据包到底是按照什么顺序经过这些链的。如果你不理解这条路,你就不可能真正控制防火墙。

所以这篇文章,我想换一种更适合普通人、也是更符合我自己大脑逻辑的写法:从真实事故、真实需求出发,讲清楚 iptables 的流量路径,让人能把它当作一张脑海里的地图,而不是堆在桌上的一本说明书。

我希望读完后会有一种“原来如此怪不得之前总觉得一知半解”的感觉。而对我自己来说,这篇文章也是一种“把知识彻底放进长期记忆里”的方式,避免再发生一次靠运气防火墙的事故。

2 为什么传统的iptables教程让人学不懂?

如果你在网上找过 iptables 教程,你大概会有同样的体验:文章通常写得非常详细,讲四个表、五条链、每个参数都解释得清清楚楚,看起来内容相当充实,但看完之后脑子里依然是一团糊。你记住了 INPUT、FORWARD、OUTPUT 的名字,知道 PREROUTING 是个什么东西,也隐约知道 NAT、Filter、Mangle 各负责什么,可真正要配置防火墙的时候,你依旧会在第一行就开始迷糊。

你会问自己:为什么我写了 DROP,包却没有被 DROP?为什么我以为 INPUT 是第一道防线,但 Docker 仿佛可以直接从背后开门进来?为什么我照着教程敲命令,结果行为跟教程解释的完全不一样?当初的我也一样困惑。

问题并不是你不够聪明,也不是你不够努力。而是大多数 iptables 教程,从出发点上就“教反了”。它们会先告诉你“世界上有四张表”,再告诉你“每张表里有哪些链”,然后一通讲参数和语法,让你觉得似乎自己已经掌握了大部分内容。可实际上,这些内容不过是固定结构的一堆名词,它们并不能解释系统为什么会做某件事,也不能让你理解真实世界的网络流量到底是怎么走的。

这就像有人在教你开车时,非常耐心地告诉你方向盘是什么、油门是什么、刹车是什么,却完全不告诉你马路是怎么规划的、车流是怎么走的、哪些路口有优先权、哪些路段是单行道。你知道了所有车辆的零件,但你还是不会开车,因为你不知道车在道路中真正的行为逻辑。

iptables 最大的问题正是如此:它不是“命令合集”,而是一套“流量路由体系”。它处理的并不是命令,而是数据包。数据包像车一样,从入口进来、经过几条“主干道”、被转进某个“支路”、可能被检查、可能被放行、可能被改变目的地。你的规则只是放在这些路口的一块牌子。你不知道路口的顺序,就永远不知道你的牌子是不是放在了没人会经过的地方。

传统教程往往避而不谈这一点,它们告诉你 INPUT 是拦截入站包的地方,于是你自然会把 INPUT 当成“第一道门”。然而在真实系统里,数据包在到达 INPUT 之前,已经经过了一些其他地方,比如 PREROUTING,而 Docker 就是悄悄在这些“你不知道的地方”插入了自己的跳转规则。到你看到 INPUT 的时候,一切早已尘埃落定。

更要命的是,大多数教程根本不会告诉你系统本身也会动态生成一些规则。这意味着你以为自己写的 DROP 是“最顶层”,但实际上系统早就在你前面插入了几条 ACCEPT,把你辛苦写的规则摆在了无人经过的角落。你以为是自己写错了,其实是从第一步开始就站在了错误的位置。

这也是为什么即使你知道什么是表、什么是链、什么是 -A 和 -I,你依旧会发现自己完全无法预测 iptables 真实行为——因为你永远没有被告知整个世界是如何运转的。

所以与其说传统教程难学,不如说它们根本没有从“正确的入口”进入这个知识体系。iptables 的世界必须从“流量的路径”开始理解,从“数据包是如何走过系统”开始理解,而不是从名词的堆叠开始。名词没有意义,路径才有意义。顺序没有搞清楚,规则永远都只是空谈。

这篇文章,我希望重新把讨论拉回正确的方向。不是讲概念,不是背命令,而是先建立那张你脑子里必须要有的“流量地图”。只有理解那张地图,你才能真正理解 iptables,理解为什么 Docker 能绕过 INPUT,理解为什么你写的规则会失效,也理解为什么事故会发生。

从这一章开始,我们要做的,就是把所有“雾气”吹散,让你第一次看到 iptables 的全貌,而不是一堆散落在桌面上的零件。

3 数据包在内核里的那条“路”


在正式开始本章的内容之前,有一件事必须强调,因为如果这件事没搞明白,后面所有的链、表、hook 点全都会看得稀里糊涂,那就是:iptables 其实并不负责“处理”任何数据包。

它更像是一个“管理员的遥控器”:你用它敲几条命令,它就把规则写进内核;真正拦包、放包、做 NAT、做连接跟踪的,其实都是 Linux 内核里的 netfilter 在干。

所以,无论你用的是 iptables、nftables、还是 firewalld,本质上都是:用户空间(你) → 发指令 → 内核空间(netfilter) → 内核运行真实的流量处理逻辑

你看到的那些 INPUT、FORWARD、PREROUTING、POSTROUTING,其实不是 iptables 的“流程”,而是 netfilter 在内核里的几个关键节点,iptables 只是把规则塞进这些节点里而已。

其实真正让人被 iptables 绕晕的,从来不是命令没记住,而是脑子里没有一条清晰的“数据包在内核里怎么移动”的路线图。你不知道它什么时候会停一下,在哪个 hook 被处理,什么时候会绕过你的规则,什么时候又会被 Docker、NAT、FORWARD 这些机制截胡。所以你看得懂命令,却看不懂 Linux 到底在对你的流量做什么。

我当初在 VPS 上被 Docker 的 DNAT 坑,也是因为这个:我以为一个外部请求一定会“先进 INPUT”,然后才有机会被 Docker 映射;但 Linux 实际上是先走到 PREROUTING(nat 表),而 Docker 正是悄悄在这里插入了 DNAT。也就是说,Docker 的修改发生在我所有 INPUT 规则之前——这和我脑子里的流程完全不一样。

这就是为什么“懂路径”远比“懂命令”重要。因为命令会忘,但路线不会变;路线一旦通透,所有链、表、规则都变得顺理成章。


如果只能选一张图,让你一眼看懂 Linux 在内核里怎么处理一个数据包、以及 iptables、netfilter、NAT、Docker 的链路到底插在什么位置,那就是你现在看到的这一张——它展示的是整个”Linux内核网络栈”的流程,只不过我们会用 iptables 的链作为参考坐标来讲解:

image.png

接下来,我们就从这张图开始,让它带着你一路追踪数据包——从进入网卡的那一刻,到被本机接收、被容器转发,或者重新被送回网络。你会发现:一旦理解它的行走路线,iptables、netfilter、NAT、Docker,甚至之后的 nftables,都不再神秘。


从 NIC 到 PREROUTING:第一站,是所有一切的入口

所有外面来的访问,无论是你访问的网页,还是攻击者扫你的端口,它们通通先进网卡,然后直冲图上左边的 PREROUTING

这里会按顺序经过:raw、mangle、nat(这里最关键),你可以把 PREROUTING 想象成“真正的第一道大门”。你以为 INPUT 才是防火墙的第一站?那是很多人的误解。

真正的第一站,是 PREROUTING。大量网络黑魔法都发生在这里——特别是 DNAT(端口映射)。我那天的事故,就是因为 Docker 在这里添加了:

DNAT --dport 3306 → 容器内部端口

所以攻击者在扫 3306 时,根本没走到我精心写好的 INPUT 链,它们早就在 PREROUTING 被 Docker 牵到容器里去了。

这段的意义是:如果你不理解 PREROUTING,就永远解释不了为什么 INPUT 链设置得再漂亮也没用。


Destination 为本机?还是要转发?图中这一小块就是整个 iptables 的大分岔点

图里有一个红色的菱形写着:“Destination 为本机”,这是一切路由行为的分界线:如果给的是你 VPS 的 IP → Y → 进入 INPUT;如果给的不是你本机 → N → 去 FORWARD

就是这么简单的一条判断,却导致很多人永远搞不懂:为什么 Docker 流量不进 INPUT?为什么 Kubernetes 的 Service NAT 走 FORWARD?为什么 VPS 上端口映射可以绕过你的 INPUT?为什么虚拟网桥 br0、docker0 的包都跑到 FORWARD 去?

如果你脑中一直只有“INPUT=入站”“OUTPUT=出站”这些字面理解,那这些问题没办法真正理解。

但一旦看到这张图,你马上就知道:Docker 网络不是“来访问我的主机”,它是在访问由 docker0 网桥转发出去的内部网络,自然走 FORWARD。


走 Y 的分支:进入真正的“本机防火墙”——INPUT

如果包确实是打向你 VPS 的 IP,它就会走向图中上方的 INPUT。

在 INPUT 中,它会按照顺序经过:mangle(一般不用管)、filter(大部分人在这里写 DROP),这一段才是传统意义上的“VPS 防火墙规则区”。

如果你想把某个端口封死、限制某个 IP、禁止某个协议,就是在这里做文章。但现在很明确的是:INPUT 是第二道门,不是第一道。

所以它能过滤到的东西,前提是:必须没有在 PREROUTING 就被改地址把“目的地址改走”,之前我踩坑的原因就在这里。

走完 INPUT 后,包就已经进入内核应用层,再往上就是进程本身,比如 sshd、nginx 或 docker-proxy。


走 N 的分支:不是打我的?那就转发——FORWARD 链登场

如果目的地址不是你本机 IP,那么包会进入图中右边的 FORWARD。

这里也是:mangle、filter

Docker、容器网络、Kubernetes、路由器转发、旁路由……这些全都走这一段。

这也是为什么 Docker 会在 FORWARD 里插入:DOCKER、DOCKER-USER,而且它是在 FORWARD 的最前面插入,所以具有强制优先级。

当你理解这张图,你马上就明白:任何容器流量(包括‘-p 3306:3306’)都会提前走 Docker 写的 PREROUTING 和 FORWARD,不会走 INPUT。

这就是“没办法用 INPUT 把容器保护起来”的本质原因。


从本机出去的包:OUTPUT → POSTROUTING

如果你的程序发一个请求出到公网,它会从图中上方的 output 路径走下来。流程是:output(raw → mangle → nat → filter)→ POSTROUTING (mangle → nat)→ NIC → 出口

这一段通常比较安静,因为大部分人不会在 OUTPUT 设置规则。但如果你想理解 SNAT / MASQUERADE,这就是发生的地方。

短句记忆就是:DNAT 在前(PREROUTING),SNAT 在后(POSTROUTING)。

Docker 的桥接网络转发出去时,会在 POSTROUTING 这里执行 MASQUERADE。


走完图之后,你就真正理解了 iptables

这张图其实就是 iptables 的“人体解剖图”。任何命令写得再复杂,只要你能回答一句:它是在图中的哪一段被执行?那你就永远不会迷路。

现在你也知道:

  • INPUT 确实不是第一站
  • PREROUTING 才是影响 Docker、端口映射、反向代理的关键路径
  • FORWARD 是所有“网桥/容器/路由转发”的主战场
  • POSTROUTING 是 SNAT 的必经之路
  • OUTPUT 是本机程序发出的包才会经过
  • 本机与非本机的“二分法”,直接决定 INPUT 和 FORWARD 的分流

一句话总结这章:别背 iptables,走一遍这张图,就懂了。

4 所谓的“4 表 5 链”,其实都是路线图上的功能区

很多人学习 iptables 最容易卡住的地方不是命令,而是那一堆听起来就让人头大的名词:什么 filter 表、nat 表、mangle 表、raw 表,以及 INPUT、OUTPUT、FORWARD、PREROUTING、POSTROUTING 这些链。大部分教程喜欢上来就把这些术语一股脑扔给你,然后说“iptables 就是由这些组成的”。但问题是,在你脑子里还没有“数据包怎么在内核里走”的路线图时,这些名字就像一本陌生工具书里的章节名,完全没有直觉意义,只会越看越糊涂。

要真正理解它们,你必须先意识到一个非常关键、但常常被忽略的事实:链并不是独立存在的,链永远隶属于表。 你看到的不是抽象的“PREROUTING 链”,而是 nat 表里的 PREROUTING,mangle 表里的 PREROUTING,raw 表里的 PREROUTING。


值得强调的是,所谓的“4 表 5 链”只是 iptables 的默认起点,而不是完整形态 ——它们更像是一张预先画好的路线图骨架,告诉你数据包在内核里大致会经过哪些节点,但并不意味着这些节点里只有你写的规则。实际上,iptables 的表和链本身就是可扩展的结构,系统和应用都可以在这些默认位置之下继续细分逻辑、插入跳转、构建自己的处理流程。

因此,当你真正查看一台正在运行的服务器时,看到的往往不是“干净的 4 表 5 链”,而是一张被不断补充、拆分、延伸后的真实流量路径图。理解这一点的意义不在于记住多了哪些链,而在于建立一个正确的直觉:iptables 描述的不是静态规则表,而是一个可被持续编辑的流量处理框架。


理解这一点非常重要,因为它能帮你在一开始就建立正确的直觉:iptables 不是一张静态表单,也不是一个死板的概念体系,而是一套会被系统和应用共同编辑的“流量路由图”。你要读懂的不是名词,而是数据包真正的行走路线;不是死记表链,而是理解它在不同节点应该被谁接手、执行什么操作。

如果你把 Linux 内核处理流量想象成一栋分工非常细致的政府大楼,理解会轻松很多。大楼里有四个大厅(四张表):raw 负责最原始的登记,mangle 负责修改元数据,nat 负责地址变更,filter 负责最终放行审批;每个大厅里设置了一些柜台(链),用于处理“从哪里来的流量要到哪个柜台过一下”。规则,就是你贴在柜台上的“如果发生 X,就执行 Y”的具体动作。

而更容易被忽略的一点是:每个表里有的链并不一样,它们不是对称的。

比如 raw 表只有 PREROUTING 和 OUTPUT,因为最原始的登记只会发生在流量进大楼那一刻,以及流量由本机内部发出的时候;nat 表天然需要在 PREROUTING(DNAT)、OUTPUT(本机发起流量的 DNAT)、POSTROUTING(SNAT)三处设置柜台;filter 表只关注 INPUT、FORWARD、OUTPUT,因为“要不要放行”只在这三个场景需要判断;而 mangle 表因为修改元数据,用到的场景非常广,在五个链里它几乎都有存在:

image.png

如果你把每个表视作不同业务部门,把每个链看成大厅里的柜台,这种分布就不再抽象,而是顺理成章。更重要的是:这四个表之间本身还有顺序,优先级是写死的。 raw → mangle → nat → filter,就是 Linux 处理一个数据包的顺序:必须先登记(raw),再改元数据(mangle),再处理地址(nat),最后决定是否放行(filter)。

你想在 filter 里做 DNAT?做不了;你想在 nat 里跳过连接跟踪?那是 raw 的活;你想在 mangle 里做最终放行判断?那属于 filter。

流程顺序决定了规则能放在哪、会不会生效。这就是为什么理解“表与链的关系”比背命令更重要。

等你把这些前置概念搞清楚,再回头看那张流量路线图,就会发现“4 表 5 链”完全不需要背。它们本来就是根据数据包在系统中行走的路线自然分布开的,而不是教材人为发明的术语。只要路线清楚,每个链是什么、每个表负责什么,会自然形成直觉,就像不上高速公路你也知道哪里是入口、哪里是出口、哪里是收费站一样。

当你这样理解之后,iptables 不再是一个“记不住的术语体系”,而是一个贴合现实逻辑的交通系统:流量会按路线经过不同的表、不同的链,你只是在每个路口贴上自己想要的规则。

5 iptables 如何与其他系统协同工作


在第 4 章中,我们刻意把注意力从“4 表 5 链的名词表”上移开,只建立了一张数据包在内核中如何行走的路线图骨架。但这张路线图并不是只给你一个人看的——任何运行在这台服务器上的系统,只要需要处理网络流量,都会在这张图上留下自己的标记

而这一章要讨论的,正是这些“标记”来自哪里,又是如何在你不知情的情况下,改变了流量真正的行走路径。


当你真正把服务器跑起来,你会发现 iptables 根本不是一个“独立的工具”——它更像是一个公共交通枢纽。任何需要处理网络流量的系统——Docker、Podman、Kubernetes、Tailscale、甚至 HAProxy、FRP、Clash——都会在 Linux 的内核网络栈上插队、插规则、抢先级、改路径。它们不会跟你商量,它们会直接把自己的规则写进 netfilter 的各个关键节点里。你只要一不注意,就会出现昨天还好好的服务今天打不开、或者数据库莫名其妙暴露出去这种事故。

这一章的关键点是:你必须把 iptables 看成一个“公共枢纽”,而不是你一个人的防火墙。所有系统都在同时使用它,你只是其中一个。

最典型的例子就是 Docker。只要你使用 -p 映射端口,Docker 就会在 PREROUTING 写 DNAT,把你的公网端口映射到容器;然后在 FORWARD 链加 ACCEPT 规则让包能继续转发;最后在 POSTROUTING 位置加 MASQUERADE,让容器回包能正确出去。整个流程你没有写任何一行 iptables,但 Docker 已经默默替你做了一个路由器的全部工作。所以你真正看到的是:你的 INPUT 链什么都没放,Docker 的容器却暴露到公网了。这不是 bug,而是 Docker 和你“共享同一套安全系统”的自然结果。

Tailscale 也是类似的逻辑,它在内核里接管了路由表,也会改写 iptables 的规则,让经过它虚拟网卡(tailscale0)的包走特定的路径;甚至会自动处理 NAT 和反向流量转发。如果你用 Tailscale Funnel、用 Tailscale Serve,它还会在本机建立临时端口,并让流量从用户态的代理回到内核。这些步骤对你是透明的,但意味着 Tailscale 会把自己的规则插在路由和转发环节里,影响你机器的整体流量路径。

再看看 Kubernetes,K8s 环境中的 iptables 是最可怕的,也最能说明“协同工作”的概念。Kubernetes 会在每个节点自动生成大量的链,例如 KUBE-SERVICES、KUBE-PORTALS、KUBE-MARK-DROP 等,把服务的 ClusterIP 映射、Pod 的 SNAT、Service 的负载均衡路径,全都用 iptables 实现。你只要有几十个 service,iptables 链会自动变得非常长,而且每个包都必须经过这些链。这样的系统里,你的自定义规则根本不能直接写在主链里,而必须“绕开”整个 K8s 流程,否则轻则不起作用,重则直接把 service 的流量断掉。

再说 HAProxy 和 FRP,这两个工具自身不会写 iptables 规则,但它们往往跟你的防火墙强绑定。例如你希望 HAProxy 只监听内网 IP 并让外网访问走某个跳板,那么你必须在 PREROUTING 做 DNAT,让外网包进来后被本机转发到 HAProxy。如果你不理解这个细节,你就会以为自己“启动了代理就有用了”,实际上流量压根没有走到你以为的位置。很多人遇到 HAProxy 怎么都转发不了,就是被这种“iptables 和服务之间没有协同”的坑绊住了。

你还能看到一些更加“隐形”的协同者,比如 OpenVPN、WireGuard、Clash、Surge。这些工具为了做流量劫持或透明代理,会写 mangle 表、打 mark、改路由,并把流量引到用户态代理再送回内核。它们不是修改 filter 规则,而是改变路由决策。如果你不了解它们在 mangle 或路由表里插入了什么东西,你会以为自己的 INPUT 写对了,结果流量被用户态代理“截胡”后绕了一圈又回来了,和你预期完全不一样。

所有这些系统共同构成一个现实:任何一个稍微复杂的服务器环境,都在同时使用 iptables。你不是唯一的“防火墙管理员”。你只是所有使用者中的一个。

理解这一点后,你才能真正掌控自己的系统。因为你知道:你的规则必须写在正确的位置;知道 Docker 一定会插到 PREROUTING;知道 Tailscale 会抢路由;知道 Kubernetes 会让 FORWARD 变得非常复杂;知道代理和 VPN 会动 mangle 和路由表;知道某些系统插队的位置比你高,只靠 INPUT 根本拦不住。

从这个角度看,iptables 本身并不复杂。复杂的是“谁在和你一起使用它”。当你知道有哪些系统会修改 netfilter 的哪些节点,你就能设计出真正可靠而可控的安全策略,不再被莫名其妙的流量行为搞到焦头烂额。

这一章的重点不是去列出每个系统写了哪些链,而是想让你明白:iptables 在现代 Linux 生态中不是“单机工具”,而是一个共享平台。你真正需要管理的,是所有系统共同对内核网络栈的修改,而不是孤立地看某一条链。

6 从真实需求出发,写出不会出事的 iptables

6.1 用一个真实 VPS 场景,把 “表、链、规则” 串成真正能用的方案

在真正开始写 iptables 规则之前,有一个问题往往被忽略:大多数人卡住的,并不是命令怎么写,而是不知道该从哪里下手。这是因为很多教程一上来就讲表、链、参数,却很少从一个更现实的角度出发——在一台真实服务器上,你到底想让哪些流量通过,又想拦住哪些流量?所以这一节,我们先不碰命令,而是从一个非常常见的 VPS 使用场景开始。

假设你现在有一台普通的 Linux VPS,用途并不复杂:它对公网提供 Web 服务,需要开放 80 和 443;你通过一个非默认端口(比如 54331)进行 SSH 登录;同时,这台机器上运行了 Docker,其中某个容器监听着 3306,用于数据库服务(这个 3306 并不是给公网用户访问的服务,它只是为了让本机上的其他应用,或者同一台机器上的容器,通过宿主机网络访问数据库。换句话说,它“存在”,但并不意味着你希望它“对外开放”)。你的安全目标也很明确:只允许必要的入站访问,其余所有来自外部的 TCP、UDP 以及 ICMP 请求,全部拒绝。如果把这个需求浓缩成一句话,其实非常简单:该进来的进来,不该来的,一律别进。

安全需求梳理表格如下:

需求类型 场景描述 是否允许 备注说明
Web 服务 公网访问 HTTP(80) 允许 对外提供网站服务
Web 服务 公网访问 HTTPS(443) 允许 对外提供网站服务
管理访问 SSH 连接(端口 54331) 允许 使用非默认端口登录服务器
数据库服务 访问宿主机 3306(Docker 容器) 允许(仅本机/内网) 不是公网服务,仅供本机应用或容器访问
其他 TCP 入站 任意来源、任意端口 拒绝 不在明确允许列表中的 TCP 请求
其他 UDP 入站 任意来源、任意端口 拒绝 包括各种探测与异常流量
ICMP 入站 ping / traceroute 等 拒绝 不对公网暴露 ICMP
转发流量 VPS 作为路由或网关 不涉及 本机不承担转发角色
出站流量 本机主动访问外部 允许 默认不限制出站连接

当你从这个角度去看问题时,就会发现 iptables 的思考路径其实并不抽象。因为你当前关心的,几乎全部是从外部进入这台机器的流量。

一个外部数据包到达 VPS 之后,通常只有几种可能:要么是发给本机上的某个服务;要么被转发给其他主机;要么在某个阶段被直接丢弃。而在这个场景里,这台 VPS 并不承担路由或网关的角色,也不需要转发流量。这一步判断非常重要,它能立刻帮你排除掉 FORWARD 链这个分支。

此时再回头看“5 条默认链”,它们各自的角色其实就已经开始分化了。PREROUTING 发生在数据包刚进入内核、还没决定去向之前,更多与地址改写和早期处理相关;POSTROUTING 则发生在流量即将离开本机时,主要用于源地址转换;OUTPUT 面向的是本机自己发起的连接;FORWARD 用于转发流量,而在这个场景下已经可以明确排除。这样一来,真正需要关注的,就只剩下外部流量进入本机之前必经的那个关口。

回到前面已经建立的直觉:filter 表负责访问控制;nat 表负责地址转换;mangle 和 raw 用于更底层或更特殊的处理。你现在要做的事情,本质上只有一件——决定哪些流量可以进入这台机器,哪些不可以。因此,这一整套规则的核心位置,其实非常清晰:就在 filter 表的 INPUT 链。

注意,这个结论并不是靠死记硬背“4 表 5 链”得来的,而是从需求一步一步自然推导出来的。

再往下拆解,你会发现所有入站流量其实可以被清楚地分成两类:一类是你明确希望放行的,比如 Web 服务和 SSH;另一类,是你并没有理由允许的所有其他请求。这恰好对应了一种非常经典、也非常稳妥的防火墙写法思路:先写清楚“允许什么”,最后用一条规则兜底,把剩余的一切全部丢弃。至于 Docker,它并不是这个模型的例外。你之所以不需要手动为 3306 写复杂规则,并不是因为 Docker 绕过了 iptables,而是因为 Docker 会在现有的规则体系中,主动插入自己的链和跳转规则,把“容器之间、宿主机内部的访问”处理掉,而不影响你对公网入站流量的整体控制。

到这里为止,我们依然一条命令都没有写。但你已经完成了最关键的一步:把一个抽象的安全需求,转化成了一张清晰的“流量决策路线图”。如果你此刻隐约感觉到,iptables 开始从一堆名词,变成了一套可以推理、可以规划的系统,那说明这一节已经达到了它应有的目的。


需要说明的是,本文的重点并不是穷举 iptables 在所有场景下的配置方式,而是借助一个最常见、也最容易落地的 VPS 使用场景,来讲清楚 “应该如何思考和规划规则”

因此,示例中主要围绕的是入站访问控制,规则自然集中在 filter 表的 INPUT 链上。而在其他使用场景下,比如将 Linux 作为独立防火墙、网关或转发路由器时,就必然会涉及 FORWARD、PREROUTING、POSTROUTING 等链,甚至对 nat 和 mangle 表的依赖会更加明显。

不过,无论角色如何变化,底层的思考方式其实是完全一致的:先明确流量从哪里来、要到哪里去,再找到它在内核“路线图”上必经的关口,最后决定在那个位置放行、修改,还是丢弃。


6.2 从规则开始:把思路真正写进 iptables

在真正写规则之前,我们已经在 5.1 里想清楚了一件事:这台 VPS 的安全策略,核心就是控制谁可以主动连进来。因此,所有关键规则,都应该围绕 filter 表的 INPUT 链展开。

写 INPUT 链时,有一个几乎不需要争论的共识:已经建立或关联的连接,必须被无条件放行。

如果连这一点都做不好,防火墙配置本身就会变成一种“自残行为”。

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

这条规则的意义非常简单:只要是当前服务器已经认可过的通信,无论是 SSH、HTTP 还是容器对外请求的返回流量,都不再重复审查。

在此基础上,接下来要做的事情就清晰得多了:明确写出你希望对公网开放的服务端口。

对于一个典型的 Web VPS 来说,这个列表往往非常短。

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

80 和 443 的存在不需要额外解释,它们就是这台服务器“被访问”的主要原因。只要你在跑网站,这两条规则就应当是 INPUT 链里最显眼的部分。

接下来是管理通道,这里假设使用的54331 端口作为 SSH 登录端口:

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

注:把 SSH 从 22 改到一个非标准端口,并不能带来真正意义上的安全性,但它至少可以显著减少无意义的扫描和日志噪音。在规则层面,它的地位依然很明确:这是一个你清楚用途、也愿意承担风险的入口。


到这里,有必要特别说明一下 Docker 相关端口的问题。例如数据库容器监听着 3306,这个端口确实存在,但它并不是“公网服务”。它只需要在容器网络或宿主机内部可达即可,而 Docker 自身已经通过 NAT 和 FORWARD 链处理了这部分流量。因此,你不需要,也不应该,把 3306 之类的端口写进 INPUT 链的放行规则中。


当所有“你明确要的入口”都已经写清楚之后,INPUT 链里剩下的流量,就只剩下一类:你没有理由允许的请求。这时候,策略反而变得极其简单:

iptables -A INPUT -j DROP

这条规则并不是“冷酷无情”,而是对前面所有规则的自然总结:允许列表之外的所有入站连接,一律拒绝。

最后把上面的规则按顺序放在一起,你会得到一份非常干净、可读性也很高的 INPUT 链策略:

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

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

iptables -A INPUT -j DROP

如果你能清楚地解释每一条规则存在的理由,那这份防火墙配置就是健康的;如果某一条规则你已经说不清它“在保护什么”,那它大概率就不该存在。

6.3 Docker、端口暴露与 iptables:一次真实事故背后的责任边界

在前面的示例中,我们刻意把数据库服务作为一个“存在,但不对公网开放”的组件来对待。这一点在纸面上很好理解,但在真实环境里,恰恰是最容易被误操作、也最容易出事故的地方。问题并不出在 iptables 命令本身,而往往发生在更早的一步:容器端口是如何被暴露出来的

很多 Docker 教程在演示数据库容器时,都会直接使用类似这样的命令:

docker run -p 3306:3306 

这条命令在语法上完全正确,也能正常工作,但它隐含了一个非常关键、却经常被忽略的事实:它会让数据库端口在宿主机的所有网络接口上监听。 换句话说,这个 3306 不仅对本机可见,也对外部网络可见。如果宿主机是在内网还没什么影响,但是如果宿主机有公网IP地址(或者有公网IP的端口映射),那就不妙了!

如果你此时再“理所当然”地认为:“没关系,我有 iptables,会在 INPUT 链里控制住它”,那么,风险其实已经悄悄出现了。

在现实世界里,Docker 并不是简单地把端口交给 INPUT 链处理。它会在 nat 表和 filter 表中插入自己的链和跳转规则,改变流量进入容器的路径。如果你并不了解这些规则是如何被插入的,很容易就会出现一种后果:规则看起来写了,但实际上并没有挡住你以为已经挡住的东西。

本文前面提到过的那次真实事故——WordPress 数据库被直接连入并删库——本质上就是这样发生的:数据库容器端口被无意中暴露在公网,而防火墙规则并没有覆盖到那条真正生效的路径。

而当你把端口映射方式改成下面这样时,问题的性质就发生了根本变化(这里的 100.x.y.z 并不是公网地址,而是 Tailscale 分配的虚拟内网 IP):

docker run -p 100.x.y.z:3306:3306 ...

这条命令的真实含义是——只在 Tailscale 私有网络接口上监听 3306,以我芝加哥VPS为例,实际效果是只将tailscale IP 100.x.y.z上的3306映射到容器IP为172.19.0.4的3306上:

image.png

也就是说,在流量还没进入 iptables 的决策体系之前,你已经把数据库从“公网世界”里彻底拿走了。对公网扫描器而言,这个端口甚至是“不存在的”。

理解这一点非常重要,因为它清楚地划分了几个不同层面的责任边界:iptables 的 INPUT 链,负责的是“哪些流量可以进入这台宿主机”;Docker 的端口绑定,决定的是“这个服务是否暴露在公网接口上”;而 Docker 自动创建的 DOCKER-USER 链,则是在你确实需要对容器流量做精细控制时,提供的一道可选保险。

当你在端口绑定阶段就已经把攻击面限制在内网时,iptables 的规则更多是在做纵深防御;而一旦你在最开始就把端口暴露到了 0.0.0.0,那么防火墙规则就会被迫承担本不属于它的风险兜底职责。

回到本文一直强调的那个核心直觉:iptables 并不是一张“万能挡板”。它更像是一套交通调度系统,而不是替你弥补前端设计失误的安全补丁。

如果你能在这一节里真正意识到:“3306 是否对外开放”,往往比“INPUT 链里写了什么规则”更早、更关键,那么你对 iptables 的理解,已经远远超过了“会写几条命令”的层面。

7 iptables 的性能与扩展性原理

当一个人真正开始用 iptables 管理服务器,往往会经历这样的阶段:最开始觉得规则是“写多少条就执行多少条”;到后来发现 Docker、NAT、conntrack 搞出很多自己没意识到的性能开销;再往后才意识到——iptables 的性能瓶颈,根本不是规则多,而是你写的规则到底触发了内核里的哪些“重活”。

很多人不知道的是,只要你用了 NAT,只要你写了大部分 filter 规则,Linux 内核基本都会引入 conntrack。这个“连接跟踪系统”本质上是一个哈希表,它用来记住每一条连接的五元组和状态,让 NAT 能正常做回包转换,让你的“ESTABLISHED,RELATED”这种规则能工作。好处显而易见,可坏处是在高并发场景下,conntrack 本身就会成为巨大的性能瓶颈:连接多的时候,内核不停查表;NAT 多的时候表里还会塞更多状态;哈希冲突一多就开始变慢;表满了甚至干脆直接掉包。这也是为什么一些 VPS 在高流量时 NAT 会突然失灵——不是 iptables 坏了,是 conntrack 爆了。

NAT 的性能损耗其实比大多数 filter 规则要大得多。这是因为 NAT 不只是简单换一下 IP 或端口,它需要为每条连接创建映射、同步状态、维护计时器、管理回包路径,整个开销是有“重量级”的。你但凡跑多一些容器,Docker/Kubernetes 用它来管理大量端口映射和流量转发,conntrack 的增长速度会比你想象得更夸张。这也是为什么许多生产环境要么关闭 conntrack,要么尽量减少 NAT,要么改用 ipvs 这种旁路方式。

说到性能开销,很多人第一反应是“规则多会变慢”。这句话不完全正确,至少不适用于所有链。例如 INPUT 链对本地服务影响最大,但一般流量并不多;PREROUTING 和 POSTROUTING 则是流量高峰时最忙的链,因为所有入站、出站的包都会从这里经过。如果这些位置挂满复杂规则,服务器的延迟就会从 TTFB 一路蔓延到整体响应时间。所以规则是不是多并不重要,更关键的是你把规则写在哪里,以及它会不会影响内核“最忙的节点”。

Linux 内核的包处理逻辑里,其实还分“快路径”和“慢路径”。当 conntrack 已经建立映射,或者路由缓存有效时,包往往可以直接走快路径,不用重新做 NAT、校验、路由判断。但只要你在 mangle 或 raw 表里做了改动,或者写了会破坏快路径的规则,内核就会被迫让包进入慢路径。慢路径意味着:更多检查、更多计算、更多状态同步。于是性能就自然掉下去。有些人随手写的 mangle 规则,或者几十条奇怪的 TEE/mark,就会在无形中把大量包拖进慢路径,结果服务器变卡,其实连点 CPU 都没满。

为什么 Docker 环境里的 iptables 规则看起来更乱、性能更差?原因其实非常简单:Docker 会自动创建大量 DNAT 映射、自动开放 FORWARD 规则、自动启用 MASQUERADE 做 SNAT,并在 POSTROUTING 插入各种转发逻辑。几十个容器时可能还好,几百个容器后,这些 NAT 和 FORWARD 的链会变得惊人地长,再加上 conntrack 的条目暴增,延迟上升是正常现象,并不是“你的配置不够优化”,而是 Docker 的默认设计决定了它没办法像传统路由器那样轻量。

当然,iptables 的性能是可以优化的。最常见的方式就是把常命中的规则放到前面,把一堆端口合并成 multiport,把大量 IP 合并成 ipset,让过滤逻辑尽量在 INPUT 而不是 PREROUTING 完成,尽量减少不必要的 NAT 操作,不要在 PREROUTING 乱写 mangle 表这种对性能最敏感的位置。特别是 ipset,它能让你把本来需要写 500 条的规则,变成一条。这种优化手法常常能让你少踩非常多的性能坑。

如果要总结这一章,其实一句话就够了:iptables 的性能瓶颈,根本不是“规则多少”,而是“规则让内核做了多少额外的工作”。你写的每一条规则,背后都是内核在跑一段逻辑。有些逻辑轻如鸿毛,有些重如泰山。你写法的差异,决定了你的服务器在高流量下能不能活得下去。

8 iptables常用命令:写规则之前,你真正会用到的就这些

在前面的章节里,我们已经在基于真实 VPS 场景的 INPUT 链配置“接触过” iptables 规则了,我刻意把命令放进具体语境中,而不是单独讲参数本身,是为了先让你建立正确的判断路径。

但当你真的开始长期维护一台服务器,会发现另一个现实问题:你并不是每天都在“设计规则”,更多时候是在“查看、调整、回滚、验证”已有规则。这时,你需要的不是一套完整思路,而是对几条最常用命令的熟练掌控——怎么看当前规则生效情况、如何安全地插入或删除一条规则、怎样确认某个数据包到底有没有被命中。

因此,这一章并不再讨论“规则该怎么设计”,而是把实际运维中最常用、也最容易出错的 iptables 操作单独拎出来,作为一份可以随时翻看的命令工具箱。你可以把它当作前面所有章节的“操作层补充”,而不是一条新的学习主线。


不过,在所有操作里的第一条原则永远是:先观察,再修改——你必须先看清现在的规则长什么样,顺序是怎样的,Docker 有没有往 PREROUTING 塞东西,NAT 是否在按你的预期工作……这些都得从“看”开始,比如:

当你怀疑 Docker 在帮你悄悄做 DNAT,只需要查 nat 表的 PREROUTING 链就行了。iptables 会按链把规则列出来,顺序就是内核执行的顺序,你能够很快判断真实发生了什么,而不是凭感觉猜。

当你想看看某个端口有没有被命中,可以在 INPUT 或 FORWARD 末尾加一条日志规则,这样既能观察路径,又不会抢掉前面关键规则的优先级。

当你想删除规则时,最稳妥的是按行号删。因为每次你添加或删除规则,链里的整体排序都会变化——通过行号来操作,可以避免误删或删错位置。

当你排查问题时,永远要把那张“内核路线图”拿出来对照。入口总是 PREROUTING,出去是 POSTROUTING;本机访问看 INPUT;容器、旁路、转发都看 FORWARD。

你要把命令和“路径”结合起来看,而不是只盯着命令本身,这样你定位问题的速度会比只背命令的人快得多。


下面这几条命令就是我平时真正会用到、也是你未来排查问题最离不开的几个动作:看规则、加规则、删规则、看规则有没有被命中。其它那些你从来没用过的命令,其实根本不需要往脑子里塞。

1. 查看某个表、某条链的规则

iptables -t nat -L PREROUTING -n -v

它在做什么: 列出 nat 表PREROUTING 链 的所有规则,按照实际执行顺序展示,并附带每条规则的命中计数。需要注意,PREROUTING 很常被系统组件插入规则(如 Docker、1Panel、CNI 插件等),所以你经常会看到一些不是你写的跳转规则。

什么时候用: 当你想确认某个程序是否往 nat 表插规则(尤其是 Docker)、或者想检查 DNAT、透明代理、端口转发是否按预期生效时,这条命令是第一选择。

我在芝加哥VPS上运行该命令的输出如下:

image.png

2. 查看所有表、所有链(完整总览)

iptables -L -n -v

它在做什么: 把 filter 表所有链的规则全部列出来,让你一次性看到整个过滤逻辑。

什么时候用: 当你对“到底谁在拦包”一脸懵时,这条命令是最快的扫盲方式。

我在芝加哥VPS上运行该命令的输出(部分)如下:

image.png

3. 在某条链的末尾追加一条规则

iptables -A INPUT -s 1.2.3.4 -j DROP

它在做什么: 在 INPUT 链末尾加一条规则,不会抢优先级。

什么时候用: 临时封一个 IP、调试路径、验证某个条件时,这种“尾部追加”最安全。

4. 在某条链的最前面插入规则

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

它在做什么: 在 INPUT 链最前面插入一条规则,让它成为优先级最高的规则。

什么时候用: 当你准备测试一个容易被前面规则覆盖的逻辑,或者你怕“不小心把自己拒之门外”时,用插入确保规则一定先执行。

5. 查看某条链中的某条具体规则的行号并删除某个行号对应的规则(以Docker链为例)

iptables -t nat -L DOCKER --line-numbers -n # 显示nat表中DOCKER链的所有规则及行号
iptables -D DOCKER 5 # 删除行号为3的规则

它在做什么: 删除 Docker 链中编号为 3 的那条规则。

什么时候用: 删除规则的时候永远推荐这种方式,因为规则顺序会变,“按行号删”最不容易误删。

比如我在芝加哥VPS上运行该命令查看nat表中DOCKER链里规则行号的输出结果如下:

image.png

这时候运行iptables -D DOCKER 5就可以直接删除行位5的第一条DNAT规则。

6. 查看INPUT规则的“命中次数”(非常关键)

iptables -L INPUT -n -v

它在做什么: 显示 INPUT 链每条规则的流量统计。

什么时候用: 排查问题时,这是最有价值的信息。你能一眼判断某条规则是否真的被执行了。

我在芝加哥VPS上运行该命令的输出如下:

image.png

7. 清空某条链(以INPUT为例)

iptables -F INPUT

它在做什么: 把 INPUT 链的所有规则直接全部清空。

什么时候用: 调试环境、写脚本前初始化、防止历史规则干扰当前行为。不推荐在生产环境无脑使用。

8. 清空整个 iptables(慎用!)

iptables -F
iptables -t nat -F

它在做什么: 把 filter 和 nat 表的所有规则全清掉。

什么时候用: 重新搭建规则体系、调试隔离环境时可以用。实际服务器上尽量不要这么干。

9. 保存当前规则(避免机器重启后消失)

Debian/Ubuntu:

iptables-save > /etc/iptables/rules.v4

CentOS/RHEL(使用 service 工具):

service iptables save

它在做什么: 把当前内存里的规则持久化到磁盘。

什么时候用: 你已经调好一套规则,准备长期使用的时候。

如果安装了iptables-persistent组件,则对应的命令是:

netfilter-persistent save

10. 恢复规则(从文件加载)

iptables-restore < /etc/iptables/rules.v4

它在做什么: 把保存的规则一次性加载进系统。

什么时候用: 系统重启之后,或批量部署几台机器时。

如果安装了iptables-persistent组件,则对应的命令是:

netfilter-persistent reload

写在最后:命令不多,关键是“会看懂”

你会发现这些命令并不多,也没有什么神秘的技巧。真正让人卡住的从来不是命令,而是不知道命令对应的是路径上的哪一段

你只要始终记得:入口永远从 PREROUTING 开始;本机活动走 INPUT;转发与 Docker 走 FORWARD;出口统一走 POSTROUTING。然后再配合上面这些“够用”的命令,大部分棘手的问题你都能在几分钟内排出个方向。


9 后话:写给未来的我(以及也许现在还看不懂 iptables 的你)

写完这一整套内容,我反而更确定一件事:iptables 这种老牌工具,虽然“老”,但并没有过时。它身上那种朴素的逻辑性、规则链的因果关系、匹配与跳转的明确性,其实非常符合工程师的思维方式。但也正是因为它太灵活,太能折腾,所以很多人第一次接触时反而容易迷路——规则看不懂、链之间的关系绕不清、改错一条就能把网络干没。

我写这篇文章的目的不是把所有语法都堆出来,而是把最容易用到、最容易出错、最值得理解的那些部分讲清楚。毕竟很多时候,我们不是要成为“iptables 行走百科”,而是要在实际场景里能稳稳地解决问题:看到一条规则能判断它的意图,看到流量方向能大概推断会经过哪些链,知道哪里能下手、哪里千万别乱碰。

也正因为如此,我才把一些常用命令、排错思路、链的实际作用都拆开写。不是为了做教程,而是为了让未来的自己在遇到奇怪的 NAT 现象、Docker 流量跑偏、策略路由不生效、端口映射莫名其妙失灵这些情况时,还有个可以回头查查、确认逻辑的地方。


其实,对于我这种习惯了配置独立防火墙的人来说,配置 iptables 时是最容易犯惯性错误的。独立防火墙的世界里,规则是平铺在一层层 GUI 或策略树上的,你改一条就是一条;但在 Linux 上,iptables 并不是一个“防火墙配置文件”,而是一个“实时编辑内核流量处理”的工具。

刚开始时,你会下意识地把它当成类似 Palo Alto、FortiGate、Hillstone 那种“哪里加规则哪里生效”的模型,但事实恰好相反——iptables 的规则散落在不同的表、不同行为的链里,系统组件还会不请自来地往这些链里塞东西。你不去查表、不去确认链、不去观察实际命中数,就很容易陷入“我明明加了规则为什么没生效”的错觉。

说到底,这不是技术问题,是经验迁移的问题。做惯了独立防火墙的人,在第一次面对 iptables 时,往往需要先把过去的那套“防火墙即配置文件”的思维放下,重新用“内核实时处理流量”的视角审视所有规则。只要这个心态调整到位,iptables 就会突然“变得能看懂”——它不再是满屏的命令,而是一个你能逐条拆解、逐环节验证的流控系统。


iptables 这个工具有一种很特别的气质:当你真正理解它之后,你会感觉网络世界忽然变得“可解释”了。以前看不懂的东西,现在可以顺着链路一路推;以前只能靠瞎试,现在可以靠规则推理;以前怀疑是玄学,现在能抓包、查链、看计数器,一步步找出是谁引发的问题。

写到这里,算是把自己这几年踩过的坑、摸到的一点规律、系统化理解它的方式都整理了一遍。未来如果再遇到更典型的问题,我也可能会继续补充,但不用急,不用规定自己必须写到什么程度。iptables 本身就是一个“用到哪里学到哪里”的工具——懂得越多,越能从容;保持一点距离,也不会失去它的价值。

就这样,留个小结,也给未来的自己留一盏灯。

📌 内容结构提示:
这篇内容属于「博客知识地图」的一部分,你可以从这里查看完整内容路径: 博客知识地图
查看相关分类·3个匹配
📎 相关文章
分享这篇文章
博客内容均系原创,转载请注明出处!博客的RSS地址为:https://blog.tangwudi.com/feed,欢迎订阅;如有需要,可以加入Telegram群一起讨论问题。

评论

  1. handy
    Windows Firefox 150.0
    2 月前
    2026-5-11 20:09:15

    我也认真看了,以前学的就是囫囵吞枣,感谢大佬的讲解

    • tangwudi
      handy
      Macintosh Chrome 147.0.0.0
      2 月前
      2026-5-11 20:14:07

      客气了,有用就好,我也是觉得以前理解得不够深入,才专门写篇文章来督促自己想清楚的。

  2. Windows Firefox 147.0
    6 月前
    2026-1-24 12:44:22

    感谢大佬的iptables详细讲解。 我真是逐字逐句的看完了,然后对iptables有了新的理解,原来想不通的地方也通透了不少。 谢谢

    • tangwudi
      DNS123
      Macintosh Chrome 144.0.0.0
      6 月前
      2026-1-24 14:04:11

      我也是习惯性的梳理一下,因为老是容易忘记,所以尽量写得详细一点。不过,没想到你还真能逐字逐句看完啊,这年头,大部分的人对长文章都没有耐心看完的。

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇
       

👋 欢迎来到“无敌的个人博客”

这里主要围绕以下方向展开长期探索:

🧱 个人数字基础设施与博客系统构建
☁️ Cloudflare 与网络架构实践
🧠 AI 与知识系统探索
🛡️ 网络安全与访问优化
🎵 音乐与声音认知
👁️ 认知视角与世界观