部署与升级
本页带你把一个能通过 --test 的 katana 二进制文件,变成可以长期运行、升级时不出意外的服务。内容包括:安装哪种 release 构建、文件放在哪里、每个配置文件运行一个 katana 进程的 systemd 模板单元、如何阅读日志、先重启一个实例再重启其他实例的升级流程、如何回滚、重启后要测试什么,以及内存和文件描述符如何随负载增长。
本页面向在装有 systemd 的 x86_64 Linux 上运行 katana v3.0.1 的运维人员。命令中使用两个示例实例 xboard 和 sspanel,每个面板一个。如果你还没有运行过 katana,请先阅读快速上手;katana 与 etemenanki-app 共有的服务行为(退出码、信号、日志过滤器)见生产环境运行。
生产节点的结构
Section titled “生产节点的结构”flowchart LR SD["systemd: katana@xboard"] --> P1["katana 进程"] SD2["systemd: katana@sspanel"] --> P2["katana 进程"] P1 --> C1["/etc/katana/config-xboard.toml"] P2 --> C2["/etc/katana/config-sspanel.toml"] P1 -- "stdout" --> J["journald"] P2 -- "stdout" --> J P1 -- "轮询并上报" --> PA["面板 A"] P2 -- "轮询并上报" --> PB["面板 B"]
- 一个二进制文件
/usr/local/bin/katana,所有实例共用。 - 每个实例一个配置文件。每个文件可以包含多个
[[node]]条目。 - 一个 systemd 模板单元
katana@.service。实例名决定使用哪个文件。 - 日志写到标准输出,由 journald 保存。
- katana 不写任何文件。它需要读取自己的配置、证书、geodata、规则列表,以及设置了的
[dns] ca_file,除此之外不需要访问磁盘上的其他内容。
选择 release 构建
Section titled “选择 release 构建”每个 katana release tag 都会发布两个 x86_64 Linux 可执行文件,各附一个 SHA-256 校验和文件。VERSION 是 tag,例如 v3.0.1。
katana-VERSION-linux-x86_64-gnu |
katana-VERSION-linux-x86_64-musl |
|
|---|---|---|
| 链接方式 | 动态链接主机的 glibc。OpenSSL 编译在内。 | 完全静态:没有程序解释器,也没有共享库。 |
| 主机要求 | glibc 版本不低于构建主机,即 Ubuntu 22.04(glibc 2.35)。 | 任意 x86_64 Linux,包括 Alpine。 |
[dns] backend = "system" |
glibc 的 getaddrinfo,遵循 /etc/nsswitch.conf 及其 NSS 模块。 |
musl 的解析器,直接读取 /etc/hosts 和 /etc/resolv.conf。 |
| 内存分配器 | glibc 的 malloc |
musl 的 malloc |
release workflow 会检查它承诺的这两项特性:如果 -gnu 二进制文件动态加载 libssl 或 libcrypto,workflow 失败;如果 -musl 二进制文件有任何动态依赖,workflow 也失败。
如何选择:
| 主机 | 构建 |
|---|---|
| Ubuntu 22.04 及以上,Debian 12 及以上 | -gnu;如果希望所有主机用同一个二进制文件,也可以用 -musl |
| Debian 11、Ubuntu 20.04、RHEL 9 及其重构发行版(glibc 2.34)、Alpine | -musl |
域名解析依赖 NSS 模块(例如 nss-resolve、LDAP 或自定义的 hosts: 行) |
-gnu |
| 不确定 | -musl |
katana 不自带内存分配器,因此两种构建在分配每个缓冲区和用户表时使用的分配器也不同。一种构建的内存数据无法推断另一种构建的表现。选定一种构建后,升级时保持不变,这样前后对比衡量的是新版本,而不是新的分配器。
要确认主机能否运行 -gnu 构建,执行该二进制文件的 --version。glibc 太旧时会在这一步直接失败,报 version `GLIBC_2.xx' not found,与配置无关。
从 release 页面或用 GitHub CLI,把二进制文件和对应的 .sha256 文件下载到同一目录。OWNER 是托管 katana 仓库的账号,你需要有该仓库的读取权限。.sha256 文件按资产的原始文件名引用它,因此请在下载目录中、重命名或移动任何文件之前执行校验:
VERSION=v3.0.1BUILD=musl # 或 gnugh release download "$VERSION" --repo OWNER/katana \ --pattern "katana-$VERSION-linux-x86_64-$BUILD*"sha256sum -c "katana-$VERSION-linux-x86_64-$BUILD.sha256"katana-v3.0.1-linux-x86_64-musl: OK输出不是 OK 就说明下载不完整或已损坏:请重新下载,不要安装。校验和与二进制文件来自同一个 CI job,因此它能发现文件损坏,但无法发现文件被替换。这些资产是普通可执行文件,不是压缩包。首次安装时的同一下载流程见安装。
规划文件布局
Section titled “规划文件布局”katana 没有内置的文件位置。它从 -c 读取配置,其他所有文件都从配置中写明的路径读取。下面的布局把所有实例的文件都放在 /etc/katana 下:
文件夹usr/local/bin/
- katana 所有实例运行的二进制文件
- katana.prev 上一个版本,升级后保留,用于回滚
文件夹etc/
文件夹katana/ 属主 root,属组 katana,权限 0750
- config-xboard.toml 实例
katana@xboard,权限 0640 - config-sspanel.toml 实例
katana@sspanel,权限 0640 文件夹certs/
- fullchain.pem TLS 和 Hysteria 2 节点使用的证书链
- privkey.pem 私钥,权限 0640,属组 katana
- geoip.dat 仅当路由规则使用
geoip时需要 - geosite.dat 仅当路由规则使用
geosite时需要 - rules.txt 本地审计规则,仅当设置了
rule_list_path时需要
- config-xboard.toml 实例
文件夹systemd/
文件夹system/
- katana@.service 下文的模板单元
文件夹katana@xboard.service.d / 可选的单实例覆盖配置
- override.conf
配置中的每个路径都写成绝对路径。像 geoip = "geoip.dat" 这样的相对路径,katana 会相对于进程的工作目录打开,而不是相对于配置文件,并且报错时不会指出是哪个文件:
configuration error: No such file or directory (os error 2)按上述布局配置的节点如下:
[log]level = "info"
[[node]]panel_type = "NewV2board"
[node.api]host = "https://panel.example.com"node_id = 1key = "replace-with-the-panel-key"node_type = "V2ray"rule_list_path = "/etc/katana/rules.txt"
[node.controller]listen_ip = "0.0.0.0"update_periodic = 60
[node.controller.cert]mode = "file"cert_file = "/etc/katana/certs/fullchain.pem"key_file = "/etc/katana/certs/privkey.pem"
[node.route]default = "direct"geoip = "/etc/katana/geoip.dat"geosite = "/etc/katana/geosite.dat"
[[node.route.rule]]outbound = "block"geoip = ["private"]创建服务用户,并一次性设置好属主和权限:
sudo useradd --system --no-create-home --shell /usr/sbin/nologin katanasudo install -d -o root -g katana -m 0750 /etc/katana /etc/katana/certssudo chown root:katana /etc/katana/*.toml /etc/katana/certs/*.pemsudo chmod 0640 /etc/katana/*.toml /etc/katana/certs/*.pem配置文件中保存着面板密钥,因此不要让其他用户能读取它们。katana 只读取这些文件,所以目录和文件都不需要对 katana 可写。
在 systemd 下运行 katana
Section titled “在 systemd 下运行 katana”将下面的内容保存为 /etc/systemd/system/katana@.service。实例名中 @ 之后的部分决定配置文件:katana@xboard 运行 /etc/katana/config-xboard.toml。
[Unit]Description=katana node agent (%i)After=network-online.targetWants=network-online.target
[Service]Type=execUser=katanaGroup=katanaWorkingDirectory=/etc/katanaEnvironment=NO_COLOR=1# 仅当 [dns] backend 为 "tls" 或 "https" 且未设置 ca_file 时需要:# Environment=SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crtExecStartPre=/usr/local/bin/katana --test -c /etc/katana/config-%i.tomlExecStart=/usr/local/bin/katana -c /etc/katana/config-%i.tomlRestart=on-failureRestartSec=5sLimitNOFILE=1048576
# 仅当面板为某个节点分配了 1024 以下的端口时需要。AmbientCapabilities=CAP_NET_BIND_SERVICECapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yesProtectSystem=strictProtectHome=yesPrivateTmp=yesPrivateDevices=yesProtectKernelTunables=yesProtectKernelModules=yesProtectControlGroups=yesRestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINKRestrictNamespaces=yesLockPersonality=yesSystemCallArchitectures=native
[Install]WantedBy=multi-user.target然后启动实例并跟踪它们的日志:
sudo systemctl daemon-reloadsudo systemctl enable --now katana@xboard katana@sspaneljournalctl -u 'katana@*' -f各项设置的作用
Section titled “各项设置的作用”| 设置 | 原因 |
|---|---|
After= 和 Wants=network-online.target |
每个节点在启动后会立即向面板请求自己的设置。首次尝试失败的节点会自行重试:第一次在 1 s 后,之后等待时间逐次翻倍,最长 60 s;如果 update_periodic 更短,则以它为上限。在网络和 DNS 就绪之后再启动,可以避免 journal 中出现一批首次尝试的错误,也能避免最长约一分钟的延迟:等到网络就绪时,节点距下一次尝试的等待时间可能已经增长到这么长。见重启与节点故障。 |
ExecStartPre=… --test |
拒绝启动有以下问题的文件:无法解析、含未知配置项、指定了未知的 panel_type、node_type、出站或 geodata 分类、指向无法读取的 geodata 文件、Hysteria 2 设置无效,或者没有任何 [[node]]。直接启动时,katana 会跳过无法构建的节点并运行其余节点;这项检查让有问题的节点导致整个启动失败,你才能注意到。--test 会在 journal 中打印 Configuration OK。 |
Restart=on-failure |
katana 以状态 1 退出,或被 SIGTERM、SIGINT、SIGHUP、SIGPIPE 以外的信号杀死(例如 OOM killer 发出的 SIGKILL)后,重新启动它。systemctl stop 或 SIGHUP 之后不会重启。ExecStartPre= 失败也算作失败:在 RestartSec=5s 下,永远达不到 systemd 默认的启动次数上限(10 秒内 5 次),因此有问题的配置会每 5 秒重试一次,每次记录相同的错误,修好文件后实例会自动启动。 |
LimitNOFILE=1048576 |
每个客户端连接占用一个描述符,通常出站还要再占一个。systemd 默认的软限制 1024 很快就会耗尽。见文件描述符。 |
AmbientCapabilities=CAP_NET_BIND_SERVICE |
让非特权的 katana 用户可以绑定 1024 以下的端口。见1024 以下的端口。 |
Environment=NO_COLOR=1 |
即使标准输出不是终端,katana 也会输出 ANSI 颜色码。NO_COLOR 可以关闭颜色,journal 中显示的就是纯文本,而不是 [2m 之类的序列。 |
WorkingDirectory=/etc/katana |
为配置中的相对路径提供兜底。使用绝对路径时不需要它。 |
ProtectSystem=strict 及其他加固选项 |
katana 只读取文件和打开网络 socket,因此文件系统对它可以是只读的,系统的其余部分也可以对它隐藏。如果你的环境需要某一行所禁止的功能,删掉那一行即可。 |
TimeoutStopSec= 保持默认的 90 秒。收到 SIGTERM 后,每个节点会关闭监听器和连接,然后发送最后一次流量上报,在 SSPanel 上还会再发送一次审计上报。每次上报最多耗时 api.timeout 秒(未设置时为 5 秒),各节点并行执行。如果 systemd 在此之前就不得不发送 SIGKILL,最后一个轮询周期的流量就会丢失。
1024 以下的端口
Section titled “1024 以下的端口”每个节点的端口由面板决定,而不是配置文件。唯一的例外是设置了 [node.hysteria].port 的 Hysteria 2 节点,它直接监听该端口,不询问面板。被分配端口 443 的节点需要 CAP_NET_BIND_SERVICE。没有该能力时,节点会记录下面的错误并不断重试,而进程和其他所有节点照常运行:
ERROR katana::manager::node: node 1: initial start failed: Permission denied (os error 13); retrying in 1s这些重试不会自行成功。进程的 capability 是在启动时获得的,因此授予该权限后,需要重启实例。
授予该权限有三种方式:
| 方式 | 做法 | 说明 |
|---|---|---|
| 单元 capability | AmbientCapabilities= 和 CapabilityBoundingSet=,如上面的单元所示 |
推荐。它属于服务本身,因此升级二进制文件后依然有效。 |
| 文件 capability | sudo setcap cap_net_bind_service=+ep /usr/local/bin/katana |
保存在文件上。下文的升级流程会安装一个新文件,新文件没有该 capability,因此下次重启后所有低端口节点都会失败。避免使用。 |
| 全系统设置 | sysctl net.ipv4.ip_unprivileged_port_start=443 |
允许主机上的所有用户绑定这些端口。 |
如果所有节点都使用 1024 及以上的端口,删除 AmbientCapabilities= 这一行,并把 CapabilityBoundingSet= 留空,这样进程就不持有任何 capability。
重启与节点故障
Section titled “重启与节点故障”Restart=on-failure 监视的是进程,而不是进程内的节点。只有在无法加载配置、无法构建出站池、没有任何 [[node]],或者一个节点都无法创建时,katana 才会以状态 1 退出。无法启动的节点则会自行重试,原因可能是启动时无法连上面板、面板返回端口 0 或没有返回用户列表,或者端口已被占用。每次尝试失败它都会记录一条错误,而 systemd 仍然显示该单元为 active (running):
ERROR katana::manager::node: node 2: node_info failed: …; retrying in 1sERROR katana::manager::node: node 3: initial start failed: Address already in use (os error 98); retrying in 4s第一次失败后 1 s 进行第一次重试。之后每次等待时间翻倍,最长 60 s;如果 update_periodic 更短,则以它为上限。每次尝试都会重新向面板请求并重新构建监听器,因此原因排除后,节点会在下一次尝试时启动:面板有响应、端口空闲、证书可读。保存对该节点 [[node]] 条目的修改,会立即触发下一次尝试。只有进程在启动时才读取的修改,例如单元设置或 capability,才需要重启实例。
每次启动后,都要按冒烟测试中的说明,确认每个节点都记录了 listening on 行。
运行多个实例
Section titled “运行多个实例”一个 katana 进程可以服务多个节点:在一个文件中重复写 [[node]] 即可。在以下情况下,可以把节点拆分到多个实例:
- 希望重启一组节点时不断开其他节点的连接,例如每个面板一个实例;
- 希望先升级一组节点,其余节点保留旧二进制文件,直到新版本经过验证;
- 希望日志分开,即
journalctl -u katana@xboard和journalctl -u katana@sspanel。
实例之间不会相互协调。请遵守以下规则:
| 规则 | 原因 |
|---|---|
| 每个面板节点只由一个实例服务。 | 面板只给节点分配一个端口,因此后启动的实例无法绑定它。该实例会为这个节点记录 initial start failed: Address already in use (os error 98); retrying in …s 并不断重试,因此另一个实例释放该端口后(例如那个实例停止时),它会在下一次尝试时占用该端口。 |
listen_ip 有重叠的实例之间,端口不能重复。默认值 0.0.0.0 与所有 IPv4 地址都重叠。 |
面板按节点分配端口,而 katana 看不到其他实例的端口。第二次绑定会以 Address already in use (os error 98) 失败,该节点会不断重试。Hysteria 2 节点监听 UDP,因此可以与 TCP 节点使用同一个端口号。 |
| 每个实例使用自己的 WireGuard 密钥,或者把所有 WireGuard 出站放在同一个实例中。 | 每个进程各自建立隧道。使用同一私钥连接同一对端的两条隧道会互相抢占对端的会话。 |
| 内存和 DNS 流量会略有增加。 | 每个进程都会构建自己的出站池、解析器缓存和用户表。 |
每个实例都会监视 /etc/katana,因为这是它配置文件所在的目录。保存某个实例的文件,会让所有实例重新读取各自的文件。文件没有变化的实例不会应用任何修改,也不会记录日志。
对于只有某一个实例需要的设置,使用 drop-in,而不是修改模板:
sudo systemctl edit katana@xboard[Service]Environment=RUST_LOG=info,katana=debug重启该实例使其生效:sudo systemctl restart katana@xboard。
katana 每个事件向标准输出写一行,journald 以单元名保存。每行包含 UTC 时间戳、级别、模块和消息:
2026-09-24T08:00:01.512304Z INFO katana::manager::node: node 1: listening on 0.0.0.0:4432026-09-24T08:00:01.733918Z WARN katana::manager::node: node 2: report traffic: …2026-09-24T09:14:52.004816Z INFO katana::runtime: shutting down查看 journal
Section titled “查看 journal”journalctl -u katana@xboard -f # 跟踪单个实例journalctl -u 'katana@*' --since '10 min ago' # 所有实例journalctl -u 'katana@*' -b -g 'WARN|ERROR' # 本次开机以来的问题journalctl -u katana@xboard -g 'listening on' -n 50 # 哪些节点已启动选择日志级别
Section titled “选择日志级别”日志过滤器取以下各项中第一个已设置的:
- 环境变量
RUST_LOG,前提是它能被解析; - 配置文件中的
[log].level; info。
如果只想在某次运行中使用某个级别而不改配置,按运行多个实例中的方法,在 drop-in 中设置 RUST_LOG。如果希望长期生效,修改配置中的 [log].level:katana 会立即应用新的 [log].level,无需重启,也不会断开连接,并且此后它会取代 RUST_LOG 过滤器。常用的值:
| 值 | 输出内容 |
|---|---|
info |
启动、监听器、重载和关闭相关的日志行,以及警告和错误。这是默认值,也是生产环境的合适级别。 |
warn |
只有警告和错误。 |
info,katana=debug |
katana 自身的模块使用 debug 级别,例如因超出限制而被拒绝的连接。 |
debug |
所有模块都使用 debug 级别,包括内核的逐连接错误。在繁忙的节点上输出量很大。 |
在 debug 级别下,繁忙的节点可能超出 journald 的速率限制,journald 随后会丢弃日志行,并记录 Suppressed N messages from katana@xboard.service。调试期间,可以在该实例的 drop-in 中设置 LogRateLimitIntervalSec=0 来放宽限制,调试结束后再删掉。过滤器语法的完整说明见生产环境运行。
值得关注的日志行
Section titled “值得关注的日志行”| 日志行 | 级别 | 含义 |
|---|---|---|
node N: listening on IP:PORT |
INFO | 节点正在提供服务。面板没有为该节点列出任何用户时,不会出现这一行:节点有用户之前,katana 不绑定任何端口。 |
node N: node_info failed: …、node N: panel returned no node info、node N: panel returned port 0、node N: user_list failed: …、node N: panel returned no user list、node N: initial start failed: …,均以 ; retrying in Ns 结尾 |
ERROR | 节点尚未启动,将在 N 秒后重试。等待时间从 1 s 开始翻倍,最长 60 s;如果 update_periodic 更短,则以它为上限。 |
node N: node_info: …、node N: user_list: … |
WARN | 某次轮询无法连上面板。节点保留上一次的设置和用户。 |
node N: report traffic: … |
WARN | 一次流量上报失败。katana 保留这些字节数,在下一次上报时一并发送。 |
node N: rebuild failed: … |
ERROR | 运行中的节点失去了监听器,例如因为证书缺失。它会在每次轮询时重试。 |
accept error, backing off 100ms: Too many open files (os error 24) |
WARN | 达到了描述符上限。请提高 LimitNOFILE=。 |
node TAG: N inbound handshake failures in the last 1s (possible handshake scan/DoS or misconfigured clients) |
WARN | 某个节点在一秒内有超过 10 次握手失败。TAG 的形式为 V2ray_0.0.0.0_443。 |
cannot read rule_list_path PATH: … |
WARN | 本地审计规则列表不存在,或 katana 无法读取。在之后某次读取成功之前,节点不使用本地规则运行。在 SSPanel 上,只有面板下发了规则列表的那次轮询才会读取。 |
config reload failed, keeping current: …、reload: bad outbounds, keeping current config: …、reload: node …: …; keeping current config |
ERROR | 对配置文件的修改被整体拒绝,例如因为某个节点指定了未知的 node_type。修改的任何部分都不会应用,每个节点都按原样继续运行。 |
node N: config edit refused, keeping the running one: … |
ERROR | 该节点修改后的条目无法构建,例如因为某条路由规则引用了未知的出站 tag。该节点继续以之前的设置运行。 |
shutting down |
INFO | katana 收到了 SIGINT 或 SIGTERM。 |
重启实例会断开其上的所有连接,并且在旧进程发送最后几次上报、新进程从面板获取节点期间,该实例的节点会有几秒钟无法访问。客户端会自行重连。下面的流程确保在停止任何服务之前,新二进制文件能接受所有配置;保留旧二进制文件以便回滚;并且在新版本通过冒烟测试之前,只让一个实例运行新版本。
flowchart TB
D["下载并校验校验和"] --> T{"所有配置都通过 --test?"}
T -- 否 --> X["到此为止,旧二进制文件继续运行"]
T -- 是 --> K["把旧二进制文件保留为 katana.prev"]
K --> I["通过重命名安装新二进制文件"]
I --> C["重启一个实例"]
C --> W{"节点在监听、客户端可用、流量已上报?"}
W -- 否 --> R["回滚"]
W -- 是 --> A["重启其他实例"]
A --> M["观察内存一天"]
-
记录基线。 记下每个实例的内存,并针对旧版本执行一遍冒烟测试,以便有可以对比的数据:
终端窗口 systemctl show -p MemoryCurrent katana@xboard katana@sspanel -
下载并校验新版本,方法同下载并校验。使用与当前运行版本相同的构建,
-gnu或-musl。 -
把新二进制文件以临时名称放在旧文件旁边,并确认它能在这台主机上运行:
终端窗口 sudo install -m 0755 "katana-$VERSION-linux-x86_64-$BUILD" /usr/local/bin/katana.new/usr/local/bin/katana.new --version -
以服务用户身份,用新二进制文件测试每个配置。新版本可能拒绝旧版本接受的配置项,而 katana 会拒绝未知配置项:
终端窗口 sudo -u katana sh -c 'for f in /etc/katana/config-*.toml; doprintf "%s: " "$f"/usr/local/bin/katana.new --test -c "$f" || echo FAILEDdone'整个循环以
katana身份运行,因此文件列表来自只有 root 和katana组能读取的目录。每个文件都必须打印Configuration OK。如果有文件失败,就此停下,先修好配置;正在运行的实例不受影响。以katana身份运行还能发现服务用户无法读取的文件,例如 geodata 或 Hysteria 2 节点的私钥。--test不会读取其他节点类型的证书,也不读取规则列表;这些由冒烟测试覆盖。 -
保留当前二进制文件,以便回滚:
终端窗口 sudo cp -p /usr/local/bin/katana /usr/local/bin/katana.prev -
通过重命名安装新二进制文件,覆盖旧文件:
终端窗口 sudo mv -f /usr/local/bin/katana.new /usr/local/bin/katana不要用
cp覆盖/usr/local/bin/katana。Linux 不允许以写方式打开正在运行的可执行文件,因此复制会以Text file busy失败。重命名只替换目录项:正在运行的进程继续使用旧文件,下次启动时使用新文件。 -
重启一个实例,观察它启动:
终端窗口 sudo systemctl restart katana@xboardjournalctl -u katana@xboard -f预期先看到启动检查输出的
Configuration OK,然后每个有用户的节点各输出一行node N: listening on …,并且没有ERROR行。 -
对该实例做冒烟测试,至少持续一个轮询周期,即
update_periodic秒(默认 60),确保第一次流量上报已经发出。按冒烟测试操作,并与基线对比。 -
重启其余实例,可以逐个重启,也可以一起重启:
终端窗口 sudo systemctl restart katana@sspanel -
持续观察接下来一天的内存和 journal。预期情况见内存。
要回到上一个版本,先确认它仍然接受这些配置,再把它重命名回原位,然后重启运行新版本的实例:
sudo -u katana sh -c ' for f in /etc/katana/config-*.toml; do printf "%s: " "$f" /usr/local/bin/katana.prev --test -c "$f" || echo FAILED done'sudo mv -f /usr/local/bin/katana.prev /usr/local/bin/katanasudo systemctl restart katana@xboard如果你在升级过程中添加了只有新版本才认识的配置项,--test 这一步就很重要。旧版本会以 unknown field 拒绝该文件,在上面的单元下会拒绝启动;请先删掉该配置项。与任何重启一样,回滚会再次断开该实例的连接。
重命名会用掉 katana.prev。如果想保留它,先复制一份(sudo cp -p /usr/local/bin/katana.prev /usr/local/bin/katana.prev2)。
--test 通过只说明文件有效。它不会联系面板、不绑定端口、不读取规则列表,也不读取除 Hysteria 2 节点以外任何节点的证书。只有真正启动,才能说明节点可以工作。
要只查看本次运行的日志行,而不包括重启前那个进程的日志,可以按本次运行的 systemd invocation ID 过滤:
id=$(systemctl show -p InvocationID --value katana@xboard)journalctl _SYSTEMD_INVOCATION_ID="$id" -g 'listening on|WARN|ERROR'按顺序完成以下检查,只需几分钟:
| 检查项 | 方法 | 预期结果 |
|---|---|---|
| 每个节点都已启动 | 按上面的方法查看本次运行的 journal | 每个有用户的节点各有一行 listening on,端口为面板分配的端口,并且没有 ERROR 行 |
| 端口已绑定 | sudo ss -ltnp | grep katana(TCP)和 sudo ss -lunp | grep katana(Hysteria 2) |
每个节点的端口都归 katana 所有 |
| 客户端能连接 | 使用真实客户端和面板中某个测试用户的订阅,通过它打开一个 HTTPS 网站 | 页面正常加载。对于 TLS 节点,客户端接受证书 |
| 路由正常 | 通过客户端访问某条规则会发往 block 或某个具名出站的目标 |
被拦截,或从预期的出口出去 |
| UDP 正常 | 如果节点中继 UDP,通过客户端执行一次 DNS 查询或运行其他 UDP 应用 | 收到响应 |
| 流量已上报 | 通过客户端下载一个已知大小的文件,然后等待 update_periodic 秒 |
面板中测试用户的用量增加约等于该大小乘以节点的流量倍率 |
| 没有新的警告 | journalctl -u katana@xboard --since '15 min ago' -g 'WARN|ERROR' |
与基线相比没有新增内容 |
关于这些检查的几点说明:
- 流量上报成功时 katana 不记录任何日志,只有失败时才记录。需要到面板确认上报结果。
- 有些面板在后台队列中处理上报,因此面板上的数字可能比上报稍晚一些。例如 Xboard 会把每次上报交给一个队列任务处理,这需要它的 queue worker 正在运行。
- 升级前,针对旧版本运行同样的客户端测试。比较两次运行,比单独评判一次运行更快发现差异。
- 如果某个 TLS 节点没有
listening on行,检查它的证书路径和权限。对于 Hysteria 2 以外的所有节点类型,构建监听器时 katana 才第一次读取这些文件,失败会表现为initial start failed: …; retrying in …s,而不会出现在--test中。节点每次重试都会重新读取这些文件,因此文件就位且可读后,节点就会启动。
katana 在构建节点的监听器时读取该节点的证书和私钥,因此续期后的证书要等监听器重建后才会生效。续期时配置文件没有任何变化,所以不会自动触发重建。请在 ACME 客户端的 deploy hook 中,在新文件就位且 katana 组可读之后,重启使用该证书的实例:
install -m 0640 -o root -g katana fullchain.pem /etc/katana/certs/fullchain.peminstall -m 0640 -o root -g katana privkey.pem /etc/katana/certs/privkey.pemsystemctl restart katana@xboard katana@sspanel与任何重启一样,这次重启会断开这些实例的连接。由于升级一节中的警告,不要让证书续期在升级过程中执行。
按节点、以及每个节点上的用户规划内存:
- 用户。 每个节点都会为自己的用户构建一张表,包含每个用户的密钥材料和流量计数器。内存随用户数乘以服务这些用户的节点数而增长。一个可以使用十个节点的用户会被保存十份。
- 连接。 每个打开的连接都占用自己的缓冲区;对于流式节点,还持有一个指向其连接时所用用户表的引用。面板的用户列表变化时,节点会为新连接构建一张新表,而旧表会一直留在内存中,直到最后一个在旧表下建立的连接关闭。在用户多、连接持续时间长的节点上,可能同时存在好几代用户表。
- 实例。 每个实例都持有自己的用户表、解析器缓存和出站。
因此,启动后随着客户端连接和用户列表变化,内存会先上涨,然后才趋于平稳。评判新版本时,要看它在数小时内稳定下来的水平,而不是最初几分钟,并与同一构建的基线对比。
systemctl status katana@xboard | grep Memorysystemctl show -p MemoryCurrent katana@xboard如果你在 drop-in 中用 MemoryMax= 设置了硬限制,请在观察到的水平之上留出充足余量。内核在达到限制时杀死 katana,实例上的所有连接都会断开,而且由于 katana 把计数器保存在内存中,自上次上报以来统计的流量会丢失。之后 Restart=on-failure 会再次启动它。
每个已接受的 TCP 连接占用一个描述符,每个到达出站的流通常还要再占一个。一个 gRPC 连接可以承载多个 stream,每个 stream 都有自己的出站。一个直连的 UDP 流可能为每个地址族各占一个 socket。Hysteria 2 节点的所有客户端共用一个 UDP socket,但它的 stream 与其他节点一样会打开出站 socket。
katana 不会自行提高描述符上限,因此 systemd 给它的上限就是它能用的上限。用尽时,节点会停止接受连接:它记录 accept error, backing off 100ms: Too many open files (os error 24),并每隔 100 ms 重试一次,直到有描述符被释放。LimitNOFILE=1048576 足以覆盖多个节点都达到连接上限的情况。查看运行中实例的情况:
pid=$(systemctl show -p MainPID --value katana@xboard)sudo ls /proc/$pid/fd | wc -lgrep 'open files' /proc/$pid/limits以下限制是内置的,无法配置。它们保护的是节点而不是主机,因此请按实际负载来设定 LimitNOFILE= 和内存,而不是按这些数字。
| 限制 | 值 | 达到时 |
|---|---|---|
| 每节点的活动连接数(流式节点) | 65,536 个 socket | 新 socket 被立即关闭,并计为一次握手失败。 |
| 每节点处于 TLS、WebSocket 或 HTTP/2 握手中的 socket 数 | 2,048 | 节点停止接受连接,直到有一个握手完成,或占位满 10 s。 |
| 每节点处于协议握手中的 stream 数 | 512 | 新 stream 被丢弃,并计为一次握手失败。 |
| 完成协议握手的时限(流式节点) | 10 s | 连接被关闭,并计为一次握手失败。 |
| 双向都没有流量的连接(流式节点) | 360 s | 连接被关闭。通常协议自身 300 s 的空闲超时会先关闭空闲的流。 |
| 每节点的 Hysteria 2 QUIC 连接数 | 4,096 | 新连接被拒绝。 |
| 每节点所有连接合计的 Hysteria 2 中继 stream 和 UDP 关联数 | 65,536 | 新 stream 被拒绝;新 UDP 关联的数据包被丢弃。 |
| 症状 | 原因 | 解决方法 |
|---|---|---|
单元为 active (running),但某个节点没有 listening on 行 |
节点的面板请求失败、面板返回了端口 0 或没有返回用户列表,或者绑定失败。也可能是节点还没有用户。 |
查看该节点最新的 ERROR 行,它以 ; retrying in Ns 结尾。排除原因后,节点会在下一次重试时启动;只有修改了单元设置或 capability 后才需要重启实例。如果是没有用户,节点会在出现用户后的第一次轮询时绑定端口。 |
initial start failed: Permission denied (os error 13); retrying in …s |
使用 1024 以下的端口却没有 CAP_NET_BIND_SERVICE,常见于升级后 setcap 设置的 capability 丢失。 |
使用单元中的 AmbientCapabilities=,然后重启实例。 |
initial start failed: Address already in use (os error 98); retrying in …s |
另一个实例或程序占用了该端口。--test 无法检测到这种情况。 |
保证各实例之间端口不重复。其他占用者释放该端口后,节点会在下一次重试时占用它。 |
单元在 ExecStartPre 失败,报 configuration error: No such file or directory (os error 2) |
配置文件不存在,或者它引用的文件(geodata 或 [dns] ca_file)不存在,通常是因为使用了相对路径。 |
核对实例名与文件名,并使用绝对路径。 |
启动检查报 configuration error: Permission denied (os error 13),或者 Hysteria 2 节点的证书或私钥报 configuration error: node N: Permission denied (os error 13) |
katana 用户无法读取配置或其中引用的文件。 |
属组设为 katana,权限设为 0640。 |
version `GLIBC_2.xx' not found |
在 glibc 较旧的主机上使用了 -gnu 构建。 |
改用 -musl 构建。 |
cp: cannot create regular file '/usr/local/bin/katana': Text file busy |
试图复制覆盖正在运行的二进制文件。 | 按升级步骤中的方法,通过重命名安装。 |
journal 中出现 [2m 之类的序列 |
颜色码。 | Environment=NO_COLOR=1。 |
journalctl -p warning 什么也不显示 |
journald 把 katana 的日志行保存为 info。 |
用 -g 'WARN|ERROR' 过滤。 |
| 服务停止了,systemd 没有重启它 | 它收到了 SIGHUP,或者是被有意停止的。 |
删除任何发送 SIGHUP 的 ExecReload=。 |
accept error, backing off 100ms: Too many open files (os error 24) |
描述符上限太低。 | 提高 LimitNOFILE=。 |
更多节点级错误以及面板响应的含义,见故障排查。