iptables规则已放行但海外仍无法访问?Ubuntu香港服务器分层排查方法
当 Ubuntu 香港服务器上的网站已经在 iptables 中加入放行规则,但海外访问仍然超时、连接被拒绝,不能直接判断为“iptables 没生效”。访问请求可能尚未到达服务器,也可能命中了更早的 DROP 规则、走了 IPv6 规则链、服务只监听本机地址,或者 TCP 已经建立但被 Nginx、应用白名单或限流策略拦截。
排查时应按“域名与地址族 → 上游访问控制 → 主机防火墙 → 数据包是否到达 → 端口监听 → 服务与应用”的顺序进行。先确认失败发生在哪一层,再修改配置;不要一开始执行 iptables -F 或直接放开全部端口,否则既可能扩大暴露面,也会破坏后续判断。
先确认“无法访问”具体表现
同一个域名在海外访问失败,至少需要记录以下信息:
- 访问时间,最好精确到分钟;
- 使用的域名、端口和协议,例如 HTTPS/443;
- 测试端的公网 IPv4 或 IPv6 地址;
- 是连接超时、连接被拒绝,还是已经返回 HTTP 状态码;
- 使用 IPv4 和 IPv6 时结果是否一致。
在测试端可以使用以下命令。将 example.com 替换为实际域名:
curl -4 -vk --connect-timeout 8 https://example.com/
curl -6 -vk --connect-timeout 8 https://example.com/
命令结果可以先按下面的方式分类:
| 现象 | 优先怀疑位置 | 说明 |
|---|---|---|
| 长时间超时,没有建立 TCP 连接 | DNS、上游安全策略、路由、主机丢包 | 还不能证明是 iptables |
立即返回 Connection refused | 服务未监听、监听地址不匹配、主机主动拒绝 | 通常已经到达服务器 |
| TCP 已建立,但返回 403、404、429 或 5xx | Nginx、应用、访问控制或限流 | iptables 放行通常已经生效 |
curl -4 成功,curl -6 失败 | AAAA 记录、IPv6 地址、ip6tables 或 IPv6 监听 | IPv4 规则不会覆盖 IPv6 |
| 浏览器偶尔成功、偶尔超时 | A/AAAA 记录不一致、多个入口配置不一致 | 需要分别验证 IPv4 和 IPv6 |
ping 不通不能单独证明 TCP 端口不可用,因为服务器或上游策略可能丢弃 ICMP。traceroute 中间节点没有响应,也不能直接证明 443 端口被防火墙拦截。判断 Web 服务是否可达,应以 TCP 握手和应用层请求为准。
建立分层原因树
可以把问题拆成五个分支:

- 请求是否解析到了正确的地址:检查 A、AAAA 记录和测试端实际使用的地址族。
- 请求是否被服务器外部的访问控制拦截:检查云侧安全组、边界防火墙或上游端口策略。
- 请求是否到达 Ubuntu 主机并通过正确的防火墙链:检查 iptables、ip6tables、nftables 兼容层和规则顺序。
- 主机是否有服务监听该地址和端口:检查
ss、服务状态和反向代理配置。 - TCP 建立后是否被应用拒绝:检查 Nginx 日志、应用日志、来源 IP 白名单和限流规则。
每一层都有对应的验证动作。只有当前一层已经通过,才进入下一层,避免把 DNS、IPv6 或应用问题误改成防火墙问题。
排查前先保存现有规则
防火墙调整有可能导致当前 SSH 会话中断。执行变更前,建议保留一个已登录的 SSH 会话,并准备服务器控制台或带外管理入口。先保存 IPv4、IPv6 和 nftables 当前状态:
stamp=$(date +%F-%H%M%S)
sudo iptables-save | sudo tee "/root/iptables-${stamp}.v4.rules" >/dev/null
sudo ip6tables-save | sudo tee "/root/ip6tables-${stamp}.v6.rules" >/dev/null
if command -v nft >/dev/null 2>&1; then
sudo nft list ruleset | sudo tee "/root/nftables-${stamp}.rules" >/dev/null
fi
同时确认 Ubuntu 当前使用哪一种管理方式:
iptables --version
ip6tables --version
sudo ufw status verbose
systemctl is-active nftables 2>/dev/null || true
如果输出中包含 nf_tables,说明 iptables 命令可能只是 nftables 的兼容前端;如果输出包含 legacy,则使用的是旧版 iptables 后端。两者的规则状态不能混为一谈。若 UFW 或其他规则管理服务处于启用状态,也不要一边手动修改 iptables,一边让管理服务继续覆盖规则。
第一层:确认海外请求使用了哪个地址
检查 A 和 AAAA 记录
在测试端或其他能够复现问题的环境中查询:
dig +short A example.com
dig +short AAAA example.com
如果没有 dig,也可以使用:
resolvectl query example.com
将查询结果与 Ubuntu 香港服务器上的地址进行对照:
ip -4 addr
ip -6 addr
常见判断方式如下:
- A 记录指向旧服务器,服务器上的 iptables 规则即使正确,也不会影响实际访问;
- AAAA 记录存在,但服务器没有可用 IPv6 地址或默认路由,支持 IPv6 的客户端可能优先尝试 IPv6;
- IPv4 访问成功、IPv6 访问失败时,不能只查看
iptables -L,还要查看ip6tables或 nftables 的 IPv6 规则; - 如果 A 和 AAAA 都正确,但只有某一地址族失败,应分别抓包,不要用 IPv4 的结论代替 IPv6 的结论。
分别验证 IPv4 和 IPv6
curl -4 -vk --connect-timeout 8 https://example.com/
curl -6 -vk --connect-timeout 8 https://example.com/
如果 IPv4 能够完成 TLS 握手并返回 HTTP 状态码,IPv6 在连接阶段超时,排查重点应转向:
- IPv6 地址是否仍然配置在服务器上;
- IPv6 默认路由是否存在;
ip6tables是否有更早的 DROP;- 服务是否监听
[::]:443; - AAAA 记录是否应当继续保留。
需要注意,0.0.0.0:443 只代表监听所有 IPv4 地址,并不自动代表 IPv6 可用;IPv6 通常需要看到 [::]:443 或明确的 IPv6 地址监听。
第二层:检查服务器外部的端口控制
如果数据包根本没有进入 Ubuntu 主机,检查主机上的 iptables 没有意义。香港服务器可能还受到以下外层策略影响:
- 云平台安全组或实例级入方向规则;
- 机房或边界防火墙的端口策略;
- 上游对特定端口或协议的访问控制;
- IPv4 与 IPv6 分开配置的安全策略。
重点核对 TCP 80、443 是否允许进入,并确认允许的地址族与实际测试一致。若网站只允许 443,而测试命令使用的是 80,也会得到误导性的结果。
最直接的判断方式是同时在服务器上抓包,在海外测试端发起一次请求:

sudo tcpdump -nn -i any \
'host <海外测试源IP> and (tcp port 80 or tcp port 443)'
将 <海外测试源IP> 替换为实际测试端公网地址。测试完成后按 Ctrl+C 停止抓包。
结果含义如下:
- 完全看不到来自测试端的 SYN:请求可能解析到了其他地址,或者在服务器外部被拦截;
- 能看到 SYN 到达,但没有服务器发出的 SYN-ACK:继续检查主机防火墙、监听状态和内核策略;
- 能看到 SYN、SYN-ACK 和 ACK,随后出现 HTTP 数据:TCP 层已经通过,问题应转到 Nginx 或应用;
- 服务器返回 RST:可能没有监听该端口,也可能有显式 REJECT;
- 服务器发出 SYN-ACK,但测试端始终没有收到:需要检查返回路径、上游出口策略或地址族配置。
tcpdump -i any 在某些情况下可能显示重复或方向不够直观。如果已经确认网卡名称,也可以改用具体接口:
ip -br link
sudo tcpdump -nn -i ens3 'host <海外测试源IP> and tcp port 443'
其中 ens3 只是示例,以实际网卡名称为准。
第三层:确认 iptables 规则真的处在有效路径上
先确认规则后端和实际规则集
Ubuntu 上运行 iptables 命令,并不一定代表规则直接由传统 iptables 内核表维护。先查看版本:
iptables --version
ip6tables --version
如果使用 nftables 兼容后端,再查看完整 nftables 规则:
sudo nft list ruleset
如果 nft list ruleset 中存在 inet、ip 或 ip6 家族的过滤链,需要确认真正生效的规则是否与 iptables -L 看到的内容一致。不要因为 iptables -S 中有一行 ACCEPT,就默认所有 nftables 链都允许访问。
IPv4 和 IPv6 也必须分开检查:
sudo iptables -L -n -v --line-numbers
sudo ip6tables -L -n -v --line-numbers
重点看规则顺序和计数器
iptables 通常按照链中的顺序匹配。对同一个数据包来说,前面的终止性规则已经执行 DROP 或 REJECT,后面的 ACCEPT 不会再次生效。
例如下面的顺序就存在典型冲突:

