跳转到内容

故障排查

本页从你看到的现象出发:节点始终起不来、客户端连不上、面板上看不到流量。每一节列出 katana 针对该问题写出的日志行、产生原因和解决办法。日志行按 katana v3.0.1 的原文引用。其他版本的部分措辞不同,某些行为也有差异,所以请先用 katana --version 确认你的版本。

深入排查具体问题之前,请先阅读提高日志详细程度:大多数单个连接的失败只在 debug 级别记录,而该级别默认是关闭的。

现象 章节
katana 启动后立即退出 katana 启动即退出
katana 在运行,但某个节点的端口没有打开 节点始终没有启动
保存了配置文件,但什么都没变 修改配置没有生效
端口已打开,但客户端连接失败 客户端无法连接
用户的速度比套餐快或慢 速度与预期不符
面板上没有流量,或流量数值不对 面板中看不到流量
审计规则本应拦截的目标仍能访问 审计规则没有拦截
只有经 WireGuard 路由的目标超时 WireGuard 出站无法传输流量
出现 node_info: GET … 或 report traffic: … 之类的日志行 面板请求错误
… inbound handshake failures in the last 1s … 握手失败告警

继续往下读之前,下面三项检查就能回答大多数问题:

  1. 检查配置文件。 katana --test -c /etc/katana/config.toml 会输出 Configuration OK 或 configuration error: …。它会解析文件、构建出站、检查每个节点的 panel_type、node_type 和路由,并检查 Hysteria 2 节点的设置。它不会联系面板,也不会绑定端口,所以 Configuration OK 并不说明面板或监听器没有问题。

  2. 检查监听器。 已启动的节点会占用自己的端口。基于 TCP 的节点监听 TCP,Hysteria 2 节点监听 UDP:

    终端窗口
    ss -ltnp | grep katana # VMess, VLESS, Trojan, Shadowsocks
    ss -lunp | grep katana # Hysteria 2

    不在此列表中的节点要么还没有启动、正在重试,要么没有用户。它的日志行会说明是哪一种。

  3. 阅读日志。 katana 写入标准输出。在 systemd 下即为 journal,例如 journalctl -u katana -f。

每一行都包含 UTC 时间戳、级别、target 和消息:

2026-09-24T08:15:02.481233Z ERROR katana::manager::node: node 1: node_info failed: GET /api/v1/server/UniProxy/config; retrying in 4s

target 是写出该行的模块;提高日志详细程度就是用它来只为 katana 的某一部分打开详细日志。本页的示例省略时间戳,通常也省略 target。

不同的日志行用不同的方式指代节点:

形式 示例 用于
node <node_id> node 1: listening on 0.0.0.0:443 启动及其重试、轮询、上报、重建,以及节点拒绝的配置修改(node 1: config edit refused, …)
node <Type>_<listen_ip>_<port> node V2ray_0.0.0.0_443: 37 inbound handshake failures … 握手告警和预认证限制
SSPanel 上为 <panel_type>@<host>#<node_id>,NewV2board 和 V2board 上为 <panel_type>@<host>#<node_id>/<node type> reload: added node newv2board@https://panel.example.com#1/v2ray 配置重载,包括被拒绝的重载(reload: node …: …; keeping current config)

在重载形式中,<panel_type> 为小写,<node type> 是 katana 向面板请求的类型:即你配置的 node_type 的小写形式;如果 V2ray、VMess 或 VLESS 节点设置了 enable_vless = true,则为 vless。

面板请求错误和重载日志行从不包含面板密钥或查询字符串。但配置解析错误会引用解析失败的那一行文件内容,所以分享日志之前请先读一遍。

katana 的日志过滤器使用 tracing 的过滤器语法:先是默认级别,然后是可选的、以逗号分隔的 target=level 对。一个 target 匹配其自身及其下的所有模块,因此 katana::manager=debug 也覆盖 katana::manager::node。

可以在两个地方设置过滤器:

启动时,如果 RUST_LOG 环境变量是有效的过滤器,katana 就使用它,否则使用 [log].level。这种方式适合一次性的前台运行:

终端窗口
RUST_LOG=info,katana::serve=debug katana -c /etc/katana/config.toml

对于 systemd 服务,把变量写进 drop-in 文件,然后重启服务。重启会断开所有连接。

/etc/systemd/system/katana.service.d/debug.conf
[Service]
Environment=RUST_LOG=info,katana::serve=debug

以下是值得了解的 target:

Target 记录的内容
katana::runtime 启动错误、配置重载、文件监视器、关闭
katana::manager::node 节点启动、轮询、面板请求错误、监听器重建、流量和审计上报
katana::manager::proxy 握手失败告警(warn)、因预认证限制而丢弃的流(debug)、用户刷新失败(error)
katana::manager 因 UUID 无效而被跳过的用户(warn)
katana::serve 每个握手失败或以错误结束的连接各一行 debug、accept 错误、活动连接数限制,以及 Hysteria 2 监听器失败(error)
katana::api 审计规则问题:规则文件无法读取,或正则表达式无法编译(warn)
katana::connector 无法打开出站的 UDP 关联(debug)
katana::outbound 因域名没有可用地址而丢弃的 direct UDP 数据报(debug)
etemenanki_protocols 代理内核:协议核心(core)、传输层、Hysteria 2 监听器(etemenanki_protocols::hysteria)和 WireGuard 隧道(etemenanki_protocols::wireguard)
boringtun WireGuard 握手、keepalive 和会话变化

