1. 触发场景

全新安装部署 3X-UI(Xray 现代化 Web 管理面板)后,在面板创建节点与客户端,并将自动生成的 Clash 订阅链接(路径格式如 http://<domain>:<subPort>/<subClashPath>/<subId>)导入 Clash / Mihomo / Clash Verge 客户端拉取节点。

2. 症状

  • 通用订阅(Base64 编码,路径形如 /<subPath>/<subId>)能正常拉取并返回节点。
  • 但 Clash 订阅 或 Sing-box 订阅 链接导入客户端时,立即报错 404 或 Invalid Config。
  • 在服务端查日志未见核心报错,直接向端口发送 HTTP 请求返回:

    HTTP/1.1 404 Not Found
    Content-Type: text/plain
    
    404 page not found

3. 决定性判据

直接在命令行用 curl 针对通用订阅路径与 Clash 路径进行状态码对照:

# 1. 查通用 Base64 订阅(正常返回 200 与 base64 文本)
curl -s -i "http://<域名或IP>:<subPort>/<subPath>/<subId>"

# 2. 查 Clash 订阅(若返回 404,则确认是子功能未使能,而非端口或数据库不存在)
curl -s -i "http://<域名或IP>:<subPort>/<subClashPath>/<subId>"

4. 根因

3X-UI Go 后端服务在初始化订阅 HTTP 路由时,对 Clash / Mihomo(YAML 格式) 和 Sing-box(JSON 格式) 的动态转换接口设置了显式特性开关:

  • subClashEnable
  • subJsonEnable

在全新安装或默认初始化时,底层 SQLite 数据库 /etc/x-ui/x-ui.db 的 settings 表中虽然自动生成了 subClashPath 与 subJsonPath 的随机路径,但开关本身并未被设置为 true。后端在匹配到该路径请求时,判定特性未开启,直接返回 404 page not found。

[NOTE] 补充注意点:Host 头校验
如果在 3X-UI 设置中配置了 subDomain(订阅域名),订阅端点会对传入的 HTTP Host 头部进行匹配校验。如果直接使用 127.0.0.1 或 IP 访问该端口,会直接触发 403 Forbidden,必须通过配置的域名或携带 -H "Host: <subDomain>" 请求。

5. 解法

方案 A:Web 界面一键开启

进入 3X-UI 管理后台 -> 面板设置 (Panel Settings) -> 订阅设置 (Subscription):
勾选 启用 Clash / Mihomo 订阅 (Enable Clash) 与 启用 Sing-box 订阅,保存并重启 Xray 服务。

方案 B:命令行/自动化脚本写入 SQLite 并重启

若通过脚本无人值守安装,可直接操作 /etc/x-ui/x-ui.db:

import sqlite3
import subprocess

conn = sqlite3.connect('/etc/x-ui/x-ui.db')
cursor = conn.cursor()

# 显式激活 Clash 和 Sing-box 订阅服务
cursor.execute("INSERT OR REPLACE INTO settings (key, value) VALUES ('subClashEnable', 'true')")
cursor.execute("INSERT OR REPLACE INTO settings (key, value) VALUES ('subJsonEnable', 'true')")

conn.commit()
conn.close()

# 重载 x-ui 服务生效
subprocess.run(["systemctl", "restart", "x-ui"], check=True)

生效后再次测试:

curl -s -i "http://<domain>:<subPort>/<subClashPath>/<subId>"

将返回标准的 Content-Type: application/yaml; charset=utf-8 及完整的 proxies / proxy-groups 配置。

6. 下次怎么识破 / 防御

  1. 认准 404 与 403 的不同语义:

    • 403 Forbidden:通常是 Host 头与 subDomain 不匹配,或者请求路径缺少合法 subId 客户端索引。
    • 404 Not Found:只要路径里的 subClashPath 存在但返回 404,100% 是 subClashEnable 未置 true。
  2. 自动化部署模版防御:在通过脚本一键初始化 3X-UI 时,应将 subClashEnable=true 与 subJsonEnable=true 作为必须的初始配置直接写进数据库,避免交付后首次导入客户端报 404。

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Network