1. 查看 Xray 实时日志
在服务器终端执行:
# 实时监控 access.log
tail -f /var/log/xray/access.log
然后在客户端点击连接测试(真连接延迟)。
- 情况 A:日志完全静止,没有任何新内容
- 结论:数据包根本没到达 Xray。
- 原因:绝对是网络层面的阻断。虽然你开了云服务商防火墙,但可能是:
- 系统内部防火墙(
iptables/nftables/SELinux)拦截。 - 运营商对该端口段的 UDP 进行了阻断(QoS)。
- 系统内部防火墙(
- 对策:换个端口试试(比如换成 5000-60000 之间的高位端口),或者检查本机
iptables。
- 情况 B:日志有滚动,但显示错误
- 内容:出现
invalid user、fails to parse或connection rejected。 - 结论:包到了,但钥匙对不上。
- 原因:客户端配置错误(UUID、Seed、协议类型不匹配)。
- 内容:出现
2. MTU (最大传输单元) 问题
mKCP对数据包大小非常敏感。默认 MTU 是 1350,但在某些网络环境(如 PPPoE拨号、使用了WireGuard/VPN 的网络、某些复杂的路由环境)中,1350 可能太大了,导致包被分片或丢弃。
- 尝试修改:在服务器配置的
kcpSettings中,手动指定一个较小的 MTU。"kcpSettings": { "mtu": 1200, // <--- 添加这一行,设为 1200 或 smaller "uplinkCapacity": 100, // ... 其他保持不变 } - 修改后重启 Xray,客户端通常会自动适应,或者在客户端也找找 MTU 设置改为 1200。
3. 协议与加密的“误会” (VLESS vs VMess)
你提到另一台机器能通,请确认:另一台机器用的是 VLESS + mKCP 还是 VMess + mKCP?
- 关键点:
- VMess + mKCP:VMess 协议本身自带加密(AES-128-GCM 等),所以跑在裸 mKCP 上是安全的。
- VLESS + mKCP:VLESS 协议本身不加密。如果跑在 mKCP 上(且不套 TLS),你的流量虽然经过了 Seed 混淆(XOR),但理论上不是强加密的。
- 客户端行为:
- 某些客户端(如新版 v2rayNG 或 Shadowrocket)可能会限制 VLESS 在不安全的传输层(非 TLS)上使用,或者配置逻辑有细微差别。
- 检查:请务必确认客户端添加配置时,协议选的是 VLESS,而不是习惯性选了 VMess。
4. 混淆种子 (Seed) 的兼容性
你配置了 "seed": "60VoqhfjP79nBQyU"。
虽然 Seed 只是简单的混淆,但不同客户端对 Seed 的处理逻辑有时不一致(有些客户端需要配合 header: wechat-video 才能生效 Seed,有些在 none 模式下也能填 Seed)。
- 排查测试:
- 暂时去掉混淆:修改服务器配置,删除
"seed": "..."这一行。 - 重启 Xray。
- 客户端也把 Seed/混淆密码清空。
- 测试:如果去掉 Seed 就能通,说明是客户端对 Seed 格式的理解出了偏差。
- 暂时去掉混淆:修改服务器配置,删除
如果日志完全静止,没有任何滚动可以确认数据包在到达 Xray 程序之前,就已经被“杀”掉了。
这不是 Xray 的配置问题,也不是密码/UUID 的问题(否则会有报错日志)。这是一个纯粹的网络连通性问题。
为了找出是谁“杀”了包,我们需要动用 Linux 上的“法医”工具 —— tcpdump。请按以下步骤排查:
第一步:安装并运行 tcpdump(抓包)
我们需要看看,数据包到底有没有到达服务器的网卡。
- 安装工具 (如果已安装可跳过):
apt install tcpdump -y # Debian/Ubuntu yum install tcpdump -y # CentOS - 开始抓包:
在服务器终端运行以下命令,不要关闭窗口:
tcpdump -i any udp port 2052 -n -v
解释:监听任意网卡 (any) 上端口为2052的udp数据包。 - 客户端发起连接: 现在,拿起你的手机或电脑(客户端),点击 mKCP 节点的**“真连接延迟测试”**(或者尝试连接一下)。
第二步:分析结果
观察服务器终端 tcpdump 的输出,会出现两种情况:
情况 A:终端没有任何反应
- 现象:你狂点测试,
tcpdump界面连一行字都没跳出来。 - 结论:数据包连服务器的网卡门都没摸到。被云服务商的防火墙(安全组)拦截了。
- 解决:
- 哪怕你觉得你开过 TCP/UDP 了,请再次登录阿里云/AWS/腾讯云/Cloudflare 的网页后台。
- 删掉原来的规则,重新添加一条:
- 协议:UDP/TCP
- 端口:2052
- 源 IP:0.0.0.0/0 (所有)
- 特例:如果你用了 Oracle Cloud (甲骨文),除了网页后台要开,还需要在机器里删掉它自带的 iptables 规则。
情况 B:终端有数据跳动
- 现象:你能看到类似下面的输出:
10:00:01.123456 IP 1.2.3.4.54321 > 5.6.7.8.2052: UDP, length 50 - 结论:包已经到了服务器网卡,但是 Xray 没收到。
- 凶手:服务器内部的防火墙 (UFW / iptables) 把包丢了,或者 Xray 监听地址不对。
**如果是情况 B:
- 检查本机防火墙:
运行以下命令,暴力放行(用于测试):
ufw allow 2052/udp iptables -I INPUT -p udp --dport 2052 -j ACCEPT
再次测试看 Xray 此时有没有日志。 - **检查监听地址:
运行:
netstat -upln | grep 2052- 必须显示:
0.0.0.0:2052或:::2052 - 绝对不能显示:
127.0.0.1:2052 - 如果显示的是 127.0.0.1:说明你 JSON 配置文件里 mKCP 那个 inbound 块里多写了一句
"listen": "127.0.0.1",删掉它,重启 Xray。
- 必须显示:
如果tcpdump有反应 且在你操作后通了,那确凿无疑就是 服务器内部的防火墙 (iptables/UFW) 之前把包给拦截了。
1. 务必持久化防火墙规则 (防重启失效)
如果你是用 iptables 命令临时放行的,重启服务器后规则会失效
- 如果是 UFW (Ubuntu/Debian 常用): UFW 的规则是自动保存的,不需要额外操作。
- 如果是 iptables (CentOS 常用):
需要手动保存:
# CentOS/RHEL service iptables save # Debian/Ubuntu (如果没有 iptables-save) apt install iptables-persistent netfilter-persistent save
2. 调整日志等级
现在调试结束了,建议把 Xray 和 Caddy 的日志等级调高,否则详细日志跑几天就能把硬盘写满。
- Xray (
config.json): 将"loglevel": "warning"或"info"改为"error"。"log": { "loglevel": "error", "error": "/var/log/xray/error.log", "access": "/var/log/xray/access.log" } - Caddy (
Caddyfile): 确保日志等级是 ERROR(调试时我们可能看的是 INFO)。log { level ERROR } - 修改后记得重启两个服务:
systemctl restart xray caddy
3. 确认 BBR 已开启
检查是否开启:
lsmod | grep bbr
- 如果看到
tcp_bbr,说明已开启。 - 如果没有,建议开启(在
/etc/sysctl.conf添加net.core.default_qdisc=fq和net.ipv4.tcp_congestion_control=bbr然后sysctl -p)。
使用如下命令可以将端口插队:
iptables -I INPUT -p udp --dport 2052 -j ACCEPT
-I INPUT(Insert Input):- 意思是**“插队”。把这条新规则插到入站规则列表的第一行**(最顶端)。
- 这很重要!如果用
-A(Append) 放到最后,可能会被前面的“拒绝所有”规则给挡住。用-I确保保安第一个就看它。
-p udp:针对 UDP 协议 的包裹。--dport 2052:针对目标端口是 2052 的包裹。-j ACCEPT:动作是 “放行”。
“UFW 配置了却不生效,而直接用 iptables 却生效了“
规则优先级问题
Linux 的防火墙规则是**“从上往下”**匹配的,一旦匹配到,就不再往下看。
- UFW 的行为:UFW 通常把用户规则放在一个特定的“链”(Chain)里,比如
ufw-user-input。而在它前面,可能还有一些系统默认的规则。 - 你那条命令的行为 (
iptables -I):-I INPUT意思是 Insert(插入)到 INPUT 链的第一行。- 这是**“插队”**,把规则放到了最顶端。
- 场景:如果你之前有一条“拒绝所有 UDP”或者类似的规则排在 UFW 规则的前面,UFW 的规则就会被忽略。而你手动执行的命令直接插到了第一行,拥有最高优先级,所以生效了。
Docker 的干扰
如果你的服务器上安装了 Docker(即使 Xray 没跑在 Docker 里),Docker 极其霸道,它会接管 iptables 并创建一大堆复杂的规则链。
- 冲突:Docker 可能会修改
iptables的转发逻辑,或者插入一些 DROP 规则。UFW 有时候甚至管不住 Docker 相关的流量。 - 结果:UFW 以为它放行了,但流量在到达 UFW 的规则链之前,就被 Docker 设置的规则给拦下或者带偏了。
- 你的命令:
iptables -I INPUT强行在主入口放行,绕过了 Docker 制造的那些迷宫。