katana 完全无法运行时会以状态码 1 退出。最后一行说明原因:

日志行 原因 解决办法
failed to load config: … 文件不存在、不是 UTF-8、不是有效的 TOML,或包含未知配置项 运行 katana --test,它会输出同样的错误以及行号和列号。配置文件列出了所有配置项。
failed to build outbounds: … 某个 [[outbound]] 条目或 [dns] 无法构建 见出站。
config defines no [[node]] entries 文件中没有 [[node]] 表 添加一个。单括号的 [node] 不算。
node 1: unknown panel_type "…" panel_type 不是 SSpanel、NewV2board 或 V2board(不区分大小写)。Xboard 对应 NewV2board。 修正该值。
node 1: unknown node_type "…" node_type 不是已知的值 使用 V2ray、Trojan、Shadowsocks 或 Hysteria2。
node 1: build router: … 节点的 [node.route] 无法编译 见路由。
no nodes could be started 所有节点都因上面三种原因之一被跳过 逐一修正;--test 会报告第一个。

因上述三种 node 1: … 原因之一被跳过的节点不会影响其他节点。只有一个节点都不剩时 katana 才会退出。

重载时,同样的错误不会跳过节点,而是拒绝整次保存。如果保存的文件中某个 [[node]] 表的 panel_type 或 node_type 未知,或者新增的节点路由无法编译,katana 会记录类似 reload: node newv2board@https://panel.example.com#1/v3ray: unknown node_type "v3ray"; keeping current config 的日志行,不应用这次保存中的任何内容,所有节点都保持原样继续运行。因此,启动时被跳过且仍然有误的节点会让之后的每次保存都被拒绝,即使这次保存只修改了文件的其他部分,直到你修正或删除它的 [[node]] 表;见热重载。已在运行的节点的新路由由该节点自己检查;见修改配置没有生效。

节点会一直尝试,直到启动成功。每次尝试都会向面板请求节点设置、请求用户列表,然后绑定监听器。设置了 [node.hysteria].port 的 Hysteria 2 节点从文件中读取设置,只向面板请求用户。node 1: listening on 0.0.0.0:443 表示这三步都成功了。

flowchart TB
  S["尝试启动"] --> I{"面板返回节点设置?"}
  I -- 否 --> R["ERROR,然后等待"]
  I -- 是 --> P{"端口不为 0?"}
  P -- 否 --> R
  P -- 是 --> U{"面板返回用户列表?"}
  U -- 否 --> R
  U -- 是 --> E{"有用户?"}
  E -- 否 --> W["不绑定端口;下一次轮询重试"]
  E -- 是 --> B{"监听器构建并绑定成功?"}
  B -- 否 --> R
  B -- 是 --> L["listening on ip:port"]
  R -- "等待结束,或保存了该节点的配置" --> S

某一步失败时,节点会记录一行 ERROR,写明失败的步骤和等待时间,例如 node 1: user_list failed: GET /api/v1/server/UniProxy/user; retrying in 2s,等待结束后再次尝试。第一次等待 1 秒,之后每失败一次翻倍,最多 60 秒或 update_periodic,取较小者。每次尝试都会重新向面板请求所有内容,所以在面板中的修复会在下一次尝试时被看到。

这些日志行都来自 katana::manager::node,级别为 ERROR。每一行都以 node <node_id>: 开头,以 ; retrying in <N>s 结尾,表中省略了结尾部分。节点会在等待结束后再次尝试,所以修复原因后留意下一行日志即可。

