跳转到内容

出站

出站(outbound)是节点接受用户流量之后,katana 把流量送往的地方。默认是 direct:katana 从自己所在的主机直接连接目标。通过 [[outbound]] 表可以添加具名的上游,例如 SOCKS5 或 HTTP 代理,VMess、VLESS 或 Shadowsocks 服务器,或者一个 WireGuard 对端。节点的路由规则再按连接或按 UDP 包从中选出一个。

本页介绍出站池、[[outbound]] 的每个配置项、各协议能承载哪些流量、一个完整的 WireGuard 出口示例,以及在让用户使用某个上游之前如何检查它。哪些流量走哪个出站由路由表决定,参见路由。

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 direct

tag 的比较区分大小写。Direct 不是保留 tag,会被当作一个新的出站接受;而写着 outbound = "Up" 的路由找不到 tag 为 up 的出站,会报 route references unknown outbound tag: Up。

下面的配置把一个域名的流量转发给上游 SOCKS5 代理,其余流量直连:

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.route.rule]]
outbound = "socks-up"
domain_suffix = ["example.com"]
[[outbound]]
tag = "socks-up"
protocol = "socks"
server = "192.0.2.20"
port = 1080
username = "katana"
password = "replace-with-a-long-random-password"

[[outbound]] 和 [[node]] 一样是顶层表。只要它从单独一行的表头开始,放在文件中的任何位置都可以。每次修改后都运行 katana --test -c config.toml。它会构建整个出站池和每个节点的路由表,所以错误的配置项、缺失的字段或未知的 tag 都会在这一步报错,不会进入正在运行的 katana。

每个 [[outbound]] 表都是严格解析的:未知的配置项(例如把 username 写成 user)会以 unknown field 报错,并列出可接受的配置项。所选协议用不到的配置项(例如 socks 出站上的 uuid)会被接受并忽略。

键类型必填默认值说明
tagstring是—供 [node.route].default 和 [[node.route.rule]].outbound 引用的名字。在所有 [[outbound]] 之间必须唯一,且不能是内置 tag direct、freedom、block、blackhole 之一;两种错误都会报 duplicate/reserved outbound tag <tag>。在所有引用处都区分大小写。
protocolstring (enum)是—要构建的客户端,不区分大小写:socks(别名 socks5)、http、vmess、vless、shadowsocks(别名 ss)、wireguard(别名 wg),或 direct(别名 freedom)。其他值报 unknown outbound protocol "<name>"(名字以小写显示)。这里没有 trojan、hysteria2 或 blackhole 协议;要丢弃流量,请使用内置的 block tag。
serverstring视情况—上游主机:IP 地址或域名。对 wireguard 来说是对端 UDP endpoint 的主机。除 direct(忽略此项)外,所有协议都必须填写。IPv6 地址不要加方括号。域名在建立连接时用 [dns] 解析器解析;wireguard 例外,它的 endpoint 域名在隧道启动时用系统解析器解析。为空时报 outbound needs a non-empty server and non-zero port。
portu16视情况—上游端口;对 wireguard 来说是对端的 UDP 端口。除 direct 外,所有协议都必须填写且不能为 0。为 0 或不写时报 outbound needs a non-empty server and non-zero port (got "<server>":0)。该检查在读取 protocol 之前进行,所以没有 server 或 port 且协议名拼错时也会报这个错误。
usernamestring否—仅用于 socks 和 http。SOCKS5 用户名/密码认证,或 HTTP Basic Proxy-Authorization。只有同时设置了 password 才生效;两者缺一时,客户端完全不做认证。
passwordstring视情况—对 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: …。
uuidstring视情况—vmess 和 vless 必填:上游服务器上的账户 UUID。缺少时报 outbound <tag> needs a uuid;格式错误时报 outbound <tag>: uuid is not a valid UUID,错误信息不会回显该值,因为它是凭据。
securitystring (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>"。
methodstring (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_paddingbool否false仅用于 vmess。开启 VMess 的 global padding 选项:每个数据块附带 0 到 63 字节的填充,以少量带宽为代价隐藏准确的载荷长度。
address_familystring (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_keystring视情况—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_keystring视情况—wireguard 必填:对端的公钥,即 [Peer] 段的 PublicKey。编码方式和错误形式与 private_key 相同。etemenanki-app 中这个键叫 peer_public_key。
pre_shared_keystring否—仅用于 wireguard。可选的预共享密钥,即 PresharedKey。编码方式与 private_key 相同;编码错误时报 wireguard outbound <tag> pre_shared_key: …。只有对端为你配置了预共享密钥时才填写。etemenanki-app 中写作 preshared_key。
local_addressarray 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>": …。
mtuinteger否1420仅用于 wireguard。隧道内 IP 包的最大字节数;用户态 TCP 协议栈据此确定分段大小。不做范围检查。如果小请求正常、大流量传输卡住,就把它调低(例如 1280)。
keepaliveu16否—仅用于 wireguard。持续保活(persistent keepalive)的间隔秒数,即 PersistentKeepalive。不写或写 0 表示关闭。本机位于 NAT 或有状态防火墙之后时应当设置(常用 25)。
reservedarray 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

如果节点的协议承载 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 tag 使用 address_family = "auto"。要让直连流量使用不同的地址族策略,可以用新的 tag 声明一个自己的 direct 出站,并把流量路由到它:

[[outbound]]
tag = "direct-v4"
protocol = "direct"
address_family = "ipv4_only"

direct 出站不需要 server 或 port,写了也会被忽略。对 TCP,katana 解析目标地址,并依次尝试每个允许的地址,直到有一个连接成功。对 UDP,它为每个允许的地址族绑定一个 socket,每个关联对每个域名目标只解析一次,并发往第一个允许的地址;没有可用地址的域名,发往它的包会被丢弃。

socks 使用 SOCKS5,http 使用 HTTP CONNECT。只有同时设置了 username 和 password 才会认证:SOCKS5 用户名/密码认证,或 HTTP Basic Proxy-Authorization 头。只设置其中一个时,katana 不带凭据连接,是否接受由上游决定。

两者都需要上游服务器上的账户 uuid。VMess 使用 AEAD 头部格式,由 security 选择正文加密方式;auto 即 AES-128-GCM,不存在不加密的模式。VLESS 发送空的 flow,所以如果 Xray 上游的账户要求 xtls-rprx-vision,它会拒绝这些 TCP 连接。

method 名称决定 katana 使用哪一代协议,password 的含义也随之改变:

[[outbound]]
tag = "ss-up"
protocol = "shadowsocks"
server = "198.51.100.30"
port = 8388
method = "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 加密方式定义了身份密钥,所以只在这两种方式下使用密钥链。

2022 加密方式的名称必须一字不差地用小写书写:2022-BLAKE3-AES-128-GCM 会报 unsupported shadowsocks cipher。经典加密方式的名称不区分大小写。不支持 rc4-md5 之类的流加密方式。

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 对端发出,屏蔽一个域名,其余流量直连。被路由到 wg-egress 的目标看到的是对端的地址,而不是节点的地址。

config.toml
# 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 = 1
key = "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 = 51820
private_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
public_key = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
local_address = ["10.8.0.2/32", "2001:db8:a::2/128"]
address_family = "prefer_ipv4"
mtu = 1420
keepalive = 25

文件中的密钥是占位值。用 wg genkey | tee private.key | wg pubkey 生成真实的密钥对,并把公钥登记到对端;或者直接使用 WireGuard 服务提供给你的密钥。

WireGuard 服务通常提供 wg-quick 文件。下面两个标签页描述的是同一条隧道:

[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
Address = 10.8.0.2/32, 2001:db8:a::2/128
DNS = 192.0.2.53
MTU = 1280
[Peer]
PublicKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
PresharedKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = 203.0.113.10:51820
PersistentKeepalive = 25

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。两个程序都会拒绝错误的写法,而不是忽略它。

katana --test 只能证明出站可以构建。它无法告诉你上游是否接受你的凭据、是否转发你的流量;而且 WireGuard 密钥错误的表现和对端不可达完全一样:连接超时。在把用户路由到新上游之前,先在同一台主机上用一个临时的 etemenanki-app 跑一遍。它与正在运行的 katana 互不相干:独立的进程、独立的配置文件、回环端口。

  1. 把出站改写成 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 = 1420
    keepalive = 25

    etemenanki-app 把未匹配的流量发往第一个出站,所以只有一个出站时,所有流量都经过它。对于 SOCKS、HTTP、VMess、VLESS 或 Shadowsocks 上游,请改用出站中对应的 etemenanki-app 出站,且不要配置 TLS、WebSocket 或 gRPC 传输层,因为 katana 通过明文 TCP 连接上游。

  2. 用 etemenanki-app --test -c wg-check.toml 检查文件,然后用 etemenanki-app -c wg-check.toml 在前台启动。

  3. 在另一个终端中,询问 IP 回显服务看到的是哪个地址:

    终端窗口
    curl -m 30 --socks5-hostname 127.0.0.1:10808 https://ifconfig.me

    返回的应当是上游的出口地址,而不是本机地址。如果经过新 WireGuard 隧道的第一个请求超时,先再试一次再下结论:第一条连接要等待握手完成。

  4. 按 Ctrl-C 停止 etemenanki-app,把同样的值按 katana 的配置项名称填进 katana 的 [[outbound]],然后运行 katana --test。

katana 会监视自己的配置文件。保存对任意 [[outbound]] 表的修改时:

  1. katana 先构建整个新出站池。只要有一个出站构建失败,它就记录 reload: bad outbounds, keeping current config: …,并且这次编辑中的任何修改都不生效,包括节点和日志的修改。正在运行的出站池继续工作。
  2. 在改动任何正在运行的节点之前,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: …。
  3. 如果全部构建成功,每个节点都会基于新出站池重新编译路由表并重建监听器。这会断开所有节点上的所有现有连接,每条 WireGuard 隧道也会以新的握手重新开始。仍在重试首次启动的节点还没有监听器:它会基于新出站池重新编译路由,并在下一次尝试时使用。
  4. 如果编辑后某个节点的路由仍然引用新出站池中已不存在的 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。