今天处理了一个挺典型的 VPS 代理节点问题:订阅链接可以在服务器本机生成,但 Karing 导入时报错;后来订阅能导入了,14 个节点里又只有 2 个能测通。这个问题绕了一圈,最后发现核心不在客户端,也不是脚本坏了,而是云厂商防火墙、服务器监听端口和客户端网络路径要分开看。

Karing 导入订阅时报错,链接和路径已打码

现象

Karing 导入订阅时提示:

1
2
download profile failed:
HttpException: Connection closed before full header was received

订阅地址形态大概是这样:

1
http://34.4.xxx.xxx:220/****/v2rayn

这个报错很容易让人误以为是 Karing 解析失败,或者订阅格式不对。实际不是。Karing 还没拿到完整 HTTP 响应头,连接就在中途断了,所以它只能报“下载订阅失败”。

换句话说,第一步不是改订阅格式,而是确认这个 URL 从公网到底能不能完整返回内容。

先分清三层

这类问题最好按三层排:

1
2
3
客户端 Karing
-> 云厂商防火墙 / 安全组
-> VPS 内部服务和本机防火墙

不要一上来就重装脚本。脚本只负责在服务器上监听端口、生成订阅;云厂商防火墙不放行的话,服务在服务器里跑得再正常,公网也访问不到。

Google Cloud 的定位过程

SSH 进 Google Cloud VPS 后,先在服务器本机测试订阅服务:

1
curl http://127.0.0.1:220/****/v2rayn

本机能返回订阅内容,说明 nginxsing-box 这一层没有坏。再看监听端口:

1
ss -tulpen

可以看到订阅服务监听在 220,各协议节点监听在 88818892 附近的端口。服务器内部没问题,问题就转向云防火墙。

当时还用 cloudflared 发现了一个临时 tunnel 地址:

1
https://****.trycloudflare.com/****/v2rayn

这个地址可以正常导入 Karing,因为它走 Cloudflare Tunnel,不依赖 VPS 公网 IP 的 220 端口直接入站。它解决了“订阅导入”的燃眉之急,但不等于所有直连节点都通了。

Google Cloud VM 实例信息,项目、IP 和账号信息已打码

真正的修复是在 Google Cloud 后台新增一条 VPC 防火墙规则,放行脚本实际使用的端口:

1
2
3
4
TCP: 220, 8881, 8884, 8885, 8886, 8889, 8890, 8891, 8892
UDP: 8882, 8883, 8885, 8892
Source: 0.0.0.0/0
Target: all instances in the network

规则创建后,Karing 重新测速,原来大面积失败的节点恢复了。这说明 Google Cloud 这台机器的关键问题就是:服务端已经监听,云防火墙没有放行对应公网入站端口。

为什么 Cloudflare Tunnel 能导入,但直连节点不通

Cloudflare Tunnel 的方向和普通公网入站不一样。

普通直连节点是客户端主动连 VPS:

1
Karing -> VPS public IP:888x

这条路要求云防火墙、VPS 本机防火墙、服务监听都允许入站。

Cloudflare Tunnel 是 VPS 主动连 Cloudflare,再由 Cloudflare 转发:

1
2
VPS -> Cloudflare tunnel
Karing -> Cloudflare URL

这条路通常只需要 VPS 能出站访问 Cloudflare,所以即使云厂商没有放行 220888x 入站端口,tunnel URL 仍然可能能用。

这也是为什么有时“订阅能导入”不代表“所有节点都能用”。订阅下载和节点连接是两件事。

AWS Ohio 这台为什么不是同一个问题

AWS Ohio 这台也出现了类似现象:14 个节点里只有 vmess-wsvless-ws-tls 两个能测通,其他直连协议大面积失败。

AWS Ohio 节点测速异常,节点名已打码

但进 AWS 后台检查后,情况和 Google Cloud 不一样。

这台实例绑定的 Security Group 入站规则已经是:

1
All traffic / All protocols / 0.0.0.0/0

出站也是全放行。

AWS Security Group 入站出站规则,账号和规则 ID 已打码

继续检查子网关联的 Network ACL,也是默认结构:

1
2
Rule 100: Allow All, 0.0.0.0/0
Rule *: Deny All

Rule 100 会先命中,所以这不是 Network ACL 拦截。

再 SSH 到 AWS 机器上看服务:

1
2
3
systemctl is-active sing-box
ss -tulpen
iptables -S INPUT

sing-box 正常运行,端口也在监听。AWS 后台和系统本机都不是主要阻断点。

不过本机脚本的端口清单里漏了几个实际监听端口。我补齐了:

1
2
TCP: 8887, 8888
UDP: 8885

补完后,服务器内部规则和实际监听端口保持一致。这个动作更像是整理配置,不是像 Google Cloud 那样补云防火墙。因为 AWS 的 Security Group 本来已经全放行。

这次排障的结论

这类问题不要只看客户端红叉。客户端只能告诉你“连不上”,不能直接告诉你是哪一层挡住了。

更可靠的判断顺序是:

  1. 先在 VPS 本机访问订阅 URL,确认服务能返回内容。
  2. ss -tulpen 看服务到底监听了哪些 TCP/UDP 端口。
  3. 检查云厂商防火墙:Google Cloud 看 VPC Firewall,AWS 看 Security Group 和 Network ACL。
  4. 再看 VPS 本机防火墙:iptablesnftablesufw
  5. 如果 Cloudflare Tunnel 节点能通、直连 IP 节点不通,就重点查公网入站端口和客户端网络路径。

Google Cloud 这次是典型的云防火墙漏放行。AWS Ohio 这台则不是 Security Group 问题,后台已经全开;我只补齐了服务器本机端口清单,后续如果仍然只有 tunnel/WS 节点可用,就更像是直连公网 IP 或自定义端口在客户端当前网络路径上不稳定。

我会保留的做法

订阅链接尽量准备两套:

1
2
直连订阅:http://公网 IP:端口/****/v2rayn
Tunnel 订阅:https://****.trycloudflare.com/****/v2rayn

直连速度和延迟可能更好,但依赖云防火墙和公网线路。Tunnel 稳定性更好,尤其适合用来救急导入订阅。真正使用时,可以优先保留测通的节点,不要迷信“节点数量越多越好”。

这次最有用的经验是:看到 Karing 的 Connection closed before full header was received,先别急着改客户端。它往往是在提醒你,HTTP 连接连响应头都没拿完整,问题大概率还在链路或服务入口上。