出站
出站(outbound)是节点接受用户流量之后,katana 把流量送往的地方。默认是 direct:katana 从自己所在的主机直接连接目标。通过 [[outbound]] 表可以添加具名的上游,例如 SOCKS5 或 HTTP 代理,VMess、VLESS 或 Shadowsocks 服务器,或者一个 WireGuard 对端。节点的路由规则再按连接或按 UDP 包从中选出一个。
本页介绍出站池、[[outbound]] 的每个配置项、各协议能承载哪些流量、一个完整的 WireGuard 出口示例,以及在让用户使用某个上游之前如何检查它。哪些流量走哪个出站由路由表决定,参见路由。
所有节点共用一个出站池
Section titled “所有节点共用一个出站池”katana 为整个进程构建一个出站池。所有 [[node]] 共享它,每个节点的 [node.route] 通过 tag 引用出站。被多个节点使用的出站是同一个对象:例如一个 WireGuard 出站就是一条隧道,承载所有路由到它的节点和用户的流量。
flowchart LR A["节点 1 路由"] --> P B["节点 2 路由"] --> P P["出站池"] --> D["direct / freedom"] P --> K["block / blackhole"] P --> S["socks-up"] P --> W["wg-egress"] D --> I["目标地址"] S --> U["上游代理"] W --> R["WireGuard 对端"]
无论是否声明了 [[outbound]],出站池中始终包含四个内置 tag:
| Tag | 别名 | 作用 |
|---|---|---|
direct |
freedom |
从本机直接连接目标,使用 address_family = "auto"。它也是路由的默认出站:没有设置 [node.route].default 的节点会把未匹配的流量发到这里。 |
block |
blackhole |
拒绝 TCP 连接,丢弃 UDP 包。被丢弃的包不计入用户流量。 |
这些 tag 不能重新定义。声明 tag = "direct" 的 [[outbound]] 会导致构建失败,重复声明同一个 tag 也一样:
configuration error: duplicate/reserved outbound tag directtag 的比较区分大小写。Direct 不是保留 tag,会被当作一个新的出站接受;而写着 outbound = "Up" 的路由找不到 tag 为 up 的出站,会报 route references unknown outbound tag: Up。
下面的配置把一个域名的流量转发给上游 SOCKS5 代理,其余流量直连:
[[node]]panel_type = "NewV2board"
[node.api]host = "https://panel.example.com"node_id = 1key = "replace-with-the-panel-key"node_type = "V2ray"
[[node.route.rule]]outbound = "socks-up"domain_suffix = ["example.com"]
[[outbound]]tag = "socks-up"protocol = "socks"server = "192.0.2.20"port = 1080username = "katana"password = "replace-with-a-long-random-password"[[outbound]] 和 [[node]] 一样是顶层表。只要它从单独一行的表头开始,放在文件中的任何位置都可以。每次修改后都运行 katana --test -c config.toml。它会构建整个出站池和每个节点的路由表,所以错误的配置项、缺失的字段或未知的 tag 都会在这一步报错,不会进入正在运行的 katana。
每个 [[outbound]] 表都是严格解析的:未知的配置项(例如把 username 写成 user)会以 unknown field 报错,并列出可接受的配置项。所选协议用不到的配置项(例如 socks 出站上的 uuid)会被接受并忽略。
| 键 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
tag | string | 是 | — | 供 [node.route].default 和 [[node.route.rule]].outbound 引用的名字。在所有 [[outbound]] 之间必须唯一,且不能是内置 tag direct、freedom、block、blackhole 之一;两种错误都会报 duplicate/reserved outbound tag <tag>。在所有引用处都区分大小写。 |
protocol | string (enum) | 是 | — | 要构建的客户端,不区分大小写:socks(别名 socks5)、http、vmess、vless、shadowsocks(别名 ss)、wireguard(别名 wg),或 direct(别名 freedom)。其他值报 unknown outbound protocol "<name>"(名字以小写显示)。这里没有 trojan、hysteria2 或 blackhole 协议;要丢弃流量,请使用内置的 block tag。 |
server | string | 视情况 | — | 上游主机:IP 地址或域名。对 wireguard 来说是对端 UDP endpoint 的主机。除 direct(忽略此项)外,所有协议都必须填写。IPv6 地址不要加方括号。域名在建立连接时用 [dns] 解析器解析;wireguard 例外,它的 endpoint 域名在隧道启动时用系统解析器解析。为空时报 outbound needs a non-empty server and non-zero port。 |
port | u16 | 视情况 | — | 上游端口;对 wireguard 来说是对端的 UDP 端口。除 direct 外,所有协议都必须填写且不能为 0。为 0 或不写时报 outbound needs a non-empty server and non-zero port (got "<server>":0)。该检查在读取 protocol 之前进行,所以没有 server 或 port 且协议名拼错时也会报这个错误。 |
username | string | 否 | — | 仅用于 socks 和 http。SOCKS5 用户名/密码认证,或 HTTP Basic Proxy-Authorization。只有同时设置了 password 才生效;两者缺一时,客户端完全不做认证。 |
password | string | 视情况 | — | 对 socks 和 http,是与 username 配套的密码。对 shadowsocks 为必填,存放密钥:经典加密方式下是密码,2022- 加密方式下是 base64 编码的 PSK,也可以写成 iPSK:uPSK 链。shadowsocks 缺少此项时报 shadowsocks outbound <tag> needs a password。2022 密钥短于该加密方式的密钥长度时报 shadowsocks-2022: PSK too short (…),base64 无效时报 decode PSK: …。 |
uuid | string | 视情况 | — | vmess 和 vless 必填:上游服务器上的账户 UUID。缺少时报 outbound <tag> needs a uuid;格式错误时报 outbound <tag>: uuid is not a valid UUID,错误信息不会回显该值,因为它是凭据。 |
security | string (enum) | 否 | "auto" | 仅用于 vmess。正文加密方式,不区分大小写:auto、aes-128-gcm 或 aes128gcm 表示 AES-128-GCM;chacha20-poly1305 或 chacha20poly1305 表示 ChaCha20-Poly1305。auto 始终等于 AES-128-GCM。none、zero 及其他值报 unsupported vmess security "<name>"。 |
method | string (enum) | 视情况 | — | shadowsocks 必填;名字决定使用哪一代协议。SIP022:2022-blake3-aes-128-gcm、2022-blake3-aes-256-gcm、2022-blake3-chacha20-poly1305,必须全部小写、一字不差。经典 AEAD,不区分大小写:aes-128-gcm、aes-256-gcm、chacha20-poly1305(或 chacha20-ietf-poly1305)、xchacha20-poly1305(或 xchacha20-ietf-poly1305),以及别名 aead_aes_128_gcm、aead_aes_256_gcm、aead_chacha20_poly1305。其他值(包括空值或不写)报 unsupported shadowsocks cipher "<name>"。 |
global_padding | bool | 否 | false | 仅用于 vmess。开启 VMess 的 global padding 选项:每个数据块附带 0 到 63 字节的填充,以少量带宽为代价隐藏准确的载荷长度。 |
address_family | string (enum) | 否 | "auto" | 出站可以使用哪些解析得到的地址,适用于所有协议:auto(保持解析器给出的顺序)、ipv4_only、ipv6_only、prefer_ipv4、prefer_ipv6。不区分大小写,忽略首尾空格,- 视为 _,空字符串等于 auto,并接受以下别名:ipv4、v4、4、ipv4only;ipv6、v6、6、ipv6only;prefer_v4、ipv4_prefer、v4_prefer;prefer_v6、ipv6_prefer、v6_prefer。对 direct 和 wireguard 作用于目标地址,对其他协议作用于 server 解析出的地址。其他值报 outbound <tag> invalid address_family "<value>"。 |
private_key | string | 视情况 | — | wireguard 必填:本端的 Curve25519 私钥,即 wg-quick 文件中的 PrivateKey。32 字节,写成带填充的标准 base64(wg genkey 的输出)或 64 位十六进制。缺少时报 wireguard outbound <tag> needs a private_key;编码错误时报 wireguard outbound <tag> private_key: invalid WireGuard key: expected base64 or hex encoding of 32 bytes。 |
public_key | string | 视情况 | — | wireguard 必填:对端的公钥,即 [Peer] 段的 PublicKey。编码方式和错误形式与 private_key 相同。etemenanki-app 中这个键叫 peer_public_key。 |
pre_shared_key | string | 否 | — | 仅用于 wireguard。可选的预共享密钥,即 PresharedKey。编码方式与 private_key 相同;编码错误时报 wireguard outbound <tag> pre_shared_key: …。只有对端为你配置了预共享密钥时才填写。etemenanki-app 中写作 preshared_key。 |
local_address | array of strings | 视情况 | — | wireguard 必填,至少一项:Address 行中的隧道内地址,例如 ["10.8.0.2/32", "2001:db8:a::2/128"]。从 / 开始的部分会被丢弃,所以前缀长度可写可不写。没有 IPv6 地址时隧道无法访问 IPv6 目标,反之亦然。错误信息:wireguard outbound <tag> needs at least one local_address、wireguard outbound <tag> invalid local_address "<value>": …。 |
mtu | integer | 否 | 1420 | 仅用于 wireguard。隧道内 IP 包的最大字节数;用户态 TCP 协议栈据此确定分段大小。不做范围检查。如果小请求正常、大流量传输卡住,就把它调低(例如 1280)。 |
keepalive | u16 | 否 | — | 仅用于 wireguard。持续保活(persistent keepalive)的间隔秒数,即 PersistentKeepalive。不写或写 0 表示关闭。本机位于 NAT 或有状态防火墙之后时应当设置(常用 25)。 |
reserved | array of integers | 否 | — | 仅用于 wireguard。恰好三个字节,每个取值 0 到 255,写入每个发出的 WireGuard 包头的第 1 到 3 字节,与 Xray 的 reserved 相同。只有服务方要求时才设置。长度不是 3 时报 wireguard outbound <tag> reserved must be exactly 3 bytes;大于 255 的值会导致解析失败。 |
各协议读取的配置项:
protocol |
必填 | 可选 |
|---|---|---|
direct、freedom |
无 | address_family |
socks、socks5 |
server、port |
username 和 password、address_family |
http |
server、port |
username 和 password、address_family |
vmess |
server、port、uuid |
security、global_padding、address_family |
vless |
server、port、uuid |
address_family |
shadowsocks、ss |
server、port、method、password |
address_family |
wireguard、wg |
server、port、private_key、public_key、local_address |
pre_shared_key、mtu、keepalive、reserved、address_family |
各协议承载的流量
Section titled “各协议承载的流量”如果节点的协议承载 UDP,节点会同时中继 TCP 和 UDP。katana 对每个 UDP 包单独做路由,所以同一个客户端的 UDP 流量可能到达多个出站。并非每种出站都能承载 UDP:
| 出站 | TCP | UDP |
|---|---|---|
direct |
支持 | 支持。每个地址族一个 socket,每个包发往各自的目标。 |
block |
拒绝 | 丢弃 |
socks |
支持 | 支持,通过 SOCKS5 UDP ASSOCIATE。每个包携带各自的目标地址。 |
http |
支持,通过 CONNECT |
不支持 |
vmess、vless |
支持 | 支持,但每个客户端关联只有一个固定目标(见下文)。 |
shadowsocks(两代都是) |
支持 | 不支持 |
wireguard |
支持 | 支持。每个包携带各自的目标地址。 |
UDP 包被路由到不承载 UDP 的出站时,katana 会丢弃它。客户端看不到任何错误,只是收不到回应,所以不要把 DNS 或 QUIC 路由到 http 或 shadowsocks 出站。
direct
Section titled “direct”内置的 direct tag 使用 address_family = "auto"。要让直连流量使用不同的地址族策略,可以用新的 tag 声明一个自己的 direct 出站,并把流量路由到它:
[[outbound]]tag = "direct-v4"protocol = "direct"address_family = "ipv4_only"direct 出站不需要 server 或 port,写了也会被忽略。对 TCP,katana 解析目标地址,并依次尝试每个允许的地址,直到有一个连接成功。对 UDP,它为每个允许的地址族绑定一个 socket,每个关联对每个域名目标只解析一次,并发往第一个允许的地址;没有可用地址的域名,发往它的包会被丢弃。
socks 和 http
Section titled “socks 和 http”socks 使用 SOCKS5,http 使用 HTTP CONNECT。只有同时设置了 username 和 password 才会认证:SOCKS5 用户名/密码认证,或 HTTP Basic Proxy-Authorization 头。只设置其中一个时,katana 不带凭据连接,是否接受由上游决定。
vmess 和 vless
Section titled “vmess 和 vless”两者都需要上游服务器上的账户 uuid。VMess 使用 AEAD 头部格式,由 security 选择正文加密方式;auto 即 AES-128-GCM,不存在不加密的模式。VLESS 发送空的 flow,所以如果 Xray 上游的账户要求 xtls-rprx-vision,它会拒绝这些 TCP 连接。
shadowsocks
Section titled “shadowsocks”method 名称决定 katana 使用哪一代协议,password 的含义也随之改变:
[[outbound]]tag = "ss-up"protocol = "shadowsocks"server = "198.51.100.30"port = 8388method = "2022-blake3-aes-256-gcm"password = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="password 是 base64 编码的密钥,长度不能短于该加密方式的密钥长度:2022-blake3-aes-128-gcm 为 16 字节,另外两种为 32 字节。可以用 openssl rand -base64 32(或 -base64 16)生成。密钥过短会报 shadowsocks-2022: PSK too short (16 < 32),base64 无效会报 decode PSK: …。
对于多用户服务器,把身份密钥和你的用户密钥用冒号隔开,写成 iPSK:uPSK。最后一个密钥始终是你自己的,前面的密钥组成身份链。每一段都单独解码并检查长度。多用户扩展(SIP023)只为两种 AES 加密方式定义了身份密钥,所以只在这两种方式下使用密钥链。
[[outbound]]tag = "ss-up"protocol = "shadowsocks"server = "198.51.100.30"port = 8388method = "chacha20-ietf-poly1305"password = "replace-with-a-long-random-password"password 是普通密码;katana 从中派生密钥的方式与其他 Shadowsocks 实现相同。
2022 加密方式的名称必须一字不差地用小写书写:2022-BLAKE3-AES-128-GCM 会报 unsupported shadowsocks cipher。经典加密方式的名称不区分大小写。不支持 rc4-md5 之类的流加密方式。
wireguard
Section titled “wireguard”wireguard 出站在 katana 内部运行一条用户态 WireGuard 隧道:不需要网络接口,不需要主机路由,也不需要 root。server 和 port 是对端的 UDP endpoint。它承载 TCP 和 UDP。本节其余部分说明它与其他出站的不同之处;下面的 WireGuard 出口示例给出了一个完整的节点。
- 延迟启动。 构建配置时不会打开任何东西,所以
--test只检查密钥编码,从不联系对端。第一个路由到该出站的流会解析 endpoint、绑定 UDP socket 并启动隧道,这第一条连接要等待握手完成。 - endpoint 解析。
server中的域名在每次隧道启动时用主机的系统解析器(而不是[dns])解析一次,并使用第一个结果。 - 目标地址解析。 经过隧道的流以域名指定目标时,katana 在本机用自己的
[dns]解析器解析该域名,再经隧道连接到解析出的 IP。查询本身不经过隧道。 - 地址族。 隧道只能访问有对应
local_address的地址族。使用address_family = "ipv4_only"时需要一个 IPv4 的local_address,使用ipv6_only时需要一个 IPv6 的,否则构建失败,报wireguard outbound <tag> address_family ipv6_only needs an IPv6 local_address。连接没有可用地址的目标时报wireguard: no usable <policy> destination address for …,后面列出隧道支持的地址族。 - 单个目标停滞。 隧道中的每个流都有自己的有界缓冲区。某个目标停止读取时,只有该流的缓冲区会被填满,然后只有该流的发送方等待,于是在目标恢复读取之前,katana 不再从客户端读取该流的上传数据。共用这条隧道的其他流、用户和节点照常传输。同样,隧道或对端变慢时会对发送方形成背压,发送方随之放慢到隧道能接受的速度。如果一个 UDP 数据报大于其所属关联的发送缓冲区,或者隧道无法寻址它的目标,这个数据报会被丢弃,该关联的其余数据照常传输。
- 恢复。 如果隧道的驱动停止(例如 UDP socket 报错),下一个流会构建新的隧道并重新解析 endpoint。已经运行了至少 10 秒的隧道会立即重建。如果隧道在此之前就断了,或启动失败(例如 endpoint 域名无法解析),katana 会先等待 2 秒再尝试,之后每次加倍,最长 30 秒;其间到达的流会报
wireguard: tunnel is down, waiting before the next attempt。
address_family 对所有协议都有效,但它过滤的是哪些地址,取决于由谁来解析什么:
| 出站 | address_family 作用于 |
|---|---|
direct |
目标解析出的地址。 |
socks、http、vmess、vless、shadowsocks |
server 解析出的地址。目标地址由上游自行解析。 |
wireguard |
目标解析出的地址,并进一步限定在 local_address 所属的地址族内。server 中的 endpoint 不受影响。 |
| 值 | 效果 |
|---|---|
auto |
保持解析器给出的顺序。TCP 依次尝试每个地址;UDP 使用第一个可用地址。 |
ipv4_only、ipv6_only |
只使用该地址族。 |
prefer_ipv4、prefer_ipv6 |
优先尝试该地址族,另一地址族作为后备。 |
WireGuard 出口示例
Section titled “WireGuard 出口示例”这个节点把两个域名和一个网段经 WireGuard 对端发出,屏蔽一个域名,其余流量直连。被路由到 wg-egress 的目标看到的是对端的地址,而不是节点的地址。
# katana: one newV2board node whose route sends selected traffic out through# a WireGuard tunnel, blocks one domain, and relays everything else directly.# Keys are placeholders: generate your own with `wg genkey | tee private.key | wg pubkey`.
[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"
[node.route]default = "direct"
# First match wins. Traffic for these domains and this network leaves# through the tunnel, so the destination sees the WireGuard peer's address.[[node.route.rule]]outbound = "wg-egress"domain_suffix = ["example.com", "example.org"]cidr = ["198.51.100.0/24"]
[[node.route.rule]]outbound = "block"domain_suffix = ["ads.example.net"]
# The tunnel. `server` and `port` are the peer's UDP endpoint# (wg-quick's `Endpoint`); `public_key` is the peer's key.[[outbound]]tag = "wg-egress"protocol = "wireguard"server = "203.0.113.10"port = 51820private_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="public_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="local_address = ["10.8.0.2/32", "2001:db8:a::2/128"]address_family = "prefer_ipv4"mtu = 1420keepalive = 25文件中的密钥是占位值。用 wg genkey | tee private.key | wg pubkey 生成真实的密钥对,并把公钥登记到对端;或者直接使用 WireGuard 服务提供给你的密钥。
从 wg-quick 文件转换
Section titled “从 wg-quick 文件转换”WireGuard 服务通常提供 wg-quick 文件。下面两个标签页描述的是同一条隧道:
[Interface]PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=Address = 10.8.0.2/32, 2001:db8:a::2/128DNS = 192.0.2.53MTU = 1280
[Peer]PublicKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=PresharedKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=AllowedIPs = 0.0.0.0/0, ::/0Endpoint = 203.0.113.10:51820PersistentKeepalive = 25[[outbound]]tag = "wg-egress"protocol = "wireguard"server = "203.0.113.10"port = 51820private_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="public_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="pre_shared_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="local_address = ["10.8.0.2/32", "2001:db8:a::2/128"]mtu = 1280keepalive = 25# AllowedIPs:改用 [[node.route.rule]]。# DNS:改用 [dns]。etemenanki-app 用名称不同的配置项构建同样的隧道,这些配置项嵌套在 [outbound.settings] 下。如下一节所述,先用 etemenanki-app 测试上游时,最后一列就很重要:
| wg-quick | katana [[outbound]] |
etemenanki-app [outbound.settings] |
|---|---|---|
[Interface] PrivateKey |
private_key |
private_key |
[Interface] Address |
local_address,可带前缀:["10.8.0.2/32"] |
address,只能是纯 IP:["10.8.0.2"] |
[Interface] MTU |
mtu |
mtu |
[Peer] PublicKey |
public_key |
peer_public_key |
[Peer] PresharedKey |
pre_shared_key |
preshared_key |
[Peer] Endpoint |
server 和 port,分开写 |
endpoint = "203.0.113.10:51820" |
[Peer] PersistentKeepalive |
keepalive |
keepalive |
[Peer] AllowedIPs |
无:由路由规则决定哪些流量进入隧道 | 无 |
[Interface] DNS |
无:由 [dns] 在主机上解析域名 |
无 |
| 无 | reserved |
reserved |
把带前缀的 Address 抄进 etemenanki-app 会报 invalid IP address syntax,在 katana 出站中写 peer_public_key 会报 unknown field。两个程序都会拒绝错误的写法,而不是忽略它。
使用上游之前先测试
Section titled “使用上游之前先测试”katana --test 只能证明出站可以构建。它无法告诉你上游是否接受你的凭据、是否转发你的流量;而且 WireGuard 密钥错误的表现和对端不可达完全一样:连接超时。在把用户路由到新上游之前,先在同一台主机上用一个临时的 etemenanki-app 跑一遍。它与正在运行的 katana 互不相干:独立的进程、独立的配置文件、回环端口。
-
把出站改写成 etemenanki-app 的格式,并给它配一个回环地址上的 SOCKS 入站。以上面的 WireGuard 出站为例:
wg-check.toml # 临时检查:通过回环 SOCKS 代理测试一个 WireGuard 上游。[[inbound]]tag = "check"protocol = "socks"listen = "127.0.0.1"port = 10808[[outbound]]tag = "wg-check"protocol = "wireguard"address_family = "prefer_ipv4"[outbound.settings]private_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="peer_public_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="endpoint = "203.0.113.10:51820"address = ["10.8.0.2", "2001:db8:a::2"]mtu = 1420keepalive = 25etemenanki-app 把未匹配的流量发往第一个出站,所以只有一个出站时,所有流量都经过它。对于 SOCKS、HTTP、VMess、VLESS 或 Shadowsocks 上游,请改用出站中对应的 etemenanki-app 出站,且不要配置 TLS、WebSocket 或 gRPC 传输层,因为 katana 通过明文 TCP 连接上游。
-
用
etemenanki-app --test -c wg-check.toml检查文件,然后用etemenanki-app -c wg-check.toml在前台启动。 -
在另一个终端中,询问 IP 回显服务看到的是哪个地址:
终端窗口 curl -m 30 --socks5-hostname 127.0.0.1:10808 https://ifconfig.me返回的应当是上游的出口地址,而不是本机地址。如果经过新 WireGuard 隧道的第一个请求超时,先再试一次再下结论:第一条连接要等待握手完成。
-
按 Ctrl-C 停止 etemenanki-app,把同样的值按 katana 的配置项名称填进 katana 的
[[outbound]],然后运行katana --test。
修改运行中节点的出站
Section titled “修改运行中节点的出站”katana 会监视自己的配置文件。保存对任意 [[outbound]] 表的修改时:
- katana 先构建整个新出站池。只要有一个出站构建失败,它就记录
reload: bad outbounds, keeping current config: …,并且这次编辑中的任何修改都不生效,包括节点和日志的修改。正在运行的出站池继续工作。 - 在改动任何正在运行的节点之前,katana 会基于新出站池构建这次编辑新增的每个节点(包括面板客户端和路由表),以及每个设置有变化的节点的面板客户端。只要其中一个失败,它就记录
reload: node <node>: <error>; keeping current config,同样不应用这次编辑中的任何修改。<node>由面板类型、主机、节点 ID 组成,在 NewV2board 和 V2board 上还包括节点类型,例如newv2board@https://panel.example.com#1/v2ray。因此,如果新增节点的路由引用了新出站池中没有的 tag,整个编辑都会被拒绝,错误为build router: route references unknown outbound tag: …。 - 如果全部构建成功,每个节点都会基于新出站池重新编译路由表并重建监听器。这会断开所有节点上的所有现有连接,每条 WireGuard 隧道也会以新的握手重新开始。仍在重试首次启动的节点还没有监听器:它会基于新出站池重新编译路由,并在下一次尝试时使用。
- 如果编辑后某个节点的路由仍然引用新出站池中已不存在的 tag,该节点会记录
node <id>: route rebuild failed, keeping current: …,并继续使用之前的路由表,而这张表仍指向旧的出站。katana --test会把同样的错误报告为route references unknown outbound tag。
[dns] 解析器与出站池一起构建,所以单独修改 [dns] 要等到下一次出站修改或重启时才生效。重载的全部行为参见热重载。
启动时,如果出站池构建失败,katana 会报 failed to build outbounds: … 并以状态码 1 退出。
| 错误 | 原因和解决方法 |
|---|---|
duplicate/reserved outbound tag <tag> |
tag 是 direct、freedom、block 或 blackhole,或者有两个 [[outbound]] 表使用了同一个 tag。重命名其中一个。 |
route references unknown outbound tag: <tag> |
某条路由规则或 default 引用了出站池中不存在的 tag。检查拼写和大小写。 |
unknown outbound protocol "<name>" |
protocol 不是配置项表中列出的值之一。名称以小写显示。不支持 Trojan 和 Hysteria 2 上游。 |
outbound needs a non-empty server and non-zero port (got …) |
需要上游的协议缺少 server 或 port。katana 在查看 protocol 之前做这项检查,所以协议名拼错且没有 server 和 port 时也会在这里报错。 |
outbound <tag> needs a uuid |
vmess 或 vless 出站没有 uuid。 |
outbound <tag>: uuid is not a valid UUID |
uuid 格式错误。错误信息有意不包含该值。 |
unsupported vmess security "<name>" |
使用 auto、aes-128-gcm 或 chacha20-poly1305。 |
shadowsocks outbound <tag> needs a password |
添加 password。 |
unsupported shadowsocks cipher "<name>" |
method 缺失、拼错,或 2022 名称的大小写不对。 |
shadowsocks-2022: PSK too short (16 < 32) |
密钥解码后的字节数少于该加密方式的要求。用 openssl rand -base64 32 生成一个。 |
outbound <tag> invalid address_family "<value>" |
使用地址族中列出的值之一。 |
wireguard outbound <tag> needs a private_key(或 public_key) |
添加缺少的密钥。 |
wireguard outbound <tag> private_key: invalid WireGuard key: … |
密钥不是带填充 base64 或十六进制编码的 32 字节。重新复制一遍,包括末尾的 =。 |
wireguard outbound <tag> needs at least one local_address |
从 wg-quick 文件中复制 Address 行。 |
wireguard outbound <tag> reserved must be exactly 3 bytes |
写三个数字,例如 reserved = [1, 2, 3],或者删除这个配置项。 |
unknown field …, expected one of … |
配置项拼错,或者使用了 etemenanki-app 的配置项名称,例如 peer_public_key 或 endpoint。 |