正在统计字数

1. 查看 Xray 实时日志

在服务器终端执行:

# 实时监控 access.log
tail -f /var/log/xray/access.log

然后在客户端点击连接测试(真连接延迟)

  • 情况 A:日志完全静止,没有任何新内容
    • 结论数据包根本没到达 Xray
    • 原因:绝对是网络层面的阻断。虽然你开了云服务商防火墙,但可能是:
      • 系统内部防火墙(iptables / nftables / SELinux)拦截。
      • 运营商对该端口段的 UDP 进行了阻断(QoS)。
    • 对策:换个端口试试(比如换成 5000-60000 之间的高位端口),或者检查本机 iptables
  • 情况 B:日志有滚动,但显示错误
    • 内容:出现 invalid userfails to parseconnection 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(抓包)

我们需要看看,数据包到底有没有到达服务器的网卡。

  1. 安装工具 (如果已安装可跳过):
    apt install tcpdump -y  # Debian/Ubuntu
    yum install tcpdump -y  # CentOS
    
  2. 开始抓包: 在服务器终端运行以下命令,不要关闭窗口
    tcpdump -i any udp port 2052 -n -v
    

    解释:监听任意网卡 (any) 上端口为 2052udp 数据包。
  3. 客户端发起连接: 现在,拿起你的手机或电脑(客户端),点击 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:

  1. 检查本机防火墙: 运行以下命令,暴力放行(用于测试):
    ufw allow 2052/udp
    iptables -I INPUT -p udp --dport 2052 -j ACCEPT
    

    再次测试看 Xray 此时有没有日志。
  2. **检查监听地址: 运行:
    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=fqnet.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 制造的那些迷宫。