日志行 原因 解决办法
node_info failed: GET /api/v1/server/UniProxy/config 对 Xboard 或 V2board 面板的请求失败。该行不说明原因:可能是 host 错误或无法访问、请求超时,也可能是面板拒绝了密钥、node_id 或节点类型。 手动发送请求,查看面板的响应。检查节点类型。
node_info failed: GET /mod_mu/nodes/1/info 同上,面板为 SSPanel。 同上。
node_info failed: /mod_mu/nodes/1/info: panel returned ret=0 SSPanel 有响应但拒绝了请求,通常是 key 或 node_id 错误。 检查 SSPanel 中的 muKey 和节点 ID。
node_info failed: parse UniProxy config response 或 node_info failed: parse /mod_mu/nodes/1/info 面板返回的不是节点配置,常见的是 host 错误时得到的 HTML 页面,或面板前面的 Web 防火墙、机器人验证页面。 手动发送请求并查看响应体。host 是面板的基础 URL,包括 https://。
node_info failed: newV2board: server port must be > 0 该节点在 Xboard 或 V2board 中没有端口。 在面板中设置端口。
panel returned port 0 SSPanel 描述的节点端口为 0。 在 custom_config 中设置 offset_port_node,或在旧式 server 字符串中设置端口。
node_info failed: invalid offset_port_node "" SSPanel 节点的 custom_config 中没有 offset_port_node。 将其设为 katana 应监听的端口。
node_info failed: sspanel: Shadowsocks node type is not supported 在 SSPanel 上使用了 node_type = "Shadowsocks"。 通过 Xboard 或 V2board 面板提供 Shadowsocks。
node_info failed: custom_config is empty, disable custom config SSPanel 节点没有 custom_config。 见 SSPanel。
node_info failed: newV2board: shadowsocks obfs "…" is not supported 面板为 Shadowsocks 节点发送的 obfs 值不是 plain 或 none。Xboard 则把插件放在 plugin 中发送,katana 不读取该字段:节点会在没有插件的情况下启动,使用插件的客户端会失败。 从节点中移除插件。
user_list failed: … 用户请求失败。节点需要用户列表才能启动,因此不绑定任何端口并重试。结尾部分与 node_info failed 相同。 按 node_info failed 的方法检查面板。在 Xboard 上,user_list failed: parse UniProxy user response 通常表示某个用户没有限速;见没有用户的节点。
panel returned no node info 或 panel returned no user list 面板或其前面的某个组件返回了 304 Not Modified,尽管 katana 请求时没有带标签。 手动发送请求,检查是谁在响应。
initial start failed: TLS node requires cert.mode = "file" 节点使用 TLS(面板开启了 TLS,或者是始终使用 TLS 的 Trojan 节点),但 [node.controller.cert] 中没有 mode = "file"。 设置 mode = "file"、cert_file 和 key_file。
initial start failed: TLS node requires cert.cert_file and cert.key_file 设置了 mode = "file",但缺少路径。 设置两个路径。
initial start failed: No such file or directory (os error 2) cert_file 或 key_file 不存在。该行不说明是哪一个。 检查两个路径。使用绝对路径:相对路径会相对于 katana 的工作目录打开。
initial start failed: Permission denied (os error 13) katana 无权绑定 1024 以下的端口,或无权读取私钥文件。 授予 CAP_NET_BIND_SERVICE 或以 root 运行,并检查私钥文件的属主和权限。
initial start failed: Address already in use (os error 98) 其他程序或同一文件中的另一个节点占用了该端口。 释放端口,或在面板中更改端口。
initial start failed: Cannot assign requested address (os error 99) listen_ip 不是本机的地址。 使用本机拥有的地址,或 0.0.0.0。
initial start failed: node requests kernel-unsupported feature: … 面板要求了 katana 不支持的功能:REALITY、VLESS XTLS flow、httpupgrade transport、splithttp transport、transport "…"、shadowsocks cipher "…",或者你自己的文件中的 ACME cert mode "…" 或 cert.reject_unknown_sni。 在面板中修改节点,或修改文件中的配置项。协议列出了 katana 支持的内容。
Hysteria 2 节点上的 initial start failed: … [node.hysteria] 设置(unknown hysteria credential kind …、udp_idle_timeout must be between 2 and 600 seconds)、证书(hysteria2 node requires cert.mode = "file")或混淆(unknown obfs …、obfs_password must be at least 4 bytes for salamander、obfs_password is set but obfs is not; …)有问题。Xboard 在关闭混淆时仍会发送混淆密码,从而产生最后一种错误。 运行 katana --test,它会检查本地设置。它无法检查来自面板的混淆设置:请在面板中开启混淆,或清空混淆密码。见 Hysteria 2 节点。

用户列表为空的节点启动后没有监听器,也不写任何相关日志行。它不绑定任何端口,因为没有需要服务的人;它会在第一次返回用户的轮询时绑定,即 update_periodic 秒之后(默认 60)。检查面板发送的内容:

  • Xboard 只列出属于节点某个权限组、未被封禁、未过期且未超出流量配额的用户。没有权限组的节点得不到任何用户。
  • Xboard,user_list failed: parse UniProxy user response; retrying in <N>s。 对于套餐没有限速的用户,Xboard 会发送 "speed_limit": null,katana 会因此拒绝整个列表。节点会不断重试且不绑定任何端口,直到面板发送的列表中不再有这样的用户,然后自行启动。请为每个套餐和每个用户设置限速;0 表示不限速。限速对此有说明。

katana 的面板错误日志行从不包含 URL,因为 URL 中带有密钥。要查看面板的响应,请用 curl 发送同样的请求。把密钥读入变量可以避免它进入 shell 历史:

终端窗口
read -rs KEY # paste the panel key, then press Enter
curl -sS -i "https://panel.example.com/api/v1/server/UniProxy/config?node_id=1&node_type=v2ray&token=$KEY"

使用 katana 发送的 node_type:即你配置的 node_type 的小写形式;如果 V2ray、VMess 或 VLESS 节点设置了 enable_vless = true,则为 vless。正常的节点返回 200 和包含 server_port 的 JSON。密钥错误时 Xboard 返回 Invalid token,类型未知时返回 Invalid node type specified,该 ID 下没有此类型的节点时返回 Server does not exist。请求用户列表时,把 config 换成 user。

请在节点所在的主机上运行,这样 DNS、路由和防火墙都与 katana 一致。连接错误、证书错误、HTTP 错误状态码和非 JSON 的响应体分别对应不同的解决办法,面板的错误消息通常会指出问题所在。

