跳转到内容

生产环境运行

本页介绍在 Linux 服务器上无人值守地运行 etemenanki-app 和 katana 所需的内容:命令行、每种退出状态的含义、进程如何响应信号、日志写到哪里以及如何控制日志、为每个程序准备的加固 systemd 单元,以及一套可以反复执行、不出意外的升级流程。

两个程序的命令行形式、信号处理和日志栈都相同,所以本页大部分内容同时适用于两者。有差异的地方会用表格标出。本指南的 katana 部分介绍与面板相关的运维;本页只涉及 katana 与 etemenanki-app 的共同之处。

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 执行的代码与正常启动相同,一直执行到程序即将打开 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。

所有相对路径都相对于进程的工作目录解析。这包括 -c 路径,以及文件中的每个路径,例如 cert_file、key_file、ca_file、geoip、geosite 和 rule_list_path。(Unix socket 的 listen 路径总是绝对路径:etemenanki-app 只有在 listen 以 / 开头时才将其视为路径。)相对路径不会相对于配置文件所在目录解析。

/etc/etemenanki/config.toml(片段)
[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:1080
2026-09-24T20:23:45.424572Z INFO etemenanki_app: shutting down

即使标准输出不是终端,这些行也包含 ANSI 颜色码,在 journal 和日志文件中会显示为 [2m 这样的序列。设置环境变量 NO_COLOR=1 可以关闭颜色。下文的单元都设置了它。

过滤器取自以下各项中第一个已设置的:

  1. 环境变量 RUST_LOG,前提是它已设置且能够解析。无法解析的 RUST_LOG 会被整体忽略。空的 RUST_LOG 也算已设置,并且不启用任何日志。
  2. 配置文件中的 [log].level。如果文件无法读取或解析,会跳过这一步,因此解析错误仍会以 info 级别记录。
  3. 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。

config.toml
[log]
level = "info,etemenanki_protocols=debug"
终端窗口
RUST_LOG=debug etemenanki-app -c config.toml # 本次运行覆盖 [log].level
etemenanki-app katana
运行中修改 [log].level 不生效。级别保持启动时的值。 立即生效,不会重启任何节点。
修改的副作用 算作一次配置变化:重载记录 config reload: log changed,重启每个监听器并关闭所有连接。 除了新的级别外没有其他影响。
运行中删除 [log].level 不生效 级别变为 info。
新值无法解析 不生效 记录 invalid log level "…": … 并保留当前级别。
以 RUST_LOG 启动 RUST_LOG 在进程整个生命周期内保持有效。 第一次修改 [log].level 就会替换 RUST_LOG 过滤器。

下面的单元以非特权用户运行 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
  1. 创建系统用户,不带登录 shell,也没有主目录:

    终端窗口
    sudo useradd --system --no-create-home --shell /usr/sbin/nologin etemenanki
  2. 安装二进制文件:

    终端窗口
    sudo install -m 0755 etemenanki-app /usr/local/bin/etemenanki-app
  3. 安装配置,使其归 root 所有,而服务用户只能读取。配置中包含密码和密钥,因此不能对所有人可读:

    终端窗口
    sudo install -d -o root -g etemenanki -m 0750 /etc/etemenanki
    sudo install -o root -g etemenanki -m 0640 config.toml /etc/etemenanki/config.toml

    /etc/etemenanki/tls/ 下的私钥也需要同样的 root:etemenanki 所有权和 0640 权限。

  4. 以服务用户身份检查,并在服务将使用的工作目录下运行:

    终端窗口
    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。

/etc/systemd/system/etemenanki.service
[Unit]
Description=etemenanki-app proxy
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=etemenanki
Group=etemenanki
WorkingDirectory=/etc/etemenanki
Environment=NO_COLOR=1
ExecStartPre=/usr/local/bin/etemenanki-app --test -c /etc/etemenanki/config.toml
ExecStart=/usr/local/bin/etemenanki-app -c /etc/etemenanki/config.toml
Restart=on-failure
RestartSec=5s
LimitNOFILE=1048576
# 无需以 root 运行即可绑定 1024 以下的端口。
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
RestrictNamespaces=yes
LockPersonality=yes
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.target

然后加载并启动它:

终端窗口
sudo systemctl daemon-reload
sudo systemctl enable --now etemenanki
journalctl -u etemenanki -f

服务启动后,journal 中每个入站会有一行 inbound … listening on …。

设置 原因
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 会报错并且不做任何改变,这是有意为之:程序会在文件变化时自行重载。

  1. 把编辑好的文件放在正在使用的文件旁边,所有权和权限保持一致,这样文件就位后服务能够读取:

    终端窗口
    sudo install -o root -g etemenanki -m 0640 config.toml /etc/etemenanki/config.toml.new
  2. 以服务用户身份检查:

    终端窗口
    sudo -u etemenanki sh -c 'cd /etc/etemenanki && exec /usr/local/bin/etemenanki-app --test -c config.toml.new'
  3. 把它移到正式位置。 运行中的服务会察觉到变化,记录 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: …,并继续使用旧配置。不过下一次启动会失败。热重载介绍了重载会重建哪些内容,以及端口无法绑定时会发生什么。

一个 katana 进程可以服务多个节点:在一个文件中重复写 [[node]] 即可。当节点需要各自独立重启时,例如每个面板一个进程,使用单独的进程会更方便。systemd 模板单元可以为每个配置文件运行一个进程:

  • 文件夹/etc/katana/ owner root, group katana, mode 0750
    • xboard.toml mode 0640
    • sspanel.toml mode 0640
  • 文件夹/etc/systemd/system/
/etc/systemd/system/katana@.service
[Unit]
Description=katana node agent (%i)
After=network-online.target
Wants=network-online.target
[Service]
Type=exec
User=katana
Group=katana
WorkingDirectory=/etc/katana
Environment=NO_COLOR=1
ExecStartPre=/usr/local/bin/katana --test -c /etc/katana/%i.toml
ExecStart=/usr/local/bin/katana -c /etc/katana/%i.toml
Restart=on-failure
RestartSec=5s
LimitNOFILE=1048576
# 仅当面板为节点分配 1024 以下的端口时需要。
AmbientCapabilities=CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX AF_NETLINK
RestrictNamespaces=yes
LockPersonality=yes
SystemCallArchitectures=native
[Install]
WantedBy=multi-user.target

@ 后面的实例名决定使用哪个文件:katana@xboard 运行 /etc/katana/xboard.toml。

终端窗口
sudo useradd --system --no-create-home --shell /usr/sbin/nologin katana
sudo systemctl daemon-reload
sudo systemctl enable --now katana@xboard katana@sspanel
journalctl -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。

  1. 把新的二进制文件以不同的名字放在旧文件旁边:

    终端窗口
    sudo install -m 0755 etemenanki-app /usr/local/bin/etemenanki-app.new
    /usr/local/bin/etemenanki-app.new --version
  2. 用新的二进制文件检查正在使用的配置,以服务用户身份、在服务的工作目录下运行。新版本可能会拒绝旧版本接受的某个键,这一步就是用来发现这种情况的:

    终端窗口
    sudo -u etemenanki sh -c 'cd /etc/etemenanki && exec /usr/local/bin/etemenanki-app.new --test -c config.toml'

    如果它没有打印 Configuration OK.,就到此为止。运行中的服务不受影响。

  3. 保留当前的二进制文件,以便回滚:

    终端窗口
    sudo cp -p /usr/local/bin/etemenanki-app /usr/local/bin/etemenanki-app.prev
  4. 通过重命名替换文件,不要直接复制覆盖正在运行的文件:

    终端窗口
    sudo mv -f /usr/local/bin/etemenanki-app.new /usr/local/bin/etemenanki-app

    Linux 不允许以写方式打开正在运行的可执行文件,因此用 cp 覆盖它会失败并报错 Text file busy。重命名只替换目录项:运行中的进程继续使用旧文件,下次启动时使用新文件。

  5. 重启服务。 这会关闭所有已打开的连接;客户端会自行重连:

    终端窗口
    sudo systemctl restart etemenanki

    对于 katana 实例:sudo systemctl restart 'katana@*'。

  6. 确认服务正在运行,并且每个入站都已重新开始监听:

    终端窗口
    systemctl status etemenanki
    journalctl -u etemenanki -n 20

要回滚,把旧的二进制文件重命名回原位并重启:

终端窗口
sudo mv -f /usr/local/bin/etemenanki-app.prev /usr/local/bin/etemenanki-app
sudo 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 不生效 级别只在启动时读取。 重启服务。