生产环境运行
本页介绍在 Linux 服务器上无人值守地运行 etemenanki-app 和 katana 所需的内容:命令行、每种退出状态的含义、进程如何响应信号、日志写到哪里以及如何控制日志、为每个程序准备的加固 systemd 单元,以及一套可以反复执行、不出意外的升级流程。
两个程序的命令行形式、信号处理和日志栈都相同,所以本页大部分内容同时适用于两者。有差异的地方会用表格标出。本指南的 katana 部分介绍与面板相关的运维;本页只涉及 katana 与 etemenanki-app 的共同之处。
两个程序一览
Section titled “两个程序一览”| etemenanki-app | katana | |
|---|---|---|
| 配置文件 | -c 指定路径,默认为工作目录下的 config.toml |
相同 |
--test 成功时的输出 |
在标准输出打印 Configuration OK. |
在标准输出打印 Configuration OK |
--test 失败时的输出 |
configuration invalid: …,经由日志器写到标准输出 |
configuration error: …,写到标准错误 |
| 优雅停止 | SIGINT、SIGTERM |
SIGINT、SIGTERM |
| 重载 | 配置文件变化时自动进行 | 配置文件变化时自动进行 |
| 重载信号 | 无;SIGHUP 会终止进程 |
无;SIGHUP 会终止进程 |
| 日志 | 标准输出 | 标准输出 |
运行中修改 [log].level |
忽略,直到下次启动 | 立即生效 |
两个二进制文件接受同样的四个参数,除此之外没有别的。没有子命令,也没有位置参数。
| 参数 | 取值 | 默认值 | 作用 |
|---|---|---|---|
-c, --config |
路径 | config.toml |
要加载的 TOML 文件。相对路径相对于进程的工作目录解析,而不是二进制文件所在的位置。 |
--test |
无 | 关闭 | 解析文件并构建其中描述的全部内容,打印结果后退出。不绑定端口,也不建立连接。 |
-h, --help |
无 | 打印用法,并以状态码 0 退出。 |
|
-V, --version |
无 | 打印名称和版本,例如 etemenanki-app 2.0.0 或 katana 3.0.1,并以状态码 0 退出。这里的版本是程序自身的包版本,因此只改动某个库的内核发布(例如 etemenanki 2.0.1 或 2.0.2)仍会打印 etemenanki-app 2.0.0。 |
未知参数,或者 -c 后面没有值,属于用法错误:程序会向标准错误打印类似 error: unexpected argument '--bogus' found 的信息,并以状态码 2 退出。
--test 检查什么
Section titled “--test 检查什么”--test 执行的代码与正常启动相同,一直执行到程序即将打开 socket 之前。
- etemenanki-app 解析文件,然后构建 DNS 解析器、每个出站、每个负载均衡器、路由表(会加载 geodata)以及每个入站(会读取 TLS 证书和私钥)。正常启动做的事情完全相同,之后再绑定监听器。
- katana 解析文件,构建出站池,然后为每个
[[node]]构建面板客户端和路由表,并检查 Hysteria 2 节点的本地设置。它不会联系面板,因此由面板下发的所有内容,例如节点的协议、端口和传输层,都要到节点启动时才会检查。
两个程序在 --test 中都不会检查任何依赖于运行中系统的条件:
- 端口是否空闲,或者进程是否有权限绑定它;
- 进程是否有权限创建 TUN 设备;
- 上游服务器、DNS 服务器或面板是否可达。
这些问题只会在启动时暴露。例如,一个标签为 tun-in、设备名为 etm0 的 TUN 入站,以非特权用户运行时能通过 --test,但启动时会失败并报错 failed to start: inbound tun-in bind tun etm0 failed: Operation not permitted (os error 1)。
| 状态 | 含义 |
|---|---|
0 |
--test 通过;-h 或 -V 已打印;或者进程在收到 SIGINT 或 SIGTERM 后停止。 |
1 |
--test 失败,或者启动失败。etemenanki-app 在以下情况启动失败:文件无法读取或无效,或者任一入站无法绑定。katana 在以下情况启动失败:文件无法读取或无效,出站池无法构建,文件中没有 [[node]],或者没有任何一个节点的面板客户端和路由表能够构建成功。 |
2 |
命令行用法错误。 |
被 SIGHUP 杀死 |
进程没有 SIGHUP 处理程序,因此由内核终止。shell 报告状态 129;systemd 报告 code=killed, status=1/HUP。 |
启动时,etemenanki-app 以 failed to start: … 记录失败原因。katana 记录以下之一:failed to load config: …、failed to build outbounds: …、config defines no [[node]] entries 或 no nodes could be started。
路径与工作目录
Section titled “路径与工作目录”所有相对路径都相对于进程的工作目录解析。这包括 -c 路径,以及文件中的每个路径,例如 cert_file、key_file、ca_file、geoip、geosite 和 rule_list_path。(Unix socket 的 listen 路径总是绝对路径:etemenanki-app 只有在 listen 以 / 开头时才将其视为路径。)相对路径不会相对于配置文件所在目录解析。
[inbound.stream.tls]cert_file = "tls/fullchain.pem" # 从 <工作目录>/tls/fullchain.pem 读取key_file = "tls/privkey.pem"在 /etc/etemenanki 下检查时,这个文件能通过。从任何其他目录以 -c /etc/etemenanki/config.toml 检查时,它会失败:
ERROR etemenanki_app: configuration invalid: No such file or directory (os error 2)这条消息不会指出缺失的是哪个文件。看到它时,先检查 -c,再检查配置中的每个相对路径。
要避免这个问题,要么全部使用绝对路径,要么始终以配置目录作为工作目录运行程序。下文的 systemd 单元通过 WorkingDirectory= 采用后一种做法。
两个程序监听的都是配置文件所在的目录,而不是文件本身,这样那些通过写入新文件再重命名来保存的编辑器也能被察觉。该目录中的任何文件事件,包括文件被创建、写入、重命名、删除,甚至仅仅被打开,都会让程序重新读取配置文件。随后 etemenanki-app 会把文件字节与上次读取的版本比较,katana 则比较解析后的设置,因此无关文件不会触发重载。请让这个目录只存放配置,不要放日志或其他频繁变动的文件。
这两种比较方式有一个重要差异。etemenanki-app 在任何字节变化时都会重载,所以即便只修改了注释或空白,也会重建全部内容并关闭所有连接;此时重载日志显示为 config reload: no changes。katana 在解析后的设置没有变化时什么都不会应用。
两个程序都没有重载信号。重载在磁盘上的配置文件发生变化时进行;参见热重载。
flowchart TB S["启动"] --> L["读取并解析配置"] L -- "出错" --> E1["exit 1"] L --> B["构建出站、路由、入站"] B -- "出错" --> E1 B -->|"--test"| E0["exit 0"] B --> N["绑定监听器"] N -- "出错" --> E1 N --> R["运行中"] R -- "配置文件变化" --> R R -- "SIGINT 或 SIGTERM" --> D["关闭监听器和连接"] D --> E0 R -- "SIGHUP" --> K["被内核杀死"]
图中展示的是 etemenanki-app。katana 的流程与之相同,只是它会分别构建和启动每个节点:构建失败的节点会被记录并跳过,只有当没有任何节点能够构建时,进程才以 1 退出。
| 信号 | etemenanki-app | katana |
|---|---|---|
SIGINT(Ctrl-C) |
优雅停止,退出码 0 |
优雅停止,退出码 0 |
SIGTERM |
优雅停止,退出码 0 |
优雅停止,退出码 0 |
SIGHUP |
立即终止进程,不输出 shutting down 行 |
同左;尚未上报给面板的流量会丢失 |
SIGKILL |
立即终止进程 | 同左;尚未上报给面板的流量会丢失 |
优雅停止时先记录 shutting down,然后:
- etemenanki-app 停止接受新连接,关闭每个监听器,并立即关闭所有已打开的连接。它不会等待连接结束。Unix socket 监听器会删除其 socket 文件。Hysteria 2 入站会关闭其 QUIC 连接,并最多等待约 6 秒让其 UDP 端口释放;其他入站都会立即停止。
- katana 停止每个节点:每个节点关闭自己的监听器和连接,然后向面板上报尚未上报的流量,在 SSPanel 上还会上报待提交的审计结果。每个请求最多耗时该节点的
api.timeout,未设置时为 5 秒,因此一次停止大约可能耗时其两倍。
第一次收到 SIGINT 或 SIGTERM 之后,后续的 SIGINT 和 SIGTERM 信号都会被忽略。如果停止过程卡住,只有 SIGKILL 能结束它。TimeoutStopSec=(默认 90 秒)到期后,systemd 会自行发送 SIGKILL。
两个程序都把日志写到标准输出,每个事件一行。在 systemd 下,由 journal 收集。每行包含 UTC 时间戳、级别、记录该日志的模块以及消息:
2026-09-24T20:23:44.726638Z INFO etemenanki_app::instance: inbound socks-in listening on 127.0.0.1:10802026-09-24T20:23:45.424572Z INFO etemenanki_app: shutting down即使标准输出不是终端,这些行也包含 ANSI 颜色码,在 journal 和日志文件中会显示为 [2m 这样的序列。设置环境变量 NO_COLOR=1 可以关闭颜色。下文的单元都设置了它。
选择日志级别
Section titled “选择日志级别”过滤器取自以下各项中第一个已设置的:
- 环境变量
RUST_LOG,前提是它已设置且能够解析。无法解析的RUST_LOG会被整体忽略。空的RUST_LOG也算已设置,并且不启用任何日志。 - 配置文件中的
[log].level。如果文件无法读取或解析,会跳过这一步,因此解析错误仍会以info级别记录。 info。
两者使用相同的指令语法:一个逗号分隔的列表,其中单独的级别设置默认值,target=level 为某个模块及其下所有模块覆盖默认值。多条指令同时匹配时,最具体的 target 生效,与它在列表中的位置无关。
| 值 | 效果 |
|---|---|
info |
启动、监听器和重载日志行,以及警告和错误。默认值。 |
warn |
只有警告和错误。 |
debug |
为每个以错误结束的连接增加一行日志,以及更多内容。在繁忙的服务器上输出量很大。 |
info,etemenanki_protocols=debug |
全局 info,协议实现使用 debug。 |
warn,etemenanki_app::instance=info |
全局只记录警告,另外保留监听器和重载日志行。 |
info,katana=debug |
katana 自身的模块使用 debug,内核使用 info。 |
off |
什么都不输出。 |
级别包括 error、warn、info、debug 和 trace,另外还有 off。target 是把 - 写成 _ 的 crate 名:etemenanki_app、katana、etemenanki_protocols、etemenanki_environment 和 etemenanki_concepts,后面可以再跟 ::module。
[log]level = "info,etemenanki_protocols=debug"RUST_LOG=debug etemenanki-app -c config.toml # 本次运行覆盖 [log].level运行时修改日志级别
Section titled “运行时修改日志级别”| etemenanki-app | katana | |
|---|---|---|
运行中修改 [log].level |
不生效。级别保持启动时的值。 | 立即生效,不会重启任何节点。 |
| 修改的副作用 | 算作一次配置变化:重载记录 config reload: log changed,重启每个监听器并关闭所有连接。 |
除了新的级别外没有其他影响。 |
运行中删除 [log].level |
不生效 | 级别变为 info。 |
| 新值无法解析 | 不生效 | 记录 invalid log level "…": … 并保留当前级别。 |
以 RUST_LOG 启动 |
RUST_LOG 在进程整个生命周期内保持有效。 |
第一次修改 [log].level 就会替换 RUST_LOG 过滤器。 |
在 systemd 下运行 etemenanki-app
Section titled “在 systemd 下运行 etemenanki-app”下面的单元以非特权用户运行 etemenanki-app,只授予它所需的 capability,并在每次启动前检查配置。它假设如下目录布局:
文件夹/usr/local/bin/
- etemenanki-app
文件夹/etc/etemenanki/ owner root, group etemenanki, mode 0750
- config.toml mode 0640
文件夹tls/
- fullchain.pem
- privkey.pem mode 0640
-
创建系统用户,不带登录 shell,也没有主目录:
终端窗口 sudo useradd --system --no-create-home --shell /usr/sbin/nologin etemenanki -
安装二进制文件:
终端窗口 sudo install -m 0755 etemenanki-app /usr/local/bin/etemenanki-app -
安装配置,使其归 root 所有,而服务用户只能读取。配置中包含密码和密钥,因此不能对所有人可读:
终端窗口 sudo install -d -o root -g etemenanki -m 0750 /etc/etemenankisudo install -o root -g etemenanki -m 0640 config.toml /etc/etemenanki/config.toml/etc/etemenanki/tls/下的私钥也需要同样的root:etemenanki所有权和0640权限。 -
以服务用户身份检查,并在服务将使用的工作目录下运行:
终端窗口 sudo -u etemenanki sh -c 'cd /etc/etemenanki && exec /usr/local/bin/etemenanki-app --test -c config.toml'Configuration OK.
将以下其中一个保存为 /etc/systemd/system/etemenanki.service。第二个版本用于包含 TUN 入站的配置:高亮的行有所不同,并且去掉了 PrivateDevices=yes。
[Unit]Description=etemenanki-app proxyAfter=network-online.targetWants=network-online.target
[Service]Type=execUser=etemenankiGroup=etemenankiWorkingDirectory=/etc/etemenankiEnvironment=NO_COLOR=1ExecStartPre=/usr/local/bin/etemenanki-app --test -c /etc/etemenanki/config.tomlExecStart=/usr/local/bin/etemenanki-app -c /etc/etemenanki/config.tomlRestart=on-failureRestartSec=5sLimitNOFILE=1048576
# 无需以 root 运行即可绑定 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[Unit]Description=etemenanki-app proxyAfter=network-online.targetWants=network-online.target
[Service]Type=execUser=etemenankiGroup=etemenankiWorkingDirectory=/etc/etemenankiEnvironment=NO_COLOR=1ExecStartPre=/usr/local/bin/etemenanki-app --test -c /etc/etemenanki/config.tomlExecStart=/usr/local/bin/etemenanki-app -c /etc/etemenanki/config.tomlRestart=on-failureRestartSec=5sLimitNOFILE=1048576
# CAP_NET_ADMIN 用于创建和配置 TUN 设备。AmbientCapabilities=CAP_NET_BIND_SERVICE CAP_NET_ADMINCapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_NET_ADMINDeviceAllow=/dev/net/tun rw
NoNewPrivileges=yesProtectSystem=strictProtectHome=yesPrivateTmp=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 etemenankijournalctl -u etemenanki -f服务启动后,journal 中每个入站会有一行 inbound … listening on …。
各项设置的作用
Section titled “各项设置的作用”| 设置 | 原因 |
|---|---|
WorkingDirectory=/etc/etemenanki |
配置中的相对路径相对于它解析,启动和 ExecStartPre= 都是如此。 |
ExecStartPre=… --test … |
配置有误时拒绝启动,并把错误记录为预启动步骤失败,与绑定错误区分开。对 etemenanki-app 来说,这与启动本身的检查是重复的。它保护不了正在运行的服务:systemctl restart 会先停止旧进程,再运行检查。请在重启前自己先运行 --test。 |
Restart=on-failure |
在以状态码 1 退出或崩溃后重启,但在 systemctl stop、SIGTERM、SIGINT 或 SIGHUP 之后不会重启。配置有误时,每次尝试都会以同样的方式失败。由于 RestartSec=5s,永远不会触发默认的启动次数限制(10 秒内 5 次),因此 systemd 会每 5 秒重试一次,直到文件被修正。 |
LimitNOFILE=1048576 |
每个客户端连接占用一个描述符,通常还要为其出站连接再占用一个。systemd 默认的软限制 1024 很快就会用完;此时 etemenanki-app 记录 accept error, backing off 100ms: Too many open files (os error 24),并每 100 ms 重试一次,直到有描述符释放。每个 TCP 或 Unix socket 入站最多维持 65,536 个活动连接;参见限制。 |
CAP_NET_BIND_SERVICE |
仅在入站端口低于 1024 时需要。没有它,启动会失败并报错 Permission denied (os error 13)。如果所有端口都不低于 1024,可以删掉这两行 capability 设置。 |
CAP_NET_ADMIN |
仅 TUN 入站需要,用于创建设备、分配地址并添加其 routes。etemenanki-app 的其他部分都不使用它;WireGuard 出站运行在用户态,不需要任何特权。 |
DeviceAllow=/dev/net/tun rw,不设 PrivateDevices= |
PrivateDevices=yes 会隐藏 /dev/net/tun。TUN 版本去掉了它,并只允许访问这一个设备。 |
AF_NETLINK |
TUN 入站通过 netlink 安装路由。默认的 system DNS 后端调用的 glibc getaddrinfo 也会打开 netlink socket 来读取主机地址。 |
ProtectSystem=strict |
整个文件系统对服务只读。etemenanki-app 不写任何文件,只有 listen 在路径上的入站会创建 Unix socket 文件。对于这类入站,请添加 RuntimeDirectory=etemenanki,并把 socket 放在 /run/etemenanki/ 下。 |
NO_COLOR=1 |
避免颜色码进入 journal。 |
单元中没有 ExecReload=。因此 systemctl reload etemenanki 会报错并且不做任何改变,这是有意为之:程序会在文件变化时自行重载。
-
把编辑好的文件放在正在使用的文件旁边,所有权和权限保持一致,这样文件就位后服务能够读取:
终端窗口 sudo install -o root -g etemenanki -m 0640 config.toml /etc/etemenanki/config.toml.new -
以服务用户身份检查:
终端窗口 sudo -u etemenanki sh -c 'cd /etc/etemenanki && exec /usr/local/bin/etemenanki-app --test -c config.toml.new' -
把它移到正式位置。 运行中的服务会察觉到变化,记录
config reload: …,并切换到新配置。重载会关闭所有已打开的连接:终端窗口 sudo mv /etc/etemenanki/config.toml.new /etc/etemenanki/config.toml
如果新文件最终还是无效,运行中的服务会记录 reload: parse failed, keeping current config: … 或 reload: build failed, keeping current config: …,并继续使用旧配置。不过下一次启动会失败。热重载介绍了重载会重建哪些内容,以及端口无法绑定时会发生什么。
在 systemd 下运行 katana
Section titled “在 systemd 下运行 katana”一个 katana 进程可以服务多个节点:在一个文件中重复写 [[node]] 即可。当节点需要各自独立重启时,例如每个面板一个进程,使用单独的进程会更方便。systemd 模板单元可以为每个配置文件运行一个进程:
文件夹/etc/katana/ owner root, group katana, mode 0750
- xboard.toml mode 0640
- sspanel.toml mode 0640
文件夹/etc/systemd/system/
[Unit]Description=katana node agent (%i)After=network-online.targetWants=network-online.target
[Service]Type=execUser=katanaGroup=katanaWorkingDirectory=/etc/katanaEnvironment=NO_COLOR=1ExecStartPre=/usr/local/bin/katana --test -c /etc/katana/%i.tomlExecStart=/usr/local/bin/katana -c /etc/katana/%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@ 后面的实例名决定使用哪个文件:katana@xboard 运行 /etc/katana/xboard.toml。
sudo useradd --system --no-create-home --shell /usr/sbin/nologin katanasudo systemctl daemon-reloadsudo systemctl enable --now katana@xboard katana@sspaneljournalctl -u 'katana@*' -f与 etemenanki-app 的不同之处:
--test比启动更严格。 启动时会跳过无法构建的节点;而ExecStartPre=会直接拒绝整个文件,这样某个节点里的拼写错误就不会让该节点悄无声息地停摆。- 端口由面板决定。 katana 绑定面板为每个节点分配的端口,所以你可能事先不知道是否需要
CAP_NET_BIND_SERVICE。katana 不需要其他 capability,也不写任何文件。 - 停止需要几秒钟。 每个节点在退出时会向面板上报最后的流量。请让
TimeoutStopSec=保持默认值,或者至少设为api.timeout的几倍,以免 systemd 在上报发出之前就杀死进程。 - 各实例共用一个目录。 每个实例都监听
/etc/katana,因此编辑其中一个文件会让所有实例重新读取各自的文件。文件没有变化的实例不会应用任何改动。 Restart=on-failure针对的是进程,而不是单个节点。 已经构建但无法启动的节点不会让进程结束;它会自行重试,其他节点照常运行。每次失败的尝试都会记录一行日志,例如node 1: node_info failed: …; retrying in 1s(第一次面板请求失败)或node 1: initial start failed: …; retrying in 1s(例如端口无法绑定)。等待时间从 1 秒开始,每失败一次翻倍,上限为 60 秒与该节点update_periodic中较短的一个。保存对该节点[[node]]条目的修改会立即触发重试。systemd 看到的仍是一个正常运行的进程,所以请在日志中留意retrying in。问题解决后,例如面板恢复响应或端口已释放,节点会在下一次尝试时启动,无需重启。只有修复单元本身的问题(例如缺少 capability)才需要systemctl restart。katana 部分介绍了运行中的节点在之后面板不可达时的行为。
同一套流程适用于两个程序。它在改动任何东西之前,先用新的二进制文件检查正在使用的配置,保留旧的二进制文件以便回滚,并通过重命名来替换文件。下面的命令以 etemenanki-app 为例。对于 katana,请改用 /usr/local/bin/katana、katana 用户和 /etc/katana,对每个实例文件分别运行一次检查(例如 -c xboard.toml),并且预期输出是不带句点的 Configuration OK。
-
把新的二进制文件以不同的名字放在旧文件旁边:
终端窗口 sudo install -m 0755 etemenanki-app /usr/local/bin/etemenanki-app.new/usr/local/bin/etemenanki-app.new --version -
用新的二进制文件检查正在使用的配置,以服务用户身份、在服务的工作目录下运行。新版本可能会拒绝旧版本接受的某个键,这一步就是用来发现这种情况的:
终端窗口 sudo -u etemenanki sh -c 'cd /etc/etemenanki && exec /usr/local/bin/etemenanki-app.new --test -c config.toml'如果它没有打印
Configuration OK.,就到此为止。运行中的服务不受影响。 -
保留当前的二进制文件,以便回滚:
终端窗口 sudo cp -p /usr/local/bin/etemenanki-app /usr/local/bin/etemenanki-app.prev -
通过重命名替换文件,不要直接复制覆盖正在运行的文件:
终端窗口 sudo mv -f /usr/local/bin/etemenanki-app.new /usr/local/bin/etemenanki-appLinux 不允许以写方式打开正在运行的可执行文件,因此用
cp覆盖它会失败并报错Text file busy。重命名只替换目录项:运行中的进程继续使用旧文件,下次启动时使用新文件。 -
重启服务。 这会关闭所有已打开的连接;客户端会自行重连:
终端窗口 sudo systemctl restart etemenanki对于 katana 实例:
sudo systemctl restart 'katana@*'。 -
确认服务正在运行,并且每个入站都已重新开始监听:
终端窗口 systemctl status etemenankijournalctl -u etemenanki -n 20
要回滚,把旧的二进制文件重命名回原位并重启:
sudo mv -f /usr/local/bin/etemenanki-app.prev /usr/local/bin/etemenanki-appsudo systemctl restart etemenanki| 现象 | 原因 | 解决办法 |
|---|---|---|
--test 或启动时报 No such file or directory (os error 2) |
从工作目录看,-c 路径或配置中的某个相对路径不存在。 |
检查 WorkingDirectory=,或者改用绝对路径。 |
--test 或启动时报 Permission denied (os error 13),且不含 bind 一词 |
服务用户无法读取配置或配置中引用的文件。 | 把这些文件的属组设为 etemenanki(或 katana),权限设为 0640。 |
failed to start: inbound … bind 0.0.0.0:443 failed: Permission denied (os error 13) |
端口低于 1024,但没有 CAP_NET_BIND_SERVICE。 |
添加该 capability,或者改用更高的端口。 |
node 1: initial start failed: Permission denied (os error 13); retrying in …(katana) |
面板分配了低于 1024 的端口,而单元缺少 CAP_NET_BIND_SERVICE。该节点会不断重试绑定,而每次尝试都以同样的方式失败。 |
在单元中添加该 capability 并重启实例。进程无法在运行期间获得新的 capability。 |
failed to start: inbound … bind … failed: Address already in use (os error 98) |
另一个进程占用了该端口。--test 检测不到这种情况。 |
停止另一个进程,或者更换端口。 |
failed to start: inbound … bind tun … failed: Operation not permitted (os error 1) |
没有 CAP_NET_ADMIN。 |
使用 TUN 版本的单元。 |
accept error, backing off 100ms: Too many open files (os error 24) |
描述符限制太低。 | 调高 LimitNOFILE=。 |
| 完全没有日志输出 | [log].level 不是级别名或为 off,或者 RUST_LOG 被设为 off 或空字符串。 |
设置 [log].level = "info",并检查单元的 Environment=。 |
journal 中出现 [2m、[0m 之类的序列 |
颜色码。 | 设置 Environment=NO_COLOR=1。 |
| 服务停止了,systemd 却没有重启它 | 它收到了 SIGHUP,或者是被有意停止的。 |
删除任何发送 SIGHUP 的 ExecReload=。 |
config hot-reload disabled: …(etemenanki-app)或 config watcher disabled (no live reload): …(katana) |
文件监听器无法启动,通常是因为 inotify 限额已耗尽。服务会继续运行,但不再自动重载。 | 调高 fs.inotify.max_user_instances 或 fs.inotify.max_user_watches,然后重启。 |
在 etemenanki-app 中修改 [log].level 不生效 |
级别只在启动时读取。 | 重启服务。 |