无需重启 katana。节点会在下一次尝试时发现修复,最多 60 秒之后;如果 update_periodic 更短,则最多一个 update_periodic 间隔。如果修复在该节点的 [[node]] 表中,保存文件会结束等待,并立即以新设置开始下一次尝试。保存前先用 katana --test 检查文件。

曾经启动过的节点能从大多数问题中自行恢复:

日志行 发生了什么 接下来会怎样
node 1: rebuild failed: … 面板或文件变化后,监听器重建时构建或绑定失败。消息是上面 initial start failed 的原因之一。 节点没有监听器。每次轮询都会重试,所以修复原因后的第一次轮询就会恢复。
无,端口关闭 面板中该节点的用户列表变为空。 节点会在第一次返回用户的轮询时重新绑定。
node 1: refreshed port is 0, keeping the last one 面板在某次轮询中报告端口为 0。 节点保留当前的监听器和端口,但仍会应用这次轮询得到的用户列表。
hysteria listener failed: … Hysteria 2 节点的 QUIC 监听器停止了。 轮询不会重建它。请重启 katana,或保存一次会重建该节点监听器的修改,例如修改 [node.hysteria]。

保存配置文件后约 500 ms,katana 会重新加载它,几乎所有修改都会立即生效。对 [node.api] 的修改(例如 speed_limit、timeout 或 rule_list_path)会为节点创建新的面板客户端,它会立即重新读取节点和用户;只有当修改改变了节点的协议或传输层时才会断开连接。enable_vless 以及 Xboard 和 V2board 上的 node_type 修改也可能断开连接;见下表前两行。例外是少数只在 katana 构建相应对象时读取的文件,以及无法构建的保存,katana 会拒绝后者。katana 应用的保存会为每个发生变化的部分写一行 reload:,被拒绝的保存则会写一行包含 keeping current 或 refused 的日志。

你修改了 发生了什么 怎么办
Xboard 或 V2board 上的 api.node_type 或 api.enable_vless,使 katana 向面板请求另一种类型,且节点重启了 面板按 ID 和 katana 请求的类型查找节点,所以新类型对应的是面板中的另一个节点。katana 停止旧节点(并做最后一次流量上报),为新类型启动一个节点:先是 reload: removing node …#1/v2ray,然后是 reload: added node …#1/vless。该节点上的所有连接都会断开,新节点的流量计数从零开始。 预期行为。请在节点空闲时修改。
disable_sniffing、[node.hysteria] 中的某个配置项,或 SSPanel 上的 api.enable_vless(在 Xboard 或 V2board 上则是不改变 katana 所请求类型的 api.enable_vless),且节点的连接断开了 这些修改通过重建节点的监听器立即生效,这会结束该监听器上的所有连接。 预期行为。请在节点空闲时做这些修改。
controller.send_ip、api.device_limit katana 接受这些配置项,但不使用它们。 无需应用。
只改了 [dns] 解析器只会随出站一起重建,而且 katana 不记录 reload: 日志行。 重启 katana,或随下一次 [[outbound]] 修改一起应用。
续期了证书,路径不变 katana 在构建监听器时读取证书文件。 每次续期后重启 katana。
替换了 geoip 或 geosite 文件,路径不变 katana 在编译节点路由时读取它们。 重启 katana,或保存一次对 [node.route] 或 [[outbound]] 的修改。
[node.route],且日志显示 node 1: config edit refused, keeping the running one: … 节点的新路由无法编译。节点不应用其 [[node]] 表中的任何修改,保留原有的规则、监听器和连接。重载仍会记录 reload: reconfigured node …,这次保存的其余部分(例如其他节点和日志级别)照常生效。 修正规则后重新保存。保存前先运行 katana --test。
[[outbound]],且日志显示 node 1: route rebuild failed, keeping current: … 节点的路由引用了新出站池中已不存在的出站。节点继续使用之前的路由表(仍指向旧的出站),并重建监听器。 恢复该出站,或修改节点的路由使之匹配,然后重新保存。
[[outbound]],且日志显示 reload: bad outbounds, keeping current config: … 新出站无法构建,因此 katana 没有应用这次保存中的任何内容。 修正出站后重新保存。
任意修改,且日志显示 reload: node …: …; keeping current config 新文件中某个 [[node]] 表无法构建:panel_type 或 node_type 未知,或本次保存新增的节点路由无法编译(build router: …)。katana 没有应用这次保存中的任何内容。 修正日志行指出的节点后重新保存。katana --test 会报告同样的错误。
任意修改,且日志显示 config reload failed, keeping current: … 文件无法解析。 修正文件后重新保存。
任意修改,且没有出现任何日志行 文件监视器没有启动(启动时记录了 config watcher disabled (no live reload): …),或者配置路径是指向其他目录的符号链接,katana 察觉不到那里的变化。 每次修改后重启 katana。
尚未启动的节点中的任意修改 不会丢失任何东西:该节点仍在运行和重试。它会接受修改,并立即以新设置开始下一次尝试。 查看该节点的下一行日志:listening on …,或带有剩余原因的 retrying in <N>s。

每个配置项在重载时的效果、哪些修改会断开连接的完整表格见热重载。

