跳转到内容

节点

katana 配置文件中的每个 [[node]] 块对应一个节点。块中写明向哪个面板查询、查询哪个节点 ID,还包括面板不决定的那部分节点设置:监听地址、轮询频率、证书以及几个开关。其余一切都由面板提供,包括端口、传输层、TLS 设置、加密方式和用户。

本页介绍 [[node]]、[node.api]、[node.controller] 和 [node.controller.cert] 中的每个配置项,并说明多个节点如何共用一个进程、热重载如何判断修改后的块是否仍是同一个节点,以及节点无法启动时会发生什么。路由([node.route])和 Hysteria 2 表([node.hysteria])各有单独的页面,链接见文末。

两个示例都提供一个 TLS 节点,证书由你自己管理。请选择与你的面板对应的标签页。

/etc/katana/config.toml
[[node]]
panel_type = "NewV2board"
[node.api]
host = "https://panel.example.com"
node_id = 1
key = "replace-with-the-panel-key"
node_type = "V2ray"
enable_vless = true # serve VLESS; leave false for VMess
timeout = 10
[node.controller]
listen_ip = "0.0.0.0"
update_periodic = 60
[node.controller.cert]
mode = "file"
cert_file = "/etc/katana/fullchain.pem"
key_file = "/etc/katana/privkey.pem"

启动 katana 之前先检查配置文件:

终端窗口
katana --test -c /etc/katana/config.toml
Configuration OK

--test 能发现未知的配置项、类型错误、未知的 panel_type 或 node_type,以及写错的路由规则。它不向面板发送任何请求,也不绑定任何端口。除 Hysteria 2 以外的节点类型,它都不读取证书文件。因此,面板 URL 或密钥写错、listen_ip 无效、证书缺失,都能通过 --test,要到节点启动时才会以错误的形式暴露出来,节点会不断重试,直到你修复原因。这些错误见节点启动失败时。

[[node]] 是一个表数组:每个节点写一个块,每个块有自己的子表。直接写在块里的只有 panel_type。

键类型必填默认值说明
panel_typestring (enum)是—本节点使用的面板 API:NewV2board(UniProxy,用于 Xboard 和 V2board)、它的别名 V2board,或 SSpanel(mod_mu)。不区分大小写。不写时 --test 失败,报 unknown panel_type "";其他值也一样失败,报错里的值会转成小写。正常启动时,这样的节点会记日志并被跳过,只有一个节点都建不起来时 katana 才退出。热重载时遇到未知的值,katana 会拒绝整次重载,继续使用当前配置。属于节点身份的一部分。
apitable是—怎样连接面板、向面板要什么,写作 [node.api]:面板地址、节点 ID、密钥和节点类型,以及几项本地覆盖设置。
controllertable否{}节点在本机这一侧的设置,写作 [node.controller]:监听地址、轮询间隔、嗅探/规则/上报几个开关,以及证书子表 [node.controller.cert]。每个键都有默认值。
routetable否{}本节点的路由表,写作 [node.route],规则写在 [[node.route.rule]] 块里。不写时所有流都走 direct 出站。
hysteriatable否{}面板不提供的 Hysteria 2 节点设置,写作 [node.hysteria]:凭据格式、UDP 中继、伪装页面,以及可选的本地端口和混淆。只有 node_type 是 Hysteria 2 的取值时才会用到,否则忽略。

块中的每个表都拒绝未知的配置项,所以拼写错误会让 --test 和启动失败,而不是被忽略:

configuration error: config parse error: TOML parse error at line 5, column 1
|
5 | apihost = "x"
| ^^^^^^^
unknown field `apihost`, expected one of `host`, `node_id`, `key`, `node_type`, `enable_vless`, `vless_flow`, `timeout`, `speed_limit`, `device_limit`, `rule_list_path`, `disable_custom_config`

[node.api] 告诉 katana 面板在哪里、如何认证、要查询哪个节点。它还包含三个本地覆盖设置:enable_vless、speed_limit 和 rule_list_path。

