iptables规则必须先放行再拒绝,否则白名单无效;需清空旧规则、先放行127.0.0.1及可信ip、再加兜底drop,规则须显式保存并配合云平台安全组与docker-user链协同生效。

iptables规则顺序错了,白名单就等于没设
先写 iptables -A INPUT -p tcp --dport 3306 -j DROP,再加允许规则,所有连接都会被拦截。iptables按顺序匹配,一旦命中DROP就终止流程,后面的ACCEPT永远不会执行。
必须严格按以下顺序操作:
- 清空已有3306相关规则:
iptables -D INPUT -p tcp --dport 3306 -j ACCEPT和iptables -D INPUT -p tcp --dport 3306 -j DROP(逐条执行,失败不报错可忽略) - 放行本地回环:
iptables -A INPUT -s 127.0.0.1 -p tcp --dport 3306 -j ACCEPT(MySQL启动自检必需) - 放行可信IP或网段:
iptables -A INPUT -s 192.168.10.5 -p tcp --dport 3306 -j ACCEPT或iptables -A INPUT -s 10.20.0.0/16 -p tcp --dport 3306 -j ACCEPT - 最后加兜底拒绝:
iptables -A INPUT -p tcp --dport 3306 -j DROP(注意用DROP,不是REJECT)
重启后规则消失是生产环境最高频事故
iptables默认规则不持久,服务器重启后白名单自动失效,数据库立刻暴露——这不是理论风险,是真实发生过多次的线上故障。
保存方式因系统而异,不能靠记忆写错:
- Ubuntu/Debian:
iptables-save > /etc/iptables/rules.v4(确保目录存在且有写权限) - CentOS 6:
service iptables save - CentOS 7+(使用iptables而非firewalld):
iptables-save > /etc/sysconfig/iptables
验证是否真正生效:重启前执行 iptables -L INPUT -n | grep :3306,记下输出;重启后再执行一次,两行输出必须完全一致。
云平台安全组没开,iptables规则根本收不到包
阿里云、腾讯云、AWS的安全组在网络更外层生效,数据包在到达操作系统前就被过滤。安全组没放开3306端口,iptables规则再精细也毫无意义。
排查步骤必须分层验证:
- 查安全组是否生效:从外网执行
telnet your-public-ip 3306,通了说明安全组已放行 - 查本地防火墙是否生效:在服务器本机执行
nc -zv 127.0.0.1 3306和nc -zv 192.168.10.5 3306(换成你的可信IP),看响应是否一致 - 生产环境必须双控:安全组只放运维跳板机和应用服务器内网段,iptables再做一层校验
Docker部署MySQL时别往INPUT链里加规则
如果MySQL跑在Docker容器中,直接对INPUT链加--dport 3306规则通常无效。Docker有自己的网络栈,入站流量走的是DOCKER-USER链,且该链在NAT和FORWARD之前执行。
正确做法是操作DOCKER-USER链:
- 放行指定源IP访问宿主机映射端口:
iptables -I DOCKER-USER -s 172.16.200.200 -p tcp --dport 3306 -j ACCEPT - 拒绝其他来源:
iptables -I DOCKER-USER -p tcp --dport 3306 -j DROP - 该方式不干扰Docker自身规则,也不影响容器间通信
最容易被忽略的是:bind-address配置和防火墙规则必须对齐。比如bind-address = 127.0.0.1却在iptables里放行公网IP,连接必然失败——这种错配在多层防护中极难定位。