单个连接失败时,katana 在默认的 info 级别下不写任何内容。如果节点的端口已打开(见先看哪里),请按顺序检查连接经过的各个阶段:

阶段 可能的失败 查看
到达端口 防火墙、云安全组、Hysteria 2 的 UDP 被阻断、IPv6 客户端遇上 listen_ip = "0.0.0.0" 端口是否可达
TLS 证书缺失或错误,证书不覆盖客户端使用的服务器名称 证书
传输层 WebSocket 路径或 Host、gRPC 服务名 当前 Xboard 上基于 WebSocket 或 gRPC 的 VLESS
协议 客户端协议与 katana 提供的不同、未知用户、时钟偏差 node_type 与面板的协议,VMess 与时钟
目标 路由到 block、审计规则、出站失败 审计规则没有拦截,WireGuard 出站无法传输流量

要查看每次握手失败的原因,按提高日志详细程度所述打开 katana::serve=debug。日志行如下:

DEBUG katana::serve: inbound handshake failed: proxy core: vmess: unknown user or invalid auth id
DEBUG katana::serve: inbound handshake failed: proxy core: invalid vless request user id
DEBUG katana::serve: inbound handshake failed: proxy core: trojan: invalid user
DEBUG katana::serve: inbound handshake failed: timed out after 10s
DEBUG katana::serve: inbound handshake failed: closed before the handshake completed
DEBUG katana::serve: inbound transport ended: …

inbound transport ended 涵盖代理协议之下的失败,例如没有完成的 TLS 握手或 WebSocket 升级。10 秒后仍处于协议握手阶段的客户端会以 timed out after 10s 断开。这些日志行不包含节点或用户。

  • 防火墙。 在主机防火墙和所有云安全组中,为 VMess、VLESS、Trojan 和 Shadowsocks 节点开放 TCP 端口,为 Hysteria 2 节点开放 UDP 端口。UDP 被阻断时 Hysteria 2 会静默失败:客户端超时,katana 不记录任何内容。例如 ufw allow 443/udp 或 firewall-cmd --add-port=443/udp --permanent。
  • 地址族。 默认的 listen_ip = "0.0.0.0" 只接受 IPv4。在 Linux 上若要同时接受 IPv6 客户端,请设置 listen_ip = "::";除非主机设置了 net.ipv6.bindv6only = 1,它同样接受 IPv4。
  • 文件描述符。 accept error, backing off 100ms: Too many open files (os error 24) 表示 katana 达到了打开文件数上限,新客户端会等待或失败。请提高上限,例如在 systemd unit 中设置 LimitNOFILE=。

katana 的所有证书都来自 [node.controller.cert]。它忽略面板发送的 TLS 设置和证书,所以上传到面板的证书永远不会被使用。

  • 文件不存在时节点无法启动:它会以 initial start failed: No such file or directory (os error 2) 不断重试,直到文件出现。见启动日志行。
  • 客户端会用它发送的服务器名称去核对证书的 Subject Alternative Names。只在 Common Name 中写了主机名,或覆盖的是其他名称的证书,会在客户端报证书错误,而 katana 只能看到一次失败的 TLS 握手。
  • 自签名证书只有在客户端固定该证书或跳过验证时才能使用。
  • katana 会一直使用构建监听器时读取的证书。续期后请重启 katana,否则客户端会看到旧证书过期。

无论面板认为节点是什么,katana 提供哪种协议都由 node_type 决定。两者不一致时,要么面板拒绝请求,要么 katana 提供了客户端不支持的协议。

使用 Xboard 或 V2board 时,katana 每次请求都会带上 node_type,面板按 ID 和类型共同查找节点:

面板中的节点 node_type enable_vless katana 发送
VMess V2ray 或 VMess false v2ray 或 vmess
VLESS V2ray true vless
Trojan Trojan false trojan
Shadowsocks Shadowsocks false shadowsocks
Hysteria 2 Hysteria2 或 Hysteria false hysteria2 或 hysteria

常见错误:

  • 设置了 node_type = "vless" 却没有 enable_vless = true。 katana 向面板请求 VLESS 节点、收到后却在上面提供 VMess。所有客户端都会以 vmess: unknown user or invalid auth id 失败。设置 enable_vless = true 并保存。节点仍对应原来的面板节点,因为 katana 本来就在请求 vless,它会立即重建监听器以提供 VLESS。
  • node_type = "hy2"。 katana 接受这个名称,但会原样发送给面板,而 Xboard 不认识它,因此所有面板请求都以 Invalid node type specified 失败。请使用 Hysteria2。
  • 该 ID 下没有这种类型的节点。 面板找不到节点,请求以 node_info failed: GET /api/v1/server/UniProxy/config 失败。手动发送请求会看到 Xboard 返回的 Server does not exist。
  • 基于 WebSocket 或 gRPC 的 Trojan。 对于来自 Xboard 或 V2board 的 Trojan 节点,katana 忽略面板的 network,始终以 TCP + TLS 提供 Trojan。请把 Trojan 客户端配置为 TCP。

使用 SSPanel 时,面板只按 ID 查找节点,katana 则按你配置的 node_type 解读它。类型不匹配时节点能启动,但客户端握手会失败。请让 node_type 与 SSPanel 中的节点类型一致。

