iptables 用 connlimit 模块可轻量限制单 IP 并发连接数,需正确指定链(如 INPUT 或 DOCKER-USER)、加 --syn 限制新连接,并注意 nf_conntrack 依赖及 IPv4/IPv6 掩码差异。

iptables 如何用 connlimit 限制单 IP 并发连接数
直接用 iptables 的 connlimit 模块最轻量、最常用,不需要额外服务或用户态程序。它工作在内核 netfilter 层,对性能影响极小。
常见错误是写成匹配「已建立连接」却忘了加 --syn 或放错链(比如误配到 FORWARD 而非 INPUT),导致规则不生效。
- 限制 SSH(端口 22)单 IP 最多 3 个并发连接:
iptables -A INPUT -p tcp --dport 22 -m connlimit --connlimit-above 3 -j REJECT --reject-with tcp-reset
- 限制所有 TCP 连接(非特定端口):
iptables -A INPUT -p tcp -m connlimit --connlimit-above 10 -j DROP
- 只限制新连接(避免误伤已有长连接):必须加
--syn,否则会匹配所有包(包括 ACK、数据包等):iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 50 -j REJECT
为什么 connlimit 默认统计的是 ESTABLISHED + SYN_RECV 状态
connlimit 统计的是当前被内核连接跟踪子系统(nf_conntrack)记录的连接条目,主要包含 ESTABLISHED 和 SYN_RECV 状态。这意味着:
- 它不区分「是否完成三次握手」——
SYN_RECV算一个连接,哪怕只是半开连接; - 它依赖
nf_conntrack模块启用,若系统关闭了连接跟踪(如某些高性能转发场景),connlimit将完全失效; - 如果
nf_conntrack_max设置过小(默认常为 65536),高并发下可能因哈希表溢出导致新建连接失败,此时限制逻辑本身也会异常; - IPv4 和 IPv6 各自独立计数,
--connlimit-mask 32(IPv4)和--connlimit-mask 128(IPv6)需分别配置。
替代方案:fail2ban 适合按请求频率封禁,不是连接数限制
很多人混淆「连接数限制」和「请求频率封禁」。fail2ban 是基于日志分析的,它看到 Nginx 日志里某 IP 1 分钟内发了 100 次 /login 请求,才触发封禁——这跟 TCP 连接数无关。
如果你的真实需求是防暴力破解或爬虫扫端口,fail2ban 更合适;但如果是防连接耗尽(如 SYN Flood、连接池打满),connlimit 是唯一合理选择。
-
fail2ban无法感知未记录日志的连接(如直接 telnet 扫描 22 端口); - 它有延迟(至少几十秒),而
connlimit是实时拦截; - 它需要配置 jail、filter、action,复杂度远高于一条
iptables命令。
注意 connlimit 在 Docker / Kubernetes 环境下的失效点
Docker 默认使用 iptables 规则做 NAT 和端口映射,且会在 DOCKER-USER 链插入规则。如果你把 connlimit 规则加在 INPUT 链,它可能根本匹配不到容器暴露的端口流量——因为包先被 DOCKER-USER 或 FORWARD 链处理了。
- 正确做法:把规则加到
DOCKER-USER链(Docker 官方推荐的用户自定义链),并指定目标容器端口和协议:iptables -I DOCKER-USER -p tcp --dport 8080 -m connlimit --connlimit-above 20 -j REJECT
- Kubernetes 中,
connlimit对 Service ClusterIP 流量无效(走的是 iptables kube-proxy 规则,不进INPUT);只有 NodePort 或 HostNetwork 暴露的端口才适用; - 容器内应用若自己监听
0.0.0.0,且宿主机没开防火墙,connlimit必须在宿主机上配,容器内配无效。
connlimit 的链位置、掩码值、甚至是否可用,全都不一样。










