CentOS 7 VPS中限制VPN输出的Iptables Accept规则失效
我来帮你排查这个问题,大概率是规则顺序、默认策略或者进程身份的问题,咱们一步步来定位和解决:
1. 先确认当前iptables规则的状态
首先执行这条命令查看OUTPUT链的所有规则和顺序:
iptables -t filter -L OUTPUT -nv --line-numbers
重点看针对ssuser的规则顺序,以及OUTPUT链的默认策略(最后一行的Policy字段)。
2. 最常见的问题:规则顺序错误或缺少DROP规则
你的需求是仅允许ssuser访问80/443端口,正确的规则逻辑应该是:
- 先放行80、443端口的TCP输出
- 再拒绝ssuser的所有其他TCP输出
- 确保默认策略不会覆盖你的规则
如果你的当前规则只有两条ACCEPT,没有后续的DROP规则,而默认策略是ACCEPT的话,所有端口都会被允许,这两条ACCEPT规则等于没起作用。
修复步骤:
如果还没添加DROP规则,按以下顺序执行命令(顺序非常重要!):
# 允许80端口的TCP输出 iptables -t filter -m owner --uid-owner ssuser -A OUTPUT -p tcp --dport 80 -j ACCEPT # 允许443端口的TCP输出 iptables -t filter -m owner --uid-owner ssuser -A OUTPUT -p tcp --dport 443 -j ACCEPT # 拒绝ssuser的所有其他TCP输出 iptables -t filter -m owner --uid-owner ssuser -A OUTPUT -p tcp -j DROP
如果已经添加了DROP规则但顺序在ACCEPT之前,那ACCEPT永远不会被匹配到。这时候需要先删除DROP规则:
# 查看规则序号,找到那条DROP规则的序号N iptables -t filter -L OUTPUT --line-numbers # 删除该规则 iptables -t filter -D OUTPUT N # 重新按正确顺序添加上面的三条规则
3. 验证VPN进程是否真的以ssuser身份运行
如果规则没问题,但还是不生效,可能是VPN服务根本没以ssuser启动。执行这条命令查看进程所属用户:
ps aux | grep <你的VPN进程名>
比如如果是Shadowsocks,就用ps aux | grep ss-server,看输出的第一列是不是ssuser。
如果是root用户运行的,需要修改启动方式:
- 手动启动的话,用
su - ssuser -c "你的VPN启动命令"切换用户启动 - 如果是systemd服务,编辑服务文件(比如
/etc/systemd/system/vpn.service),添加User=ssuser字段,然后重新加载服务:
systemctl daemon-reload systemctl restart vpn.service
4. 检查iptables owner模块是否加载
极少数情况下,owner模块未加载会导致规则不生效,执行这条命令检查:
lsmod | grep ipt_owner
如果没有输出,手动加载模块:
modprobe ipt_owner
5. 保存规则防止重启失效
CentOS7上修改iptables规则后,需要保存才能永久生效:
service iptables save # 或者用iptables-save命令 iptables-save > /etc/sysconfig/iptables
完成这些步骤后,你可以用ssuser身份执行curl http://example.com和curl https://example.com测试能否访问,再试其他端口比如curl telnet://example.com:22应该会被拒绝,这样就说明规则生效了。
内容的提问来源于stack exchange,提问作者Hank zhu