VMess 认证包含时间戳,katana 只接受与自身时钟前后相差 120 秒以内的时间戳。超出这个范围,每个连接都会以 vmess: unknown user or invalid auth id 失败,与未知用户的日志行相同。使用 2022-blake3-… 加密方式的 Shadowsocks 节点更严格:请求头的时间戳必须在 30 秒以内,超出范围的客户端会以 shadowsocks-2022: bad timestamp 失败。请检查服务器和客户端的时间都准确:

终端窗口
timedatectl status # "System clock synchronized: yes"

如果同一节点上只有一个客户端失败而其他客户端正常,请检查该设备的时钟和时区设置。VLESS、Trojan、Hysteria 2 和较早的 Shadowsocks 加密方式不以这种方式依赖时钟。

当前 Xboard 上基于 WebSocket 或 gRPC 的 VLESS

Section titled “当前 Xboard 上基于 WebSocket 或 gRPC 的 VLESS”

katana 从面板响应的 network_settings 键读取 VLESS 节点的传输层设置。当前的 Xboard 版本对所有节点类型都以 networkSettings 发送这些设置,因此 katana 看不到路径、Host 或服务名:

  • VLESS WebSocket 节点监听路径 / 并接受任意 Host,因此配置了其他路径的客户端会收到 HTTP 404;
  • VLESS gRPC 节点期望空的服务名,因此配置了服务名的客户端会失败。

要确认这一点,请手动发送配置请求,看响应中是否只有 networkSettings 而没有 network_settings。绕过办法有:在面板中把 WebSocket 路径设为 /,改用 TCP + TLS 提供 VLESS,或把 WebSocket 或 gRPC 节点改为 VMess 提供。VMess 节点读取 networkSettings,不受影响。

除了 UDP 防火墙之外:

  • 凭据。 默认情况下,客户端的密码是用户的 UUID。设置 [node.hysteria].credential = "user_pass" 后,在 Xboard 和 V2board 上为 <uuid>@v2board.user:<uuid>,在 SSPanel 上为 <user id>:<uuid>。发送了错误格式的客户端会得到 authentication error, HTTP status code: 404,或你设置的 masquerade 状态码。
  • 混淆。 客户端的 salamander 密码必须与节点的一致:即面板的 obfs-password,本地描述的节点则为 [node.hysteria].obfs_password。不一致时的表现与 UDP 被阻断完全相同,只是超时而没有认证错误,因为 katana 无法读取这些数据包。
  • 证书。 Hysteria 2 客户端像任何 TLS 客户端一样验证证书;见证书。

RUST_LOG=info,etemenanki_protocols::hysteria=debug 会显示监听器一侧的情况,例如 hysteria2: a handshake failed: …。Hysteria 2 节点介绍了相关设置。

  • 新用户暂时无法连接。 katana 在下一次轮询时才得知用户变化,最多在变化后 update_periodic 秒(默认 60)。
  • 某个用户始终不被接受。 在 V2ray 节点上,UUID 不是有效 UUID 的用户会被排除,并在 WARN 级别记录 skipping user 7: uuid is not a valid UUID。请在面板中修正 UUID。
  • 某个时间点之后添加的用户都无法连接。 查看每次轮询时是否有 user_list: … 警告:katana 会继续使用它最后一次成功读取的用户列表。在 Xboard 上,user_list: parse UniProxy user response 通常是某个用户或套餐没有限速;见没有用户的节点。
  • 已删除的用户仍能使用。 删除在下一次轮询时生效,届时也会断开该用户已打开的连接。

用户的速率取节点限速和用户自身限速中较小的一个,值为 0 的忽略不计。只有 SSPanel 有节点限速;在 Xboard 和 V2board 上,用户的限速就是其速率。katana 为节点上的每个用户使用一个令牌桶来执行限速。限速解释了其机制。

现象 原因 怎么办
节点上所有用户的速度都一样,与套餐无关 [node.api].speed_limit 大于 0。它会替换每个用户的限速,包括套餐本身不限速的用户。它不是上限。 设为 0 并保存。节点上的用户会立即使用各自的限速,作用于此后打开的流,现有连接保持不变。
速率比预期低或高 8 倍 所有限速的单位都是兆比特每秒(十进制)。speed_limit = 100 即每秒 12,500,000 字节,客户端显示约为 12.5 MB/s。 换算:字节每秒乘以 8,再除以 1,000,000。
修改的限速只对部分流量生效 在面板中修改的限速在下一次轮询时生效,在文件中保存的 speed_limit 则立即生效,Hysteria 2 节点也一样。两种情况下修改都原地生效、不断开连接,并且只作用于之后打开的流。已打开的流以旧速率继续直到结束。 等待客户端打开新连接。
同时下载和上传的用户,每个方向只有约一半的速率 两个方向以及该用户在节点上的所有连接共享一个令牌桶。 预期行为。按合计流量规划套餐。
SSPanel 用户比套餐慢 SSPanel 中节点自身的限速更低,取较小者。 提高或清除节点限速。
Hysteria 2 客户端声明的带宽没有作用 katana 的每用户限速只来自面板和配置文件。 在面板中设置限速。
没有设置限速,但所有人都很慢 瓶颈在别处:主机、线路或出站。 绕过 katana 测试;隧道问题见 WireGuard 出站无法传输流量。

katana 在每次轮询时上报流量,即每 update_periodic 秒一次。没有传输任何字节的用户不会被上报;所有用户都没有流量时,katana 根本不发送请求。

现象 原因 怎么办
完全没有流量,也没有警告 [node.controller].disable_upload_traffic = true 设为 false,修改在下一次上报时生效。流量上报解释了在此期间计数会怎样。
刚启动,还没有流量 第一次上报在节点成功启动后一个完整的 update_periodic 间隔才发出。 等待一个间隔。
node 1: report traffic: POST UniProxy push 向 Xboard 或 V2board 上报失败。 见面板请求错误。katana 会保留计数,并计入下一次上报。
node 1: report traffic: POST /mod_mu/users/traffic,或 … panel returned ret=0 向 SSPanel 上报失败或被拒绝。 同上。
节点没有监听器 节点还没有启动、正在重试,因此没有可上报的内容。 见节点始终没有启动。
Xboard 显示节点在线,但没有推送 一段时间内没有用户传输任何字节,所以 katana 没有推送。 空闲节点上属于预期行为。
面板显示的流量少于客户端或网卡统计 katana 只计费有效载荷:TLS、WebSocket、gRPC 和代理协议的开销不计入。 预期行为。
面板显示的流量多于 katana 实际传输的 Xboard 乘以了节点倍率;或者某次上报在面板已接受后在 katana 一侧超时,katana 又发送了一次。 检查节点倍率。见流量上报;如果面板响应慢,请调大 api.timeout。

面板访问日志中的 304 Not Modified 响应是正常的。katana 请求节点配置、用户列表以及 SSPanel 上的审计规则时,会带上上一次响应的标签。304 表示没有变化,katana 保留已有内容,不记录任何日志。流量上报是 POST 请求,永远不会得到 304。

katana 在拨号之前,用审计规则检查客户端请求中的主机。目标审计完整解释了匹配方式。规则没有触发的常见原因:

  • 客户端通过 IP 地址连接。 规则只看到代理请求中的地址,从不看从 TLS 服务器名称或 HTTP Host 嗅探到的域名。客户端自行解析了域名时,域名规则不会匹配。要拦截某个站点的 TCP 流量而不论客户端如何指定地址,请在路由中添加一条把它发往 block 的 domain_suffix 规则;开启嗅探时,路由能看到嗅探到的域名。
  • 大小写和锚点。 匹配区分大小写:请在模式开头加上 (?i)。^blocked\.example\.com$ 不匹配 www.blocked.example.com。
  • 规则被关闭。 启动时设置了 disable_get_rule = true,katana 不加载任何审计规则,本地文件也不例外。通过重载将其设为 true 会停止刷新,但保留已加载的规则;再设回 false 会在下一次轮询时加载规则。
  • 规则尚未加载,或加载失败。 规则在节点启动后立即加载,并在每次轮询时刷新。查找 WARN 级别的 invalid local rule …、invalid block rule …、invalid panel rule … 或 cannot read rule_list_path …;在 SSPanel 上还要查找 node_rule: … 警告。
  • 路由已经拦截了它。 被路由发往 block 的流在审计规则运行之前就被拒绝,因此不会记录审计命中。
  • 流在之前就已打开。 规则只作用于新的流。已打开的 TCP 连接不会被重新检查。
  • 在 SSPanel 上修改了本地规则文件。 SSPanel 以 304 响应规则请求时,katana 也不会重新读取本地文件。修改要等面板的规则发生变化、保存的 [node.api] 修改为节点创建了新的面板客户端,或 katana 重启后才生效。

被拒绝的流在客户端看来与路由到 block 相同,katana 也不为它写日志行。在 SSPanel 上,面板规则的命中会在下一次轮询时进入检测日志。本地规则的命中,以及 Xboard 或 V2board 上的所有命中,都不会上报到任何地方。

如果路由到 wireguard 出站的目标超时而其他一切正常,问题就在该出站。经隧道超时的连接,katana 自身不写任何日志行。在默认级别下,你可能会看到以下警告:

警告 含义
HANDSHAKE(REKEY_TIMEOUT)(target boringtun) 对端不响应握手。持续约 90 秒后,会出现 ERROR 级别的 CONNECTION_EXPIRED(REKEY_ATTEMPT_TIME)。
wireguard: tunnel start failed: … 隧道根本无法启动,例如其 endpoint 无法解析。
wireguard: tunnel driver stopping, send failed: … 或 … receive failed: … 隧道的 UDP socket 出错,隧道停止。
wireguard: tunnel driver stopped, rebuilding 下一个连接发现隧道已停止,katana 启动一个新隧道。

