代理网络故障排查指南:从 DNS、Fake-IP、TUN 到节点连接
适用系统:macOS、Ubuntu、Windows
适用工具:Shadowrocket、v2rayN、Clash、sing-box、Xray、Hysteria2 等
典型现象:IP 节点正常、域名节点超时;延迟显示-1;开代理后 DNS 异常;手机正常但电脑不正常
脱敏说明:本文中的
example.com/.net/.org均为文档示例域名;192.0.2.0/24、198.51.100.0/24、203.0.113.0/24均为文档示例地址段。接口名、端口和局域网地址也经过泛化,实际操作时请替换为本机信息。
一、先建立正确的排障思路
代理软件出现“节点超时”时,问题不一定在代理服务器。一次完整的代理连接至少经过以下几层:
应用程序
↓
系统 DNS / 代理 DNS
↓
域名解析为服务器 IP
↓
本机路由、系统代理或 TUN 虚拟网卡
↓
TCP 或 UDP 到达代理服务器端口
↓
TLS / Reality / Hysteria2 等协议握手
↓
代理服务器访问目标网站
任何一层失败,都可能在客户端里表现为:
延迟 -1
超时
测速跳过
连接失败
no servers could be reached
因此不要一开始就反复修改节点参数。正确顺序是:
- 确认域名能否解析。
- 确认解析结果是否正确。
- 确认服务器端口能否到达。
- 确认流量实际走了哪个接口和路由。
- 最后再检查代理协议、TLS、UUID、密码等配置。
二、先用现象快速分类
1. IP 节点正常,域名节点全部失败
这是非常有价值的特征:
IP 节点不需要 DNS → 正常
域名节点需要 DNS → 失败
优先检查:
- 系统配置了失效 DNS;
- DNS 查询回退时间过长;
- 存在错误的 AAAA/IPv6 记录;
- TUN 接管 DNS 后形成循环;
- Fake-IP 被错误用于代理服务器自身域名;
- DoH 必须经过尚未建立的代理才能访问。
2. 域名能解析,但端口连接失败
优先检查:
- 域名是否指向旧 IP;
- 防火墙是否开放端口;
- 服务是否监听正确的 TCP/UDP 端口;
- Cloudflare 小橙云是否代理了不支持的端口;
- 当前网络是否限制 UDP 或特定端口。
3. 域名和端口都正常,但客户端仍失败
继续检查:
- VLESS UUID、Reality 公钥、Short ID;
- TLS SNI、证书域名;
- WebSocket Path、Host;
- Hysteria2 密码和 TLS 配置;
- 客户端 Core 类型及版本;
- 系统时间是否准确。
三、DNS、TUN、Fake-IP 到底是什么关系
1. 普通 DNS
DNS 把域名转换成真实 IP:
node-a.example.com → 203.0.113.10
如果 DNS 不可用,使用域名的代理节点连第一步都无法完成。
2. TUN 模式
TUN 模式会创建虚拟网卡并接管系统流量。它比“系统 HTTP 代理”覆盖范围更广,可以处理许多不遵循系统代理设置的应用和 UDP 流量。
但 TUN 也更容易产生循环:
解析代理节点域名
↓
DNS 请求被 TUN 接管
↓
DNS 被配置为通过代理访问
↓
代理节点尚未完成域名解析
↓
互相等待,最终超时
3. Fake-IP
Shadowrocket、Clash 等工具可能给应用返回一个保留地址,例如:
node-a.example.com → 198.18.0.18
198.18.0.0/15 是保留测试网段,常被代理软件作为 Fake-IP 地址池。它的工作方式是:
应用查询域名
↓
代理 DNS 返回 198.18.x.x
↓
应用连接这个 Fake-IP
↓
TUN 根据内部映射还原原始域名
↓
按代理规则建立真实连接
Fake-IP 本身不是 DNS 污染。对普通网站来说,这种机制很正常。
但代理服务器自身的域名通常要能够在代理建立前解析。如果代理软件没处理好启动域名,可能出现:
连接代理需要解析节点域名
解析节点域名又依赖代理
这时可把节点域名加入 Shadowrocket 的“总是真实 IP(Always Real IP)”。
4. DoH 的启动依赖
DoH 是通过 HTTPS 查询 DNS,例如:
https://cloudflare-dns.com/dns-query
https://dns.google/dns-query
它可以提高 DNS 查询的完整性和隐私性,但它自身也需要网络连接。如果 DoH 被设置为通过代理访问,就可能发生:
要解析代理节点域名
↓
需要访问 DoH
↓
DoH 需要经过代理
↓
代理尚未建立
↓
超时
解决方法是在备用 DNS 中保留能够直连的普通 DNS,例如:
路由器 DNS
223.5.5.5
119.29.29.29
普通 DNS 先完成代理节点的启动解析,代理建立后再使用 DoH。
四、通用排查流程
无论使用哪个系统,都可以按下面的顺序进行。
第一步:记录节点信息
至少确认:
服务器地址:域名还是 IP
端口:例如 30443、31443
协议:VLESS / Hysteria2 / VMess 等
传输层:TCP / UDP / WebSocket / gRPC
TLS 类型:TLS / Reality
第二步:比较域名与 IP
如果同一台服务器:
- 填写 IP 时正常;
- 填写域名时失败;
优先排查 DNS,而不是服务器性能。
第三步:分别测试系统 DNS 和指定 DNS
例如:
dig example.com
dig @223.5.5.5 example.com
如果指定 DNS 很快,而普通 dig 超时,问题在系统当前 DNS 路径。
第四步:测试端口
TCP 节点可以使用 nc、Test-NetConnection 等工具。
注意:Hysteria2 主要使用 UDP,普通 TCP 端口测试不能证明 Hysteria2 一定可用,也不能因为 TCP 测试失败就断定 UDP 服务失败。
第五步:关闭 TUN 做对照实验
临时关闭:
- TUN/VPN 模式;
- 系统代理;
- 代理软件 DNS 接管。
重新测试域名。如果关闭 TUN 后恢复,重点检查代理 DNS、Fake-IP 和路由循环。
五、Ubuntu 排查方法
1. 检查系统解析结果
getent ahosts node-a.example.com
示例:
203.0.113.10 STREAM node-a.example.com
203.0.113.10 DGRAM
203.0.113.10 RAW
getent 使用系统名称解析路径,结果比只查看某个 DNS 文件更接近普通程序的行为。
2. 查看 systemd-resolved 状态
resolvectl query node-a.example.com
resolvectl status
resolvectl status enpXs0
重点观察:
- 当前使用哪个网络接口;
Current DNS Server;DNS Servers;- 查询耗时是否异常。
例如:
Current DNS Server: 192.168.1.1
DNS Servers: 192.168.1.1 223.5.5.5
3. 使用 dig 检查实际 DNS
dig A node-a.example.com
dig AAAA node-a.example.com
dig @192.168.1.1 node-a.example.com
dig @223.5.5.5 node-a.example.com
判断:
A:IPv4 地址;AAAA:IPv6 地址;SERVER:实际回答查询的 DNS;Query time:最后一次成功查询的耗时。
注意,dig 前面如果出现多个超时,最后的 Query time: 5 msec 只代表最后一个 DNS 的耗时,不包含此前等待失效 DNS 的总时间。建议加上:
time dig node-a.example.com
查看整个命令真实耗时。
4. 实际案例:失效 DNS 导致 v2rayN 域名节点显示 -1
故障时 /etc/resolv.conf 内容为:
nameserver 192.168.10.99
nameserver 192.168.10.100
nameserver 192.168.1.1
nameserver 8.8.8.8
nameserver 8.8.4.4
其中 192.168.10.99 和 192.168.10.100 已经不可达。每次查询都会先等待它们超时,最后才使用 192.168.1.1。
表现为:
communications error to 192.168.10.99#53: timed out
communications error to 192.168.10.100#53: timed out
系统最终能得到正确结果,但总耗时超过 v2rayN 节点测试的等待时间,于是:
域名节点 → -1
IP 节点 → 正常
修复 NetworkManager DNS
在 Ubuntu 网络设置中:
IPv4:Automatic (DHCP)
DNS Automatic:关闭
DNS:192.168.1.1, 223.5.5.5
Routes Automatic:开启
也可以使用命令。先查看连接名称:
nmcli connection show --active
假设连接名为“有线连接 1”:
sudo nmcli connection modify "有线连接 1" ipv4.ignore-auto-dns yes
sudo nmcli connection modify "有线连接 1" ipv4.dns "192.168.1.1 223.5.5.5"
sudo nmcli connection down "有线连接 1"
sudo nmcli connection up "有线连接 1"
检查 /etc/resolv.conf
ls -l /etc/resolv.conf
cat /etc/resolv.conf
Ubuntu 使用 systemd-resolved 时,标准结构通常是:
/etc/resolv.conf -> /run/systemd/resolve/stub-resolv.conf
内容为:
nameserver 127.0.0.53
options edns0 trust-ad
search .
如果 /etc/resolv.conf 被改成普通静态文件,可以先备份,再恢复符号链接:
sudo cp -a /etc/resolv.conf /etc/resolv.conf.backup
sudo ln -sf /run/systemd/resolve/stub-resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
sudo resolvectl flush-caches
验证:
ls -l /etc/resolv.conf
time dig node-a.example.com
不要轻易对 /etc/resolv.conf 使用 chattr +i。这可能阻止 NetworkManager、VPN 和系统 DNS 正常切换。
5. 检查是谁修改了 resolv.conf
搜索永久配置:
sudo grep -RIn "192\.168\.1\.99\|192\.168\.1\.100" \
/etc/NetworkManager \
/etc/netplan \
/etc/systemd \
/etc/dhcp \
/etc/openvpn \
2>/dev/null
搜索命令历史:
history | grep -E "resolv.conf|192.168.10.99|192.168.10.100"
sudo grep -E "resolv.conf|192.168.10.99|192.168.10.100" \
/root/.bash_history 2>/dev/null
如果问题会再次出现,可以使用 auditd 记录修改者:
sudo apt install auditd
sudo auditctl -w /etc/resolv.conf -p wa -k resolv_conf_change
sudo ausearch -k resolv_conf_change -i
重点查看:
exe=
comm=
pid=
6. 测试 TCP 端口
nc -vz node-a.example.com 30443
nc -vz node-b.example.net 31443
再与 IP 对比:
nc -vz 203.0.113.10 30443
nc -vz 198.51.100.20 31443
如果域名失败、IP 成功,仍然优先检查 DNS 或 IPv6。
7. 检查 IPv4/IPv6
dig A example.com
dig AAAA example.com
nc -4 -vz example.com 443
nc -6 -vz example.com 443
如果 IPv4 成功而 IPv6 失败:
- 检查错误 AAAA 记录;
- 检查本机 IPv6 默认路由;
- 将代理 Core 的查询策略临时设为 IPv4 Only/UseIPv4。
8. 检查路由和代理环境变量
ip address
ip route
ip rule
env | grep -i proxy
检查某个目标实际走哪个接口:
ip route get 203.0.113.10
使用 curl 查看连接过程:
curl -v --connect-timeout 5 https://example.com/
curl -4 -v --connect-timeout 5 https://example.com/
curl -6 -v --connect-timeout 5 https://example.com/
六、macOS 排查方法
1. 查看 macOS 实际 DNS
macOS 不应只看 /etc/resolv.conf。最重要的命令是:
scutil --dns
提取 DNS 地址:
scutil --dns | grep 'nameserver\[[0-9]*\]'
输出可能同时包含:
198.18.0.2 # Shadowrocket/TUN DNS
192.0.2.53 # Wi-Fi DHCP 下发 DNS
192.0.2.54
查看 Wi-Fi 是否手动配置 DNS:
networksetup -getdnsservers Wi-Fi
如果显示:
There aren't any DNS Servers set on Wi-Fi.
意思是没有手动配置,正在使用 DHCP 自动下发的 DNS,并不是没有 DNS。
列出网络服务:
networksetup -listallnetworkservices
然后使用输出中的准确名称,例如:
networksetup -getdnsservers "USB 10/100 LAN"
2. 测试系统 DNS 与指定 DNS
time dig node-a.example.com
dig @192.168.1.1 node-a.example.com
dig @223.5.5.5 node-a.example.com
dscacheutil -q host -a name node-a.example.com
如果普通查询返回:
198.18.0.18
而指定 DNS 返回:
203.0.113.10
说明代理软件正在使用 Fake-IP。这在 TUN 模式下通常是正常现象。
3. 清理 macOS DNS 缓存
sudo dscacheutil -flushcache
sudo killall -HUP mDNSResponder
成功后通常没有输出。
4. 修改和恢复 Wi-Fi DNS
手动设置:
sudo networksetup -setdnsservers Wi-Fi 192.168.1.1 223.5.5.5
恢复 DHCP 自动 DNS:
sudo networksetup -setdnsservers Wi-Fi Empty
5. 实际案例:Shadowrocket 的 Fake-IP 与 Always Real IP
Shadowrocket 开启时:
resolver #1
nameserver[0] : 198.18.0.2
if_index : utunN
普通查询得到:
node-a.example.com → 198.18.0.18
node-b.example.net → 198.18.0.19
直接查询路由器或公共 DNS 得到真实地址:
node-a.example.com → 203.0.113.10
node-b.example.net → 198.51.100.20
这证明权威 DNS 记录没有问题,198.18.x.x 是 Shadowrocket 的 Fake-IP。
如果域名被用作代理节点服务器地址,可在 Shadowrocket 当前配置的“总是真实 IP”中加入:
*.example.com
*.example.net
*.example.org
对应配置语义类似:
[General]
always-real-ip = *.example.com, *.example.net, *.example.org
修改后验证 Shadowrocket 内部 DNS:
dig @198.18.0.2 node-a.example.com +time=2 +tries=1
dig @198.18.0.2 node-b.example.net +time=2 +tries=1
SERVER 仍然可以是:
198.18.0.2
关键是 ANSWER 应返回真实 IP,而不是 Fake-IP。
6. 实际案例:只有 DoH 导致代理启动循环
原 DNS 覆写只有:
https://cloudflare-dns.com/dns-query
https://dns.google/dns-query
加入 Always Real IP 后,Shadowrocket 必须向上游查询节点真实 IP。但 DoH 连接可能被设置为经过代理,于是:
解析节点域名
↓
需要访问 DoH
↓
DoH 需要代理
↓
代理节点尚未解析
↓
超时
解决方法是在“备用 DNS”中加入能够在代理建立前直接使用的普通 DNS:
192.168.1.1
223.5.5.5
119.29.29.29
建议结构:
DNS 覆写:
https://cloudflare-dns.com/dns-query
https://dns.google/dns-query
备用 DNS:
192.168.1.1
223.5.5.5
119.29.29.29
其中:
192.168.1.1是当前路由器 DNS,换网络后可能不可用;223.5.5.5和119.29.29.29可用于其他网络下的启动解析;- DoH 在代理建立后继续提供加密 DNS;
- 普通备用 DNS 负责打破代理启动阶段的循环依赖。
如果服务器 IP 长期固定,也可以在 [Host] 中为节点入口指定真实 IP:
[Host]
node-a.example.com = 203.0.113.10
node-b.example.net = 198.51.100.20
但如果服务器 IP 会变化,固定 Host 会造成新的旧 IP 问题,因此优先解决上游 DNS 路径。
7. 检查 macOS 路由
netstat -rn
route -n get 203.0.113.10
ifconfig
关注:
- 默认路由是
en0还是utun; - 是否存在
0.0.0.0/1、128.0.0.0/1等 TUN 分流路由; - 节点服务器 IP 是否被错误送回 TUN;
- 到节点服务器的启动连接是否应该从物理网卡直出。
测试连接:
nc -vz node-a.example.com 30443
curl -v --connect-timeout 5 https://example.com/
七、Windows 排查方法
1. 查看 DNS 配置
传统命令:
ipconfig /all
PowerShell:
Get-DnsClientServerAddress
Get-DnsClientServerAddress -AddressFamily IPv4
重点检查:
- 当前正在使用的物理网卡;
- 是否残留旧路由器、公司内网或 VPN DNS;
- TUN 虚拟网卡是否配置了单独 DNS;
- 同时存在多个网卡时,哪个网卡优先。
2. 查询域名
Resolve-DnsName node-a.example.com
Resolve-DnsName node-b.example.net
分别查询 IPv4 和 IPv6:
Resolve-DnsName node-a.example.com -Type A
Resolve-DnsName node-a.example.com -Type AAAA
传统工具:
nslookup node-a.example.com
nslookup node-a.example.com 223.5.5.5
判断逻辑:
- 系统查询失败,指定 DNS 成功:系统 DNS 配置有问题;
- A 正常,AAAA 指向不可用 IPv6:检查 IPv6;
- 域名解析到旧 IP:检查 DNS 缓存和记录 TTL;
- 域名解析正常但 v2rayN 显示
-1:继续检查端口、TUN 和 Core 日志。
3. 测试 TCP 端口
Test-NetConnection node-a.example.com -Port 30443
Test-NetConnection node-b.example.net -Port 31443
结果:
TcpTestSucceeded : True
说明 DNS 解析及 TCP 三次握手成功。
再与 IP 对比:
Test-NetConnection 203.0.113.10 -Port 30443
Test-NetConnection 198.51.100.20 -Port 31443
同样注意,Hysteria2 使用 UDP,Test-NetConnection 的 TCP 结果不能完整验证 Hysteria2。
4. 查看 Windows 系统代理
WinHTTP 代理:
netsh winhttp show proxy
查看当前用户 Internet 代理:
Get-ItemProperty \
'HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings' |
Select-Object ProxyEnable, ProxyServer, AutoConfigURL
如果代理软件已经退出,但 ProxyEnable 仍开启,浏览器可能继续访问一个已经不存在的本地代理端口。
5. 查看路由和网卡
route print
Get-NetAdapter
Get-NetIPConfiguration
Get-NetRoute -AddressFamily IPv4 |
Sort-Object RouteMetric, InterfaceMetric
检查:
- 默认路由
0.0.0.0/0; - 是否存在 TUN 添加的
0.0.0.0/1和128.0.0.0/1; - 代理服务器 IP 是否错误走入 TUN;
- VPN 断开后是否留下静态路由。
查看去往某个地址的路径:
tracert 203.0.113.10
6. 清除 DNS 和网络栈
先执行影响较小的 DNS 清理:
ipconfig /flushdns
如果确认 Winsock 异常,再执行:
netsh winsock reset
winsock reset 通常需要重启电脑,不应把它作为每次故障的第一步。
7. 修改 Windows DNS
图形界面可以给当前网卡设置:
首选 DNS:223.5.5.5
备用 DNS:119.29.29.29
PowerShell 示例,先确认接口名称:
Get-NetAdapter
假设接口为 Ethernet:
Set-DnsClientServerAddress `
-InterfaceAlias "Ethernet" `
-ServerAddresses ("223.5.5.5","119.29.29.29")
恢复 DHCP 自动 DNS:
Set-DnsClientServerAddress `
-InterfaceAlias "Ethernet" `
-ResetServerAddresses
8. v2rayN 的针对性检查
如果 v2rayN 中:
IP 节点有延迟
域名节点全部 -1
按顺序执行:
Resolve-DnsName检查域名;Test-NetConnection测试 TCP 节点端口;- 关闭 v2rayN TUN/VPN 模式重新测速;
- 暂时关闭系统代理重新测试;
- 将 Core DNS 查询策略设为
UseIPv4或IPv4 Only; - 查看 Core 日志。
日志中重点搜索:
failed to lookup
no such host
DNS
timeout
network is unreachable
connection refused
context deadline exceeded
如果关闭 TUN 后域名立即恢复,通常不是节点配置错误,而是 TUN DNS 接管、路由或解析循环。
八、常用判断表
| 测试结果 | 最可能原因 | 下一步 |
|---|---|---|
| IP 节点正常,域名节点失败 | DNS、Fake-IP、TUN 循环 | 比较系统 DNS 和指定 DNS |
| 系统 DNS 失败,指定 DNS 成功 | 当前 DNS 配置异常 | 修改网卡 DNS、清缓存 |
| A 正常,AAAA 存在且 IPv6 不通 | IPv6 路由或错误 AAAA | 强制 IPv4 对照测试 |
| 域名和 IP 端口都失败 | 防火墙、服务、网络路径 | 检查监听端口和安全组 |
| TCP 端口成功,客户端仍失败 | 协议握手或客户端配置 | 检查 TLS、Reality、UUID |
| 关闭 TUN 后恢复 | TUN 路由或 DNS 循环 | 检查虚拟网卡、Fake-IP、DNS |
| Fake-IP 查询立即返回 198.18.x.x | 代理 DNS 正常接管 | 普通网站一般无需处理 |
| Always Real IP 域名查询超时 | 上游真实 DNS 无法启动 | 添加可直连备用 DNS |
| 手机正常、电脑失败 | 电脑本机 DNS/路由/客户端 | 不要先改服务器配置 |
九、建议保存的最小命令集
Ubuntu
getent ahosts example.com
resolvectl status
resolvectl query example.com
time dig example.com
dig @223.5.5.5 example.com
nc -vz example.com 443
ip route
ip route get 1.1.1.1
macOS
scutil --dns
networksetup -getdnsservers Wi-Fi
time dig example.com
dig @223.5.5.5 example.com
dscacheutil -q host -a name example.com
netstat -rn
route -n get 1.1.1.1
Windows
ipconfig /all
Get-DnsClientServerAddress
Resolve-DnsName example.com
nslookup example.com 223.5.5.5
Test-NetConnection example.com -Port 443
netsh winhttp show proxy
route print
十、实战:域名解析、路由确认与 NAS 双向测速
这一节把前面的理论串成一套可以重复执行的检查流程。以下地址均为脱敏示例:
| 用途 | 示例值 |
|---|---|
| 家庭路由器 / DNS | 192.168.50.1 |
| NAS 公司内网地址 | 192.168.60.20 |
| NAS Overlay 地址 | 10.20.30.10 |
| Shadowrocket Fake-IP DNS | 198.18.0.2 |
| 统一访问域名 | nas-media.example |
10.1 先确认“谁在解析”
不要只执行一次 ping 就判断 DNS 正常。按下面顺序分别检查系统解析器、指定 DNS 和 macOS 综合解析结果:
# 1. 使用系统当前选择的 DNS
dig +time=2 +tries=1 github.com
# 2. 明确询问家庭路由器 DNS
dig +time=2 +tries=1 @192.168.50.1 github.com
# 3. 明确询问 Shadowrocket Fake-IP DNS
dig +time=2 +tries=1 @198.18.0.2 github.com
# 4. 查看 macOS 实际解析结果,包含 /etc/hosts、缓存和系统 DNS
dscacheutil -q host -a name nas-media.example
# 5. 查看当前 DNS 作用域
scutil --dns | grep nameserver
这里有一个重要区别:
dig直接向 DNS 服务器发起查询,不读取/etc/hosts。dscacheutil走 macOS 系统解析链,会受到/etc/hosts、缓存和作用域 DNS 影响。- Shadowrocket 配置里的
[Host]是客户端内部映射。浏览器经过 Shadowrocket 时可能识别它,但命令行程序未必读取这项映射。
因此,出现“浏览器能打开,但 iperf3 不认识域名”时,并不矛盾。先检查:
grep -n 'nas-media.example' /etc/hosts
dscacheutil -q host -a name nas-media.example
dig +short @192.168.50.1 nas-media.example
如果希望所有 macOS 命令行程序都得到同一个地址,应在真正使用的局域网 DNS 上建立记录,或谨慎写入 /etc/hosts;不要把 Shadowrocket 的 [Host] 当成全系统 DNS。
10.2 Fake-IP 查询超时,不一定是上游 DNS 坏了
若 dig @192.168.50.1 github.com 成功,而 dig @198.18.0.2 github.com 超时,应继续检查 Fake-IP 地址走哪个接口:
route -n get 198.18.0.2
route -n get 192.168.60.20
netstat -rn -f inet | grep -E '198\.18|192\.168\.60'
正确情况下,198.18.0.2 应由 Shadowrocket 的 utun 接口接管。如果它错误地走物理网卡 en0,系统会把 DNS 包发到一个并不存在于真实局域网中的地址。
可在外出配置中明确包含 Fake-IP 网段和需要代理的 NAS 网段:
[General]
tun-included-routes = 198.18.0.0/15,192.168.60.0/24
dns-server = 192.168.50.1
fallback-dns-server = 192.168.50.1
198.18.0.0/15 是常见 Fake-IP 地址池,不应把它配置成 TUN 排除路由。修改后重启 Shadowrocket 的隧道,再重新执行 route、dig 和 curl 三组测试:
dig +time=2 +tries=1 @198.18.0.2 github.com
curl -I https://github.com
curl -I http://nas-media.example:5050/
10.3 用连接地址判断到底走了哪条隧道
同一个名字可能在不同场景解析到不同地址:
dscacheutil -q host -a name nas-media.example
route -n get 10.20.30.10
route -n get 192.168.60.20
执行 iperf3 时,首行会直接显示最终连接目标。例如:
local 198.18.0.1 port 54000 connected to 192.168.60.20 port 5201
这通常表示流量进入了 Shadowrocket TUN,并由 Hysteria 节点访问 NAS 内网地址。若显示:
local 192.168.50.100 port 54000 connected to 10.20.30.10 port 5201
则目标是 Overlay 地址,流量更可能走 ZeroTier,而不是 Hysteria。测速前必须先确认最终目标,否则两次结果没有可比性。
10.4 在 NAS 上启动 iperf3 服务
为了避免 Docker 端口回环导致 192.168.60.20:5201 在 NAS 自身无法连接,推荐让 iperf3 容器使用 host 网络:
docker rm -f iperf3-server 2>/dev/null || true
docker run -d \
--name iperf3-server \
--restart unless-stopped \
--network host \
networkstatic/iperf3 \
-s -p 5201
部分 Synology DSM 的 Docker 命令位于:
/var/packages/Docker/target/usr/bin/docker
启动后在 NAS 上确认监听和本机回环:
ss -lntp | grep 5201
iperf3 -c 127.0.0.1 -p 5201 -t 3
如果 127.0.0.1:5201 成功,而 NAS 自己访问其 LAN 地址失败,通常是 Docker bridge 的 hairpin / 回环路径问题,不是 Hysteria 只能传 UDP。Hysteria 底层使用 QUIC/UDP,但它承载的代理流可以是 TCP;iperf3 和 Web 服务的 TCP 流量都能通过 Hysteria 转发。
10.5 本地到 NAS:测试上传方向
iperf3 -c nas-media.example -p 5201 -P 4 -t 30
路径为:
本地电脑 -> Shadowrocket/v2rayN -> Hysteria Client
-> 公网 UDP/QUIC -> Hysteria Server -> NAS iperf3
参数含义:
-c:客户端模式。-P 4:使用 4 条并行 TCP 流,降低单流窗口和抖动造成的误判。-t 30:持续测试 30 秒,观察稳定阶段而不是瞬时峰值。
10.6 NAS 到本地:使用反向测试
iperf3 -c nas-media.example -p 5201 -P 4 -t 30 -R
-R 不代表连接方向反转。控制连接仍由本地电脑发起,但数据由 NAS 发送回本地,因此更接近“从 NAS 下载电影”的真实方向:
NAS iperf3 -> Hysteria Server -> 公网 UDP/QUIC
-> Hysteria Client -> 本地电脑
建议把两组结果放在一起记录:
| 测试 | 主要受限链路 |
|---|---|
不带 -R | 本地上行、NAS 所在网络下行 |
带 -R | NAS 所在网络上行、本地下载 |
家庭宽带标称 600 Mbps 下载,并不代表远程播放一定有 600 Mbps。播放公司 NAS 时,最常见瓶颈是公司出口上行、跨网质量、丢包和抖动。
10.7 Hysteria 上下带宽应该怎么设置
Hysteria 2 当前支持 Brutal、BBR 和 Reno。这里最容易被误解:
- 客户端填写
bandwidth.up/down时,对应方向会使用 Brutal。 - 删除某个方向的带宽值后,该方向使用
congestion指定的非 Brutal 控制器,默认是 BBR。 - 服务端的
bandwidth是每个客户端的最大收发速率限制。 - 服务端上传对应客户端下载,服务端下载对应客户端上传。
客户端示例:
server: nas-gateway.example.com:8443
auth: REPLACE_WITH_AUTH
bandwidth:
up: 40 mbps
down: 100 mbps
disableLossCompensation: true
congestion:
type: bbr
bbrProfile: standard
服务端限速示例:
listen: :8443
bandwidth:
up: 100 mbps
down: 50 mbps
disableLossCompensation: true
congestion:
type: bbr
bbrProfile: standard
若只供自己使用,通常可以删除服务端的 bandwidth 与 ignoreClientBandwidth,仅在客户端按当前接入网络设置。若明确不想使用 Brutal,则应删除客户端整个 bandwidth 段,让 Hysteria 使用 congestion.type: bbr 或 reno,而不是一边写固定带宽、一边说“关闭 Brutal”。
高带宽值不一定更快。填写超过真实可用带宽的值,可能造成队列堆积、丢包补偿和延迟抖动。建议从实测稳定吞吐的约 80% 开始,再用前面的正向、反向 iperf3 逐级增加。
官方参考:
10.8 一套可重复的最短排查顺序
1. dig @指定DNS 域名:DNS 服务器是否回答?
2. dscacheutil:系统最终把域名解析成什么?
3. route -n get:目标地址由 en0、utun 还是 ZeroTier 接管?
4. nc/curl:目标端口是否可达?
5. iperf3 正向:本地到 NAS 的稳定吞吐是多少?
6. iperf3 -R:NAS 到本地的稳定吞吐是多少?
7. 最后再调整 Hysteria bandwidth / congestion。
不要用一次 ping、浏览器能否打开、或客户端显示的“延迟 -1”替代这套分层检查。它们只能说明某一个探测方式的结果,不能单独证明 DNS、路由和隧道都正确。
十一、结语
代理故障最容易让人误判的地方,是所有问题最终都可能只显示一个“超时”。
真正高效的排查方法不是不断更换节点和参数,而是把连接拆成独立层次:
DNS 是否得到正确 IP?
端口是否能够到达?
路由是否走对接口?
TUN 是否形成循环?
Fake-IP 是否只用于普通流量?
DoH 是否依赖尚未建立的代理?
最后才是协议握手是否正确。
本次两个实际案例很好地说明了这一点:
- Ubuntu 中失效的
192.168.10.99/100DNS 让查询先等待多次超时,最终虽然能解析成功,但超过 v2rayN 测速时限,因此域名节点全部显示-1。 - macOS 中 Shadowrocket 的 Fake-IP 本身正常,但节点域名切换为 Always Real IP 后,需要真正访问上游 DNS。只有 DoH 时形成代理启动循环,加入普通备用 DNS 后,节点域名可以在代理建立前完成解析,连接随即恢复。
只要坚持“解析—端口—路由—代理—协议”的顺序,大部分看似复杂的代理网络故障都能迅速缩小范围。