num pkts bytes target prot opt in out source destination
1 120 9600 DROP all -- * * 0.0.0.0/0 0.0.0.0/0
2 0 0 ACCEPT tcp -- * * 0.0.0.0/0 0.0.0.0/0 tcp dpt:443
第 2 行虽然显示了 443 放行,但数据包已经在第 1 行被丢弃。应重点观察:
- 早于 ACCEPT 的 DROP 或 REJECT 是否在增长;
- 443 ACCEPT 的计数器是否为 0;
- 规则是否位于
INPUT、FORWARD或其他链; - 规则中的协议、端口、来源地址和入接口是否与实际请求一致。
可以单独检查一个预期规则是否存在:
sudo iptables -C INPUT -p tcp --dport 443 -j ACCEPT
echo $?
返回 0 只表示存在一条完全匹配的规则,不代表数据包已经走到这条规则,也不代表前面没有 DROP。因此还要结合计数器和抓包结果判断。
如果希望观察一次请求前后的计数变化,可以先查看:
sudo iptables -L INPUT -n -v --line-numbers
然后发起一次测试,再次查看:
sudo iptables -L INPUT -n -v --line-numbers
也可以使用:
watch -n 1 'sudo iptables -L INPUT -n -v --line-numbers'
规则计数器的解释应当结合抓包:
- 抓包看到 SYN,早期 DROP 计数增加:优先修复规则顺序或错误的来源匹配;
- 抓包看到 SYN,443 ACCEPT 计数增加,但仍无法建立连接:查看服务监听、OUTPUT、返回路径;
- 抓包看不到 SYN,所有主机规则计数不变:不要继续修改 iptables,回到 DNS 和上游访问控制;
- ACCEPT 计数增加并且 TCP 握手完成:防火墙已经不是主要阻断点。
检查 INPUT、FORWARD 和 OUTPUT 是否看错链
访问运行在宿主机上的 Nginx,通常经过 INPUT 链;如果端口实际转发到容器或其他内部地址,则可能经过 FORWARD 链。此时只看 INPUT 可能得出错误结论。
sudo iptables -L INPUT -n -v --line-numbers
sudo iptables -L FORWARD -n -v --line-numbers
sudo iptables -L OUTPUT -n -v --line-numbers
如果网站服务在本机直接监听,重点是 INPUT 和服务监听状态。如果存在端口转发,则还需要核对:
- 是否有正确的 DNAT 或端口映射;
FORWARD默认策略是否为 DROP;- 转发链是否允许已建立连接返回;
- 内部目标地址是否仍然存在。
不要为了验证而直接执行 iptables -F。清空规则会同时移除 SSH、回程流量和其他已有的安全策略,可能导致远程失联。
典型根因:ACCEPT 规则存在,但被更早的 DROP 或另一套规则接管
这是“iptables 已放行但仍无法访问”中最容易误判的配置冲突之一。常见表现是:
iptables -L中能看到 443 的 ACCEPT;- 访问仍然超时;
- ACCEPT 计数器不增长,或者前面的 DROP 计数器增长;
nft list ruleset、ip6tables或 UFW 中还存在另一条限制;- IPv4 检查通过,但海外客户端实际优先使用 IPv6。
定位时可以按以下顺序执行:
sudo iptables -L INPUT -n -v --line-numbers
sudo ip6tables -L INPUT -n -v --line-numbers
sudo nft list ruleset
sudo ufw status numbered
如果规则由 UFW 管理,应在 UFW 的规则来源中修改,而不是只用 iptables 临时插入一条规则。若使用 nftables,则应修改 nftables 的持久化配置,并在加载前进行语法检查。若使用传统 iptables,则应把放行规则放在对应 DROP 之前,并通过现有的持久化机制保存。
在确认网站确实需要对公网提供 80/443,且已经完成备份、保留控制台入口后,可以用类似方式临时验证规则顺序:
sudo iptables -I INPUT 1 -p tcp -m conntrack \
--ctstate NEW -m multiport --dports 80,443 -j ACCEPT
IPv6 需要单独验证:
sudo ip6tables -I INPUT 1 -p tcp -m conntrack \
--ctstate NEW -m multiport --dports 80,443 -j ACCEPT
这些命令只是用于在明确规则后端和适用范围后进行验证。不要把它们直接用于所有服务器,也不要将 SSH 端口一并加入公网放行范围。网站端口可以按业务需要开放,管理端口应采用来源限制、密钥认证和单独的防护策略。
验证成功后,应把修改写入当前使用的规则管理方式。如果服务器已经安装并使用 netfilter-persistent,可以先确认命令存在,再保存:
command -v netfilter-persistent
sudo netfilter-persistent save
如果没有使用该服务,不要为了保存规则而临时引入另一套管理工具。应修改已有的 UFW、nftables 或系统启动配置,并在维护窗口中重载和验证。
回滚时使用变更前的备份,例如:
sudo iptables-restore < /root/iptables-2026-01-01-120000.v4.rules
sudo ip6tables-restore < /root/ip6tables-2026-01-01-120000.v6.rules
文件名以实际备份为准。恢复操作同样可能切断 SSH,建议从服务器控制台执行,或确保已有可靠的回滚入口。
第四层:检查端口监听和服务状态
防火墙允许连接,不代表端口上一定有服务。先查看 80、443 以及实际业务端口:
sudo ss -lntp | grep -E ':(80|443)\s'
典型输出可以这样理解:

LISTEN 0 511 0.0.0.0:443 0.0.0.0:* users:(("nginx",pid=1234,fd=8))
LISTEN 0 511 127.0.0.1:8080 0.0.0.0:* users:(("app",pid=1357,fd=7))
0.0.0.0:443:监听所有 IPv4 地址;127.0.0.1:443:只有服务器本机可以访问;[::]:443:监听 IPv6,具体是否同时接受 IPv4 还要看系统参数和服务配置;- 没有任何输出:服务未启动、监听了其他端口,或配置加载失败。
如果服务只监听 127.0.0.1,而 iptables 已经放行外部流量,外部请求仍然会失败。此时应修改服务监听地址或让 Nginx 在公网地址监听,而不是继续增加防火墙放行规则。
本机可以先验证服务是否响应:
curl -vk --connect-timeout 5 https://127.0.0.1/
curl -v --connect-timeout 5 http://127.0.0.1/
如果 HTTPS 依赖域名证书、SNI 或虚拟主机,可以使用:
curl -vk --resolve example.com:443:127.0.0.1 https://example.com/
如果服务器使用 Nginx,还应检查配置和服务日志:
sudo nginx -t
sudo systemctl status nginx --no-pager
sudo journalctl -u nginx --since "15 minutes ago" --no-pager
nginx -t 失败时不要直接重启服务。先修复语法或引用文件问题,再使用平滑重载。应用服务也应采用相同原则:先检查配置,再查看状态和启动日志。
第五层:确认 TCP 建立后是否被应用拒绝
如果抓包显示三次握手完成,curl -vk 能够看到 TLS 协商或 HTTP 响应,那么 iptables 已经不是主要问题。接下来检查:
- Nginx
server_name是否匹配实际域名; - HTTPS 证书和 SNI 配置是否正确;
- 应用是否根据来源 IP 返回 403;
- 是否存在请求频率限制或连接数限制;
- 反向代理到后端时,后端地址是否可达;
- 应用日志中记录的来源地址是否为真实测试端地址。
可根据返回码快速判断:
| HTTP 状态 | 常见方向 |
|---|---|
| 400、421 | Host、SNI 或协议配置不匹配 |
| 401、403 | 认证、来源 IP 白名单或访问控制 |
| 404 | 虚拟主机或 URL 路径不匹配 |
| 429 | 应用或反向代理限流 |
| 502、504 | Nginx 到后端服务失败 |
| 5xx | 应用异常、后端不可用或超时 |
如果海外请求已经出现在 Nginx access log 中,就说明请求至少到达了 Web 服务层。此时继续调整 iptables,通常不会解决 403、429 或 502。
检查返回路径和内核反向路径校验
在能够看到入站 SYN,但客户端收不到响应时,需要检查服务器返回路径:
ip route get <海外测试源IP>
ip -6 route get <海外测试源IPv6>
如果 IPv4 或 IPv6 没有合适的路由,或者返回接口与入接口不一致,可能出现连接建立不完整。还可以查看反向路径校验参数:
sysctl net.ipv4.conf.all.rp_filter
sysctl net.ipv4.conf.default.rp_filter
rp_filter 用于校验来源地址是否应当从当前接口到达。在存在非对称路径的环境中,过严的反向路径校验可能丢弃数据包。但不要为了“先恢复访问”就直接全局关闭它。应先结合抓包、路由表和上游网络信息确认确实属于反向路径问题,再针对具体接口和维护窗口调整,并记录回滚值。
如果请求使用 IPv6,还要查看:
ip -6 route
ip -6 addr
IPv6 地址存在并不代表默认路由、邻居发现和防火墙策略都已完成。
为海外访问保留必要端口,同时防护 SSH 暴力破解
网站访问和服务器管理不应使用同一套放行思路。对外提供网站时,通常只需要按照业务开放 80/443;SSH 等管理端口应尽量限制来源地址,不要因为网站需要海外访问,就把所有管理端口对公网开放。
先确认 SSH 的实际监听端口
sudo ss -lntp | grep ssh
sudo sshd -T | grep '^port '
如果允许维护来源地址固定,优先使用来源白名单。修改前必须确认白名单中包含当前维护出口,否则可能立即失去 SSH 连接。
如果使用 SSH 密钥登录,可以在确认新密钥能够独立登录后,再考虑关闭密码认证或限制 root 直接登录。修改 SSH 配置前先备份,并检查语法:
sudo cp -a /etc/ssh/sshd_config \
"/etc/ssh/sshd_config.bak.$(date +%F-%H%M%S)"
sudo sshd -t
只有 sshd -t 成功,并且当前 SSH 会话仍然保持可用时,才考虑平滑重载:
sudo systemctl reload ssh
不要在没有验证密钥、没有控制台入口的情况下直接关闭密码登录。
使用连接速率限制时注意规则顺序
如果确实需要在主机层限制 SSH 新连接,可以使用 hashlimit 进行示例性限制,但必须先确认模块可用:
sudo iptables -m hashlimit -h >/dev/null
echo $?
例如,下面是针对 TCP/22 的参考规则:
sudo iptables -I INPUT 1 -p tcp --dport 22 \
-m conntrack --ctstate NEW \
-m hashlimit \
--hashlimit-name ssh_new \
--hashlimit-above 10/minute \
--hashlimit-burst 10 \
--hashlimit-mode srcip \
--hashlimit-srcmask 32 \
-j DROP
这条规则只适用于已经确认使用传统 iptables 兼容方式、SSH 端口确实为 22、且没有被 UFW 或其他管理器覆盖的场景。阈值只是参考值,办公出口、跳板机或多人共享公网地址可能会被误伤。
还要特别注意规则顺序:如果前面已经有一条“所有新 SSH 连接直接 ACCEPT”的规则,后面的限速规则不会生效。需要结合:
sudo iptables -L INPUT -n -v --line-numbers
查看限速规则是否早于宽泛的 SSH 放行规则。IPv6 管理流量还需要单独配置和验证 ip6tables 或 nftables IPv6 规则。
无论使用哪种防护方式,都应持续查看认证日志:
sudo journalctl -u ssh --since "30 minutes ago" --no-pager
如果日志中出现大量失败登录,应优先检查密钥认证、来源限制和账户策略,而不是通过封禁所有海外地址来解决网站访问问题。
修复后的完整验证方法
修复规则或服务后,不要只看配置文件中是否出现了 ACCEPT。至少完成以下验证:
- 在海外测试端分别执行
curl -4和curl -6,记录连接是否建立、TLS 是否完成以及 HTTP 状态码。 - 在服务器端运行短时间抓包,确认测试端 SYN 到达,并观察是否完成三次握手。
- 查看 iptables 或 nftables 对应规则的计数器,确认命中了预期的 ACCEPT,而不是更早的 DROP。
- 使用
ss -lntp确认端口仍然由预期服务监听。 - 查看 Nginx 和应用日志,确认请求没有在应用层被拒绝。
- 如果修改了持久化配置,在计划维护窗口重载或重启后再次验证。
- 分别测试域名、直接地址和 IPv4/IPv6,避免只验证其中一个入口。
可以使用以下命令作为复核入口:
sudo ss -lntp | grep -E ':(80|443)\s'
sudo iptables -L INPUT -n -v --line-numbers
sudo ip6tables -L INPUT -n -v --line-numbers
sudo nft list ruleset
验证成功的标准不是“配置文件里有一行放行规则”,而是:
- 测试请求解析到了正确地址;
- 数据包确实到达服务器;
- 正确的防火墙链命中了放行规则;
- 服务在对应地址和端口监听;
- TCP 和 TLS 能够完成;
- 应用返回预期的 HTTP 状态码;
- 重载或重启后规则仍然存在。
设置复发监控点
这类问题容易在系统重启、规则管理器重新加载、证书更新、DNS 调整或应用发布后再次出现。建议为 Ubuntu 香港服务器保留以下监控和变更记录:
- A、AAAA 记录是否发生变化;
- 80/443 的监听地址和端口是否变化;
- INPUT、FORWARD 中 DROP、REJECT、ACCEPT 计数是否异常;
- 海外测试端的 TCP 建连成功率和 HTTP 状态码;
- Nginx 访问日志中的 4xx、5xx、429 是否突然增加;
- SSH 失败认证数量和来源集中度;
- iptables 后端是否从 legacy 切换为 nftables;
- UFW、nftables 或持久化服务是否在重启后覆盖了临时规则。
当再次出现“iptables 已放行但海外无法访问”时,优先拿到四项证据:测试端实际使用的 IP 地址族、服务器 tcpdump 是否看到 SYN、命中规则的计数器变化、服务是否处于监听状态。凭这四项信息,通常可以快速判断问题是在服务器外部、iptables 规则路径、服务监听,还是应用层访问控制,而不必反复盲目增加放行规则。