握手成功的隧道在 info 级别不记录任何内容,无论流量是否通过。请按以下步骤排查:

  1. 在 katana 之外测试上游。 在一个临时的 etemenanki-app 中运行同样的隧道,配一个回环地址上的 SOCKS 入站,并通过它访问一个 IP 回显服务。出站给出了步骤和现成的配置。这不会影响正在运行的 katana。

  2. 第一次请求失败时重试一次。 新隧道的第一个连接要等待 WireGuard 握手,而且某些服务上用新签发密钥建立的第一个连接会失败。判定密钥失效之前先重试一次:第一次请求超时、第二次成功,说明配置没有问题。

  3. 不要只看握手。 握手成功只说明对端认识你的公钥,不说明服务仍会为它转发流量:有些服务会为已不再接受的密钥完成握手,然后丢弃所有数据包。只有返回上游出口地址的请求才能证明密钥有效。如果握手成功但没有流量通过,请先从服务商那里获取新的密钥或配置。

  4. 阅读隧道自身的日志。 在 katana 或临时的 etemenanki-app 中打开 WireGuard 相关的 target:

    终端窗口
    RUST_LOG=info,boringtun=debug,etemenanki_protocols::wireguard=debug

    反复出现 Sending handshake_initiation 而没有 Received handshake_response,说明对端没有响应:检查 server、port、public_key、pre_shared_key 和 reserved,并确认允许出站 UDP。出现 Received handshake_response 和 New session 之后仍然超时,说明隧道已建立但对端不转发。WireGuard 完整解释了这些日志行。

  5. 如果小请求正常而大请求卡住,请调低 mtu,例如调到 1280。

面板错误日志行只写出失败的请求,不写原因:

WARN katana::manager::node: node 1: node_info: GET /api/v1/server/UniProxy/config

katana 只写出错误最外层的描述:方法和路径。它省略面板的主机名、带有密钥的查询字符串,以及底层原因,例如连接被拒绝、超时或 HTTP 状态码。因此同一行日志可能对应 host 错误、面板无法访问、请求慢于 api.timeout,以及任何 4xx 或 5xx 响应。请手动发送请求确认是哪一种。

node <node_id>: 之后的内容 请求
node_info failed: …; retrying in <N>s(节点启动过程中,ERROR)或 node_info: …(轮询时,WARN) 节点设置
user_list failed: …; retrying in <N>s(节点启动过程中,ERROR)或 user_list: …(轮询时,WARN) 用户列表
report traffic: … 流量上报
node_rule: … SSPanel 审计规则
report illegal: … SSPanel 检测日志

冒号之后的部分说明请求进行到了哪一步:

结尾 含义
GET /api/v1/server/UniProxy/config、GET /mod_mu/users、POST UniProxy push、POST /mod_mu/users/traffic 没有可用的响应:网络或 TLS 错误、超时,或 HTTP 错误状态码。
GET /mod_mu/users body 等以 body 结尾的形式 katana 读取响应时响应中断了。
parse UniProxy config response、parse UniProxy user response、parse /mod_mu/users、parse sspanel user list 等 面板有响应,但不是 katana 期望的 JSON:常见的是 HTML 错误页面、panel_type 设成了另一种面板,或在 Xboard 上有用户没有限速。
/mod_mu/users: panel returned ret=0 等 SSPanel 有响应,但拒绝了请求。

各种失败的后果:

  • 节点启动过程中,节点设置或用户请求失败会让节点等待后重试:见节点始终没有启动。
  • 轮询时,katana 保留最后一次收到的设置和用户。不会拆除任何东西,下一次轮询会重试。
  • 流量上报失败时,计数保留到下一次上报,不会丢失。
  • 检测日志上报失败时,该日志被丢弃。

api.timeout 是每个请求的时限,单位为秒;0 或不设置表示 5 秒。经常较慢的面板需要更大的值。保存的修改立即生效:katana 原地重建节点的面板客户端,并保留节点的连接。

WARN katana::manager::proxy: node V2ray_0.0.0.0_443: 37 inbound handshake failures in the last 1s (possible handshake scan/DoS or misconfigured clients)

每个基于 TCP 的节点都会统计在客户端完成认证之前失败的连接,并每秒检查一次计数。某一秒超过 10 次时,katana 写出这条警告。计入的有:

  • 在第一个流之前失败的传输层握手:TLS、WebSocket 升级、gRPC 的 HTTP/2 preface;
  • 失败的协议握手:未知用户、格式错误的请求、提前关闭或 10 秒内未完成握手的客户端;
  • 因节点达到活动连接数或预认证限制而被拒绝的连接。

这条警告只是告警:katana 不会因此拦截任何东西。Hysteria 2 节点不统计失败次数,也从不写出这条警告。

它通常意味着:

模式 可能的原因 怎么办
在面板中修改节点的传输层、TLS 或协议后立即出现一阵 客户端仍在使用旧设置。 无需处理,或让用户刷新订阅。
全天持续出现,来自大量地址 互联网扫描器在探测端口。 通常无害。如果在意这些噪音,可在主机防火墙中对新连接做速率限制。
所有客户端都失败,告警持续不断,没有人能连接 影响所有人的不匹配:node_type、enable_vless、证书或时钟。 见客户端无法连接。
计数非常高,debug 日志显示 pre-auth limit reached 或 live connection limit reached 节点触及了连接护栏。 见连接护栏。

要查看失败的原因,打开 katana::serve=debug 一分钟,阅读 inbound handshake failed 和 inbound transport ended 日志行,方法见客户端无法连接。