键类型必填默认值说明
hoststring是—面板的基础 URL,要带协议头,例如 https://panel.example.com。面板部署在子路径下时,把路径也写上。katana 拼接 API 路径前会去掉末尾的斜杠。--test 不检查这个值:缺少 https:// 或 http:// 的地址能通过检查,但之后每次访问面板都会失败。属于节点身份的一部分,按原样比较。
node_idu32是—节点在面板里的 ID。写负数会解析失败,报 invalid value 错误,结尾是 expected u32。属于节点身份的一部分。
keystring是—面板的节点通信密钥:Xboard 和 V2board 里的 server token,SSPanel 里的 muKey。每次请求都带上它:UniProxy 面板放在查询参数 token 里,SSPanel 同时放在 key 和 muKey 里。属于节点身份的一部分。
node_typestring (enum)是—面板描述的节点类型,不区分大小写:V2ray、vmess 或 vless(三者都表示 V2ray 节点,除非打开 enable_vless,否则提供 VMess)、Trojan、Shadowsocks,或 Hysteria2、hysteria、hy2。UniProxy 面板会以小写形式在查询参数 node_type 里收到它(打开了 enable_vless 的 V2ray 节点则收到 vless),所以要按面板的写法填写。不写时报 unknown node_type ""。在 NewV2board 和 V2board 下,katana 请求的节点类型属于节点身份,所以热重载改变了请求的类型(不只是大小写)时会替换节点。其他改动,以及 SSPanel 下的任何改动,都会在热重载时新建面板客户端并立即生效。
enable_vlessbool否false让 V2ray 节点提供 VLESS 而不是 VMess。此时向 UniProxy 面板请求时使用 node_type=vless,并从面板的 network_settings 对象(而不是 networkSettings)读取传输层设置。SSPanel 也可以通过 custom_config 打开 VLESS,两处任意一处打开即可。在 NewV2board 和 V2board 下,对 node_type 为 V2ray 或 vmess 的节点打开或关闭它会改变 katana 请求的节点类型,而这属于节点身份,所以热重载时会替换节点。node_type = "vless" 时,无论开关与否,请求的类型都是 vless。其他情况下(包括 SSPanel),热重载改动它时会新建面板客户端并立即重建监听器。
vless_flowstring否""只用于 SSPanel 旧式 server 字符串:V2ray 节点的 VLESS 流控(flow)。任何非空值都会让这类节点失败,报 node requests kernel-unsupported feature: VLESS XTLS flow,所以请留空。UniProxy 面板和 SSPanel 的 custom_config 会自己给出 flow。热重载改动它时,katana 会新建面板客户端,改动立即生效。
timeoutu64否0每次面板 HTTP 请求的时限,单位为秒,从建立连接开始算到读完整个响应为止。0 表示 5 秒。热重载改动它时,katana 会就地新建面板客户端,不会替换节点。
speed_limitfloat否0限速覆盖值,单位 Mbps(1 Mbps 等于每秒 125 000 字节;小数和整数都可以)。大于 0 时,它取代面板为本节点下发的所有限速,包括节点级和每用户的限速,每个用户的速率都正好是这个值。0 或负数表示使用面板的限速。热重载改动它时,katana 会新建面板客户端,所有连接都保留;新速率作用于重载之后打开的每个流。
device_limitinteger否0可以写,但不起作用。katana 不限制每个用户的设备数。
rule_list_pathpath否""本地审计规则文件,每行一条正则表达式;空行和以 # 开头的行会被跳过。每条规则匹配目标域名或 IP(不含端口),匹配上的流会被拒绝。它和面板规则一起读取,所以 disable_get_rule = true 也会让这个文件失效。每次刷新规则时都会重新读取,所以修改文件内容会在下一个周期生效(SSPanel 下只有面板自己的规则请求成功并返回完整结果时才会重新读取)。文件读不了或某行正则无效时,katana 记日志并跳过。命中这些规则的流会被拒绝,但不会上报给面板。热重载改动路径时,katana 会新建面板客户端并立即读取新文件,连接不受影响。
disable_custom_configbool否false只用于 SSPanel。即使面板版本不低于 2021.11 并提供 custom_config,也从旧式 server 字符串读取节点设置。面板报告的版本低于 2021.11 或没有报告版本时,总是按 server 字符串解析。热重载改动它时,katana 会新建面板客户端,改动立即生效。

host 是基础 URL。katana 会去掉末尾的斜杠再拼接 API 路径,所以 https://panel.example.com/ 和 https://panel.example.com 访问的是同样的 URL。如果面板部署在某个路径下,要把路径写上:写 https://example.com/panel 时,katana 请求的是 https://example.com/panel/api/v1/server/UniProxy/config。

一定要写协议头。--test 接受 host = "panel.example.com",但由它拼出的每个请求都会失败,节点永远无法启动,只会不断重试。

katana 在每个请求的查询字符串中带上密钥,参数名按各面板的要求填写。

面板 节点设置请求 其他请求
NewV2board / V2board GET /api/v1/server/UniProxy/config?node_id=…&node_type=…&token=… …/user 和 …/push 上带同样三个参数
SSpanel GET /mod_mu/nodes/<node_id>/info?key=…&muKey=… key 和 muKey;用户列表请求和上报请求还带 node_id

UniProxy 面板同时按 ID 和类型查找节点。katana 发送的 node_type 是小写形式,唯一的例外是 enable_vless = true 的 V2ray 节点会以 vless 发送。在 katana 支持的节点类型中,Xboard 认识 vmess、vless、trojan、shadowsocks 和 hysteria,以及别名 v2ray 和 hysteria2,因此:

  • VLESS 节点要设置 enable_vless = true。只写 node_type = "vless" 时,katana 向面板查询的是 VLESS 节点,但在上面提供的是 VMess;
  • Hysteria 2 节点写 Hysteria2 或 hysteria。katana 也接受 hy2,但 Xboard 不认识它。

SSPanel 只按 ID 查找节点。katana 不支持 SSPanel 的 Shadowsocks 节点:SSpanel 搭配 node_type = "Shadowsocks" 可以通过配置检查,但节点永远无法启动:每次启动尝试一拉取设置就会失败,报 sspanel: Shadowsocks node type is not supported。

katana 从各面板读取的全部字段见各面板的单独页面。

speed_limit 的单位是 Mbps,katana 按 1 Mbps 等于每秒 125 000 字节换算。大于 0 时,它取代面板为本节点下发的所有限速。为 0 或负数时,katana 使用面板自己的限速。

speed_limit 面板限速 每个用户的速率
0 只有用户限速(UniProxy) 该用户的限速;为 0 时不限速
0 节点限速和用户限速(SSPanel) 两者中非零的较小值;都为 0 时不限速
50 任意 50 Mbps(每秒 6 250 000 字节),不管面板怎么设置

覆盖值不是整个节点的总速率,而是分别作用于每个用户。限速的具体实现见限速。

rule_list_path 指定一个正则表达式文本文件,每行一条。katana 用每条规则去匹配流所请求的目标(域名或 IP 地址,不含端口),第一条匹配上的规则即拒绝该流。规则不带锚定,所以 example\.com 也会匹配 example.com.example.net;如果只想匹配某个域名及其子域名,请写成 (^|\.)example\.com$。

/etc/katana/rules.txt
# One regular expression per line. Blank lines and lines starting with # are skipped.
(^|\.)tracker\.example\.com$
^203\.0\.113\.

katana 在拉取面板规则的同一次刷新中读取这个文件,所以 disable_get_rule = true 也会让这个文件失效。使用 UniProxy 面板时,katana 每个周期都重新读取该文件,因此修改文件内容会在下一个周期生效。使用 SSPanel 时,只有面板自己的规则请求成功并返回完整结果时,katana 才重新读取它;该请求失败或返回 304 Not Modified 时,已加载的规则保持不变。不是有效正则表达式的行会记录日志并被跳过。命中本地规则的流会被拒绝,但命中记录永远不会上报给面板。面板规则、命中上报和刷新时机见目标审计。

有两个配置项只在 panel_type = "SSpanel" 时有意义:

  • disable_custom_config = true 让 katana 即使在面板提供 custom_config 时,也从旧式 server 字符串解析节点。面板报告的版本早于 2021.11 或没有报告版本时,总是按旧式方式解析。
  • vless_flow 为 V2ray 节点的旧式解析提供 VLESS flow。katana 不支持 XTLS,所以请留空:任何值都会让这类节点失败,报 node requests kernel-unsupported feature: VLESS XTLS flow。使用 custom_config 时,katana 忽略此项,flow 取自面板。

UniProxy 面板会忽略这两个配置项。

[node.controller] 保存属于本机的设置:在哪里监听、多久与面板通信一次,以及三个开关。

键类型必填默认值说明
listen_ipstring否"0.0.0.0"监听器绑定的地址:VMess、VLESS、Trojan 和 Shadowsocks 节点绑定 TCP,Hysteria 2 绑定 UDP。端口始终来自面板(或 [node.hysteria].port)。写不带方括号的 IPv4 或 IPv6 地址,例如 "0.0.0.0"、"::" 或 "203.0.113.10"。--test 不检查它;地址不对时,节点启动时绑定失败。它也是节点标签的一部分,例如 V2ray_0.0.0.0_443。热重载改动它时会重建监听器。
send_ipstring否"0.0.0.0"可以写,但不起作用。katana 不把出站连接绑定到指定源地址,源地址由操作系统选择。
update_periodicu64否60两次轮询之间的秒数。所有周期性工作都由这一个定时器驱动:拉取节点设置和用户、刷新审计规则、上报流量和审计命中。0 按 1 处理。面板自己的推送和拉取间隔不会被读取。节点启动成功后过一个完整周期才进行第一次轮询。节点首次启动失败并重试时,两次尝试之间的等待时间也不会超过它,否则最长为 60 秒。热重载改动它时会重新开始计时。
disable_upload_trafficbool否false不再向面板上报用户流量。限速和审计规则照常生效。每个周期都会读取,所以热重载后从下一个周期开始生效。
disable_get_rulebool否false不再获取审计规则,面板规则和 rule_list_path 都不读。启动时就打开的话,节点没有任何审计规则。通过热重载打开时,只是停止刷新,已经加载的规则会一直生效到 katana 重启。已经记录的审计命中照常上报。
disable_sniffingbool否false不再从每个 TCP 流开头的数据里读取 TLS SNI 或 HTTP Host。嗅探结果只用于路由规则,让以 IP 为目标的流也能匹配域名规则;katana 实际连接的目标不会被改变。热重载改动它时会立即重建监听器,节点上的连接会断开。
certtable视情况{}监听器使用的证书,写作 [node.controller.cert]。Trojan 和 Hysteria 2 节点,以及面板标记为 TLS 的 V2ray 节点,都必须写上并设置 mode = "file"。热重载改动其中任何一个键时会重建监听器。

启动时,节点从面板拉取设置和用户,构建并绑定监听器,然后加载审计规则。其中任何一步失败,节点都会重试,直到成功为止(见节点启动失败时)。节点启动成功后,由一个定时器每 update_periodic 秒触发一次。每次触发运行一个周期,顺序如下:

  1. 拉取节点设置和用户列表。拉取失败时保留上一次成功的结果。
  2. 应用变化。新的用户集合会就地替换。端口、传输层或 TLS 设置变化时会重建监听器。用户列表为空时关闭监听器,直到重新有用户为止。
  3. 刷新审计规则,除非设置了 disable_get_rule = true。
  4. 上报每个用户的流量,除非设置了 disable_upload_traffic = true。
  5. 上报审计命中(仅 SSPanel;UniProxy 没有对应的接口)。

第一个周期在节点启动成功后过一个完整周期才运行,而不是立即运行。katana 接受的配置修改如果涉及 [node.api] 或某项监听器设置(listen_ip、[node.controller.cert]、disable_sniffing、[node.hysteria] 或 [node.route]),也会立即运行一个周期,但不改变定时器;详见修改运行中的节点会发生什么。按默认值 60,在面板中新增的用户最多可能要等一分钟才会被准入,流量也是按最长一分钟的批次到达面板。周期越短,变化到达得越快,发往面板的请求也越多。katana 不读取面板公布的推送和拉取间隔。

katana 收到 SIGINT 或 SIGTERM 停止时,每个节点先关闭监听器,再把剩余的流量和审计命中最后上报一次。

listen_ip 只是地址,端口始终来自面板。katana 为 VMess、VLESS、Trojan 和 Shadowsocks 节点绑定 TCP,为 Hysteria 2 绑定 UDP。"::" 监听 IPv6;在 Linux 默认的 net.ipv6.bindv6only = 0 下,也同时监听 IPv4。

katana 为每个运行中的节点取一个标签,由节点类型、监听地址和端口组成:V2ray_0.0.0.0_443、Trojan_203.0.113.10_8443、Shadowsocks_::_10086 或 Hysteria2_0.0.0.0_443。VLESS 节点的标签同样以 V2ray 开头。标签用来索引节点的审计规则,也会出现在少数日志行中,例如:

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

其他大多数节点日志用的是节点 ID:node 1: listening on 0.0.0.0:443。

默认情况下,katana 从每个 TCP 流开头的数据中读取 TLS SNI 或 HTTP Host,并交给路由规则使用。这样,直接连接 IP 地址的客户端仍然可以匹配 domain_suffix 或 geosite 规则。嗅探从不改变 katana 的连接目标:流仍然发往客户端请求的地址。UDP 数据包不做嗅探。

如果希望路由规则只看到客户端给出的目标,请设置 disable_sniffing = true。无论是否嗅探,审计规则始终匹配客户端请求的目标。

[node.controller.cert] 为监听器提供证书。katana 从不使用面板公布的证书设置,也没有 ACME 客户端,因此需要你自己申请和续期证书,并让 katana 指向这些文件。

键类型必填默认值说明
modestring (enum)视情况"none""none"(不用证书)或 "file"(读取 cert_file 和 key_file),区分大小写。所有使用 TLS 的节点都必须用 "file";否则流式节点报 TLS node requires cert.mode = "file",Hysteria 2 节点报 hysteria2 node requires cert.mode = "file"。ACME 模式 "dns"、"http"、"tls" 在任何流式节点上都会被拒绝,不论它是否用 TLS:node requests kernel-unsupported feature: ACME cert mode "dns";在 Hysteria 2 节点上,它们和其他不是 "file" 的值一样报错。在流式节点上,其他值的效果与 "none" 相同。
cert_filepath视情况""PEM 格式的证书链:服务器证书在前,中间证书在后(即 fullchain.pem)。mode = "file" 时必填;它或 key_file 为空时,使用 TLS 的节点或 Hysteria 2 节点报 TLS node requires cert.cert_file and cert.key_file。每次构建监听器时读取,文件变化本身不会触发读取。文件不存在时只报操作系统的错误,例如 No such file or directory (os error 2),错误里不含路径。
key_filepath视情况""与 cert_file 配对的 PEM 私钥。mode = "file" 时必填。读取时机与 cert_file 相同;私钥与证书不匹配时,监听器构建失败。
reject_unknown_snibool否false没有实现,所以写 true 会被拒绝,而不是悄悄忽略:节点报 node requests kernel-unsupported feature: cert.reject_unknown_sni。请保持 false。

哪些节点需要 mode = "file":

节点 TLS 是否需要证书
V2ray(VMess 或 VLESS) 由面板决定:UniProxy 的 tls = 1;SSPanel 的 custom_config 中 security = "tls" 或 "xtls",或旧式 server 字符串中的 tls。UniProxy 的 tls = 2(REALITY)会被拒绝 仅当面板开启 TLS 时
Trojan 始终使用 是
Shadowsocks 从不使用 否;保持 mode = "none"
Hysteria 2 始终使用,在 QUIC 内部 是

katana 在构建监听器时检查证书设置:节点首次启动时检查一次,此后每次重建时都会检查。对 Hysteria 2 节点,--test 也会检查这些设置;对其他类型则不检查。TLS 流式监听器接受 TLS 1.2 和 1.3;QUIC 始终使用 TLS 1.3。

一个 katana 进程可以服务任意数量的节点。每个 [[node]] 块都有自己的面板客户端、监听器、用户表、流量计数器、审计规则和路由表。所有节点共用 [[outbound]] 池和 [dns] 解析器。

下面的配置文件在一台机器上服务同一个面板的两个节点,各用一个地址:

/etc/katana/config.toml
[[node]]
panel_type = "NewV2board"
[node.api]
host = "https://panel.example.com"
node_id = 1
key = "replace-with-the-panel-key"
node_type = "V2ray"
[node.controller]
listen_ip = "203.0.113.10"
[node.controller.cert]
mode = "file"
cert_file = "/etc/katana/fullchain.pem"
key_file = "/etc/katana/privkey.pem"
[[node]]
panel_type = "NewV2board"
[node.api]
host = "https://panel.example.com"
node_id = 2
key = "replace-with-the-panel-key"
node_type = "Trojan"
speed_limit = 50
[node.controller]
listen_ip = "203.0.113.11"
disable_sniffing = true
[node.controller.cert]
mode = "file"
cert_file = "/etc/katana/fullchain.pem"
key_file = "/etc/katana/privkey.pem"

请记住以下几点:

  • 端口来自面板。 两个 TCP 节点或两个 Hysteria 2 节点,只有监听在不同的具体地址上时才能共用一个端口;0.0.0.0 和 :: 与所有地址都重叠。两个节点冲突时,后绑定的那个会失败,报 Address already in use (os error 98)。TCP 节点和 Hysteria 2 节点可以使用相同的端口号,因为一个绑定 TCP,另一个绑定 UDP。
  • 节点各自独立失败。 一个节点无法启动不会影响其他节点,在该节点重试期间 katana 也会继续运行。
  • 让每个块有不同的身份。 身份相同(见下文)的两个块都会启动,但热重载无法区分它们,会把所有修改都应用到第一个上。

katana 监视自己的配置文件,不重启就能应用修改。为此,它要判断新文件中的每个 [[node]] 是否是一个已经在运行的节点。它按五个值进行匹配,这五个值就是节点身份,合起来指向面板中的一个节点:

组成部分 比较方式
panel_type 不区分大小写,所以 NewV2board 和 newv2board 是同一个节点。NewV2board 和 V2board 是不同的值
[node.api].host 按原样比较,所以加一个末尾斜杠也算作改动
[node.api].node_id 按数值比较
[node.api].key 按原样比较
katana 向面板查询的节点类型 NewV2board / V2board:enable_vless = true 的 V2ray、Vmess 或 Vless 节点为 vless,否则为小写的 node_type。SSpanel 没有这一项,因为它只按 ID 查找节点

UniProxy 面板按 ID 和所查询的类型查找节点,所以同一个 ID 分别以 vmess 和 vless 查询时,在面板上是两个节点,各有自己的用户和流量。这就是在这类面板上所查询的类型属于节点身份的原因。

匹配结果的含义:

  • 身份相同: 是同一个节点。它保留流量计数器和审计状态,其余修改就地应用。修改 [node.api] 会为它构建新的面板客户端;有些修改会重建监听器;其余的完全不影响连接。
  • 身份从文件中消失: katana 停止该节点。它会关闭监听器(这会断开节点上的连接),并上报节点剩余的流量。
  • 新的身份: katana 从头启动一个新节点,与启动时完全相同。

因此,修改任何一个身份字段,都相当于先删除再添加。旧节点先停止,所以新节点可以绑定同一个端口。日志会记录每一步,用面板类型、host、ID 以及(在 UniProxy 面板上)所查询的类型来指代节点(从不包含密钥)。例如在 Xboard 上为 V2ray 节点开启 enable_vless 时,日志为:

INFO katana::runtime: reload: removing node newv2board@https://panel.example.com#1/v2ray
INFO katana::runtime: reload: added node newv2board@https://panel.example.com#1/vless

这个名称只省略了密钥,所以修改密钥后,两行日志显示的名称相同。SSPanel 节点的名称不含类型:sspanel@https://panel.example.com#1。保持身份不变的修改则记录为 reload: reconfigured node …。

修改内容 对运行中节点的影响
panel_type(仅改大小写除外)、host、node_id 或 key;在 NewV2board / V2board 上,还包括改变了所查询类型的 node_type 或 enable_vless 修改 替换节点:先停止,再从头启动
listen_ip、disable_sniffing,或 [node.controller.cert] 中的任何配置项 立即重建监听器,断开节点上的所有连接
node_type、enable_vless、vless_flow、speed_limit、rule_list_path、disable_custom_config 或 timeout,且节点未被替换 立即生效:katana 构建新的面板客户端,由它完整读取节点设置和用户。只有当返回结果改变了协议或传输层时,连接才会断开。enable_vless 还会重建监听器
update_periodic 定时器重新开始;下一个周期在一个完整的新周期之后运行
disable_upload_traffic 或 disable_get_rule 从下一个周期开始生效
send_ip 或 device_limit 没有影响;katana 不使用它们

第二行或第三行中的修改还会立即运行一次轮询周期,不必等待定时器:节点用新值向面板查询,应用返回结果(按该行所述重建监听器),刷新审计规则并上报流量。修改 speed_limit 或 rule_list_path 会保留所有连接:新的速率和规则作用于修改之后打开的每个流,包括已连接用户新开的流;已经打开的流保持原来的速率。在 SSPanel 上,node_type 和 enable_vless 不属于节点身份,所以对它们的修改总是就地应用。仍在重试首次启动的节点会保存这次修改,并立即用新值再试一次。

katana 在应用任何修改之前会先检查它:

  • 如果某个被修改的块无法构建新的面板客户端(例如 panel_type 或 node_type 未知),katana 会拒绝整次热重载,所有节点保持原样运行。新增或被替换的节点如果路由规则无法编译,也是如此。日志会指明是哪个节点:reload: node <name>: <error>; keeping current config。
  • 如果运行中节点的新 [node.route] 无法编译,该节点会记录 node <id>: config edit refused, keeping the running one: …,并保留之前的全部配置,包括面板客户端和监听器。

[node.route] 和 [node.hysteria] 的修改见各自的页面,文件其余部分见热重载。

节点首次启动分四步:拉取节点设置、拉取用户、构建并绑定监听器、加载审计规则。任何失败都不会让节点终止。前三步中的任何一步失败时,节点会在 ERROR 级别记录原因,等待一段时间,然后从第一步重新开始。第一次失败后等待 1 秒,此后每失败一次翻倍,最多 60 秒;如果 update_periodic 更短,则以它为上限。修改该节点的 [[node]] 块会提前结束等待:节点应用修改后立即重试,因为这次修改很可能就是修复。

stateDiagram-v2
  [*] --> Starting: katana 启动,或热重载添加了该节点
  Starting --> Serving: 设置、用户和监听器都已就绪,或尚无用户
  Starting --> Down: 拉取失败、端口为 0 或监听器失败
  Down --> Starting: 等待结束,或有修改作用到该节点
  Serving --> Serving: 每 update_periodic 秒一次轮询周期
  Serving --> Stopped: SIGINT、SIGTERM,或被热重载删除
  Down --> Stopped: SIGINT、SIGTERM,或被热重载删除
  Stopped --> [*]

每次失败的尝试记录一行日志 node <id>: <reason>; retrying in <N>s,其中 <N> 是距下一次尝试的等待时间:

步骤 出错原因 日志(级别 ERROR)
拉取节点设置 面板无法访问、超时,或返回 HTTP 错误状态,例如在 Xboard 上密钥错误或节点 ID 不存在 node 1: node_info failed: GET /api/v1/server/UniProxy/config; retrying in 1s(SSPanel:GET /mod_mu/nodes/1/info)
拉取节点设置 响应不是 katana 预期的 JSON,例如 host 指向了错误的网站,返回了状态码为 200 的 HTML 页面 node 1: node_info failed: parse UniProxy config response; retrying in 1s(SSPanel:parse /mod_mu/nodes/1/info)
拉取节点设置 JSON 描述的节点 katana 无法使用 node 1: node_info failed: newV2board: server port must be > 0; retrying in 1s、node 1: node_info failed: sspanel: Shadowsocks node type is not supported; retrying in 1s、node 1: node_info failed: /mod_mu/nodes/1/info: panel returned ret=0; retrying in 1s、…
拉取节点设置 katana 没有带缓存标签发起请求,面板却返回 304 Not Modified node 1: panel returned no node info; retrying in 1s
拉取节点设置 SSPanel 给出端口 0(UniProxy 的端口 0 则报 server port must be > 0) node 1: panel returned port 0; retrying in 1s
拉取用户 用户列表请求出现与拉取节点设置相同的请求错误 node 1: user_list failed: …; retrying in 1s
拉取用户 katana 没有带缓存标签发起请求,面板却返回 304 Not Modified node 1: panel returned no user list; retrying in 1s
构建监听器 功能不受支持被拒绝、证书问题,或绑定失败 node 1: initial start failed: node requests kernel-unsupported feature: REALITY; retrying in 1s、… TLS node requires cert.mode = "file"; …、… No such file or directory (os error 2); …、… Address already in use (os error 98); …

两次拉取都是必需的:节点拿到设置和用户列表之后才会启动,所以拉取用户列表失败与其他失败的步骤一样会被重试。retrying in 后面的数字随每次失败增长:1s、2s、4s,以此类推,直到上限。因此,暂时性的原因(例如面板正在重启、DNS 尚未响应,或端口仍被本 katana 所替换的进程占用)会自行消除。如果原因在配置中,修复后保存文件即可;如果原因在配置之外(例如证书文件缺失),修复后节点会在下一次尝试时启动。两种情况都不需要重启 katana。在节点启动之前,它不绑定任何端口,也不上报流量。katana 继续服务其他节点。如果失败的是唯一的节点,进程会在没有任何监听的状态下运行,服务管理器仍会显示它处于 active 状态;请留意这些日志行。

节点一旦启动成功,之后的失败同样不是致命的:

  • 轮询中拉取失败会记录一条警告,例如 node 1: node_info: GET /api/v1/server/UniProxy/config,节点保留上一次成功的设置和用户。
  • 轮询返回端口 0 时,会在 ERROR 级别记录 node 1: refreshed port is 0, keeping the last one。节点保留上一次的设置,用户仍随面板更新。
  • 重建监听器失败会记录 node 1: rebuild failed: …,节点暂时没有监听器。下一个周期会再次尝试。
  • 没有用户的节点不绑定任何端口,这不算错误,无论用户列表是在首次启动时就为空,还是之后才变为空。此时节点算作已启动,并在第一个带来用户的周期绑定监听器。监听器相关的错误(例如证书缺失)只会在那时以 rebuild failed 出现,并在每个周期重试。

面板请求失败时,日志只记录 katana 当时在做什么,例如 GET /api/v1/server/UniProxy/config 或 parse UniProxy config response,不包含底层原因。在节点所在的机器上手动发送同样的请求,即可看到状态码和响应内容:

终端窗口
curl -sS -H 'Accept: application/json' -w '\nHTTP %{http_code}\n' \
'https://panel.example.com/api/v1/server/UniProxy/config?node_id=1&node_type=vmess&token=replace-with-the-panel-key'

node_type 要用 katana 实际发送的值:你配置的值的小写形式,或在 V2ray、Vmess 或 Vless 节点设置 enable_vless = true 时为 vless。Xboard 对每种错误都返回 JSON 和错误状态码,katana 把它记录为失败的 GET:

状态码 消息 原因
422 Invalid token key 与面板的 server token 不一致
422 Invalid node type specified Xboard 不认识的 node_type,例如 hy2
400 Server does not exist 没有这个 ID 和类型的节点

这条命令会把密钥留在 shell 历史中。如果机器是多人共用的,事后请删除这条记录。

消息 原因和解决办法
configuration error: unknown panel_type "" 缺少 panel_type。在 [[node]] 块中(而不是 [node.api] 中)加上 panel_type = "NewV2board" 或 "SSpanel"。
configuration error: unknown panel_type "xboard" Xboard 请使用 NewV2board(或 V2board)。
configuration error: unknown node_type "" 缺少 [node.api].node_type。
configuration error: unknown node_type "vmess2" 请使用上文 node_type 一行中列出的值。
configuration error: config defines no [[node]] entries 文件中没有 [[node]] 块。
configuration error: node 1: hysteria2 node requires cert.mode = "file" Hysteria 2 节点需要证书。设置 mode = "file"、cert_file 和 key_file。
node 1: initial start failed: TLS node requires cert.mode = "file"; retrying in <N>s 这是 Trojan 节点,或面板将其标记为 TLS。加上证书表并设置 mode = "file"。
node 1: initial start failed: TLS node requires cert.cert_file and cert.key_file; retrying in <N>s 设置了 mode = "file",但有一个路径为空。
node 1: initial start failed: node requests kernel-unsupported feature: ACME cert mode "http"; retrying in <N>s katana 没有 ACME 客户端。请使用 mode = "file",证书由你自己续期。
node 1: initial start failed: node requests kernel-unsupported feature: VLESS XTLS flow; retrying in <N>s 在面板中去掉 flow;如果是 SSPanel 旧式节点,则清空 vless_flow。
node 1: initial start failed: Address already in use (os error 98); retrying in <N>s 该地址上的端口已被其他节点或程序占用。修改 listen_ip 或面板中的端口。
node 1: initial start failed: Cannot assign requested address (os error 99); retrying in <N>s listen_ip 不是本机的地址。

每出现一行 initial start failed,节点都会继续重试。修复原因后,它会在下一次尝试时启动;如果修复方式是修改它的 [[node]] 块,则会立即启动,不需要重启。katana 各部分的错误汇总见故障排查。