Skip to content

Protocols and transports

Every katana node runs one listener, and two things decide what it speaks. node_type in [node.api] picks the protocol family. The panel’s answer to katana’s node-info request fills in the rest: the port, the transport, whether TLS is on, and the protocol details such as the Shadowsocks cipher. katana then builds the listener from that answer, or refuses to build it when the answer asks for something it does not implement.

Read this page when you set up a node in the panel and want to know which settings katana will honour, or when a node does not start and the log says node requests kernel-unsupported feature. The panel pages (Xboard and V2board, SSPanel) cover the panel API itself.

node_type Protocol Transports TLS UDP relay Multiplexing Panels
V2ray VMess, AEAD only (alter_id 0) TCP, WebSocket, gRPC Optional Yes mux.cool and XUDP UniProxy, SSPanel
V2ray with enable_vless = true VLESS, no flow TCP, WebSocket, gRPC Optional Yes mux.cool and XUDP UniProxy, SSPanel
Trojan Trojan, password = the user’s UUID UniProxy: TCP. SSPanel: TCP, WebSocket, gRPC Always Yes mux.cool and XUDP UniProxy, SSPanel
Shadowsocks AEAD (SIP004) or 2022 multi-user (SIP022) TCP Never No No UniProxy only
Hysteria2 Hysteria 2 QUIC over UDP Always, inside QUIC When [node.hysteria].udp = true Not applicable UniProxy, SSPanel (custom_config), or local settings

“UniProxy” means the newV2board API that Xboard and V2board serve (panel_type = "NewV2board", or its alias "V2board"). Hysteria 2 has its own page, Hysteria 2 nodes; the rest of this page is about the four stream protocols.

katana checks everything that can fail before it binds the port, so a refused node never half-starts:

flowchart TB
  P["Panel node info"] --> N["Parse for the node type"]
  N -->|"Shadowsocks obfs, SSPanel Shadowsocks"| E1["node_info failed"]
  N --> T["Build the transport: TCP, WebSocket, gRPC, TLS"]
  T -->|"REALITY, ACME, missing certificate, unknown transport"| E2["initial start failed"]
  T --> R["Build the protocol user table"]
  R -->|"XTLS flow, unknown cipher"| E2
  R --> B["Bind the TCP port and serve"]

The certificate is read in the transport step, so a TLS node with a missing certificate is refused before its protocol settings are looked at.

node_type is set in katana’s config file, not in the panel. The value is case-insensitive:

You write Node type Notes
V2ray, vmess, vless V2ray Serves VMess, or VLESS when enable_vless = true.
Trojan Trojan
Shadowsocks Shadowsocks UniProxy panels only.
Hysteria2, hysteria, hy2 Hysteria 2 See Hysteria 2 nodes. katana sends hy2 to a UniProxy panel as written, and Xboard does not accept that type, so write Hysteria2 there.

Any other value, including an empty one, is refused. katana --test prints:

configuration error: unknown node_type "Socks"

At startup katana logs node 1: unknown node_type "Socks" and skips that node. The other nodes still start.

A hot reload of a file that contains such a node is refused as a whole: katana applies none of the new file and every node keeps running as it was. The log names the node by its panel, host, ID and, on a UniProxy panel, the type it is asked for:

reload: node newv2board@https://panel.example.com#1/socks: unknown node_type "Socks"; keeping current config

The same applies while a node that was skipped at startup is still in the file: no edit to the file takes effect until you correct that node’s node_type.

A VLESS node on a UniProxy panel looks like this:

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"
enable_vless = true
[node.controller.cert]
mode = "file"
cert_file = "/etc/katana/fullchain.pem"
key_file = "/etc/katana/privkey.pem"

On a UniProxy panel the node type is also part of every request: katana sends node_type=vless for a V2ray node with enable_vless = true, and the lowercased node_type otherwise. Xboard finds a node by its ID and this type, so the same node_id asked as vless and as v2ray names two different panel nodes. An edit that changes the type katana asks for, such as turning on enable_vless for a V2ray node, therefore restarts the node on a hot reload, with empty traffic counters; see Node identity and reload.

The panel’s network value picks the transport. katana lowercases it before matching:

Panel network Transport Behaviour
empty, tcp, raw TCP The protocol runs directly on the TCP connection, or on TLS over it.
ws, websocket WebSocket Accepts the upgrade only on the configured path. An empty path means /; a path without a leading / gets one, and an ?ed= query is stripped because it configures early data, which katana accepts through Sec-WebSocket-Protocol (up to 16 KiB; more is answered with HTTP 413). When the panel gives a host, the request’s Host header must match it (case-insensitive, port ignored). A wrong path or host is answered with HTTP 404.
grpc, gun gRPC Serves the gun tunnel on /<serviceName>/Tun and the multi-hunk tunnel on /<serviceName>/TunMulti, with the service name used exactly as the panel gives it. A stream on any other path is reset. Each HTTP/2 stream is one proxied connection, so one TCP connection can carry many.
httpupgrade Refused node requests kernel-unsupported feature: httpupgrade transport
splithttp, xhttp Refused node requests kernel-unsupported feature: splithttp transport
anything else Refused node requests kernel-unsupported feature: transport "quic", naming the value

Only V2ray nodes and SSPanel Trojan nodes read network. A UniProxy Trojan node is always TCP, and a Shadowsocks node is always TCP.

Whether a node uses TLS depends on its type and, for V2ray, on the panel:

Node type TLS
V2ray On when the panel says so: UniProxy tls = 1, SSPanel security = "tls" or "xtls", or tls in the SSPanel legacy string.
Trojan Always, whatever the panel says.
Shadowsocks Never.
Hysteria 2 Always; the TLS handshake is part of QUIC.

The certificate never comes from the panel. katana reads it from [node.controller.cert], and the panel’s tls_settings, server_name and similar fields are not used:

KeyTypeRequiredDefaultDescription
modestring (enum)depends"none""none" (no certificate) or "file" (read cert_file and key_file). Case-sensitive. "file" is required for every node that uses TLS; without it a stream node fails with TLS node requires cert.mode = "file" and a Hysteria 2 node with hysteria2 node requires cert.mode = "file". The ACME modes "dns", "http" and "tls" are refused on every stream node, TLS or not: node requests kernel-unsupported feature: ACME cert mode "dns"; on a Hysteria 2 node they fail like any value other than "file". Any other value behaves like "none" on a stream node.
cert_filepathdepends""PEM certificate chain: the server certificate first, then any intermediates (a fullchain.pem). Required with mode = "file"; if it or key_file is empty, a TLS or Hysteria 2 node fails with TLS node requires cert.cert_file and cert.key_file. Read each time the listener is built, not when the file changes. A missing file fails with the bare OS error, such as No such file or directory (os error 2), which does not name the path.
key_filepathdepends""PEM private key matching cert_file. Required with mode = "file". Read at the same moments as cert_file; a key that does not match the certificate fails the listener build.
reject_unknown_sniboolnofalseNot implemented, so true is refused rather than silently ignored: the node fails with node requests kernel-unsupported feature: cert.reject_unknown_sni. Leave it false.

Details of the TLS server:

  • Versions: TLS 1.2 and 1.3. Older versions are refused.
  • Certificate: the first certificate in cert_file is the server certificate, and the rest are sent as the chain.
  • ALPN: a gRPC node selects h2, which is what HTTP/2 clients offer. TCP and WebSocket nodes do not configure ALPN, so a client’s ALPN list is accepted without a protocol being selected.
  • SNI: not checked. Any server name gets the one certificate. reject_unknown_sni = true is refused, as the table says.

Only the fields below shape a stream node’s listener (the Hysteria 2 fields are on the Hysteria 2 nodes page). Every other field in the panel’s answer is ignored, including Xboard’s tls_settings, multiplex, decryption, plugin and plugin_opts, so a setting that exists only there has no effect on a katana node.

Field Node types Use
server_port all The port to listen on. 0 or a missing value fails with newV2board: server port must be > 0.
network V2ray The transport, from the table above.
networkSettings V2ray, VMess path (WebSocket), headers.Host (WebSocket host check), serviceName (gRPC), header (TCP, ignored).
network_settings V2ray, VLESS The same fields, read instead of networkSettings when enable_vless = true.
tls V2ray 0 or missing: no TLS. 1: TLS. 2: REALITY, refused.
flow V2ray Must be empty. Any value is refused as an XTLS flow.
cipher Shadowsocks The cipher, from the Shadowsocks table below.
server_key Shadowsocks The server PSK of a 2022 cipher, base64.
obfs Shadowsocks Empty, plain or none (exactly, in lowercase). Anything else is refused.

A Trojan node reads only server_port here, and is served on TCP with TLS.

A V2ray node without enable_vless serves VMess.

  • AEAD headers only. The legacy MD5 header that goes with alterId greater than 0 is not implemented. katana gives every user an alter ID of 0 and ignores the value in the SSPanel legacy string, so clients must use alterId: 0.
  • Body security: aes-128-gcm or chacha20-poly1305. A client set to auto picks one of these. none and zero are not accepted, and the connection is closed during the handshake.
  • Clock: a VMess header carries a timestamp, and katana accepts it only within 120 seconds of its own clock. Keep the server’s clock synchronised.
  • Users: the account ID is the user’s UUID. A user whose UUID does not parse is skipped with skipping user 7: uuid is not a valid UUID, and the others are served.
  • Commands: TCP, UDP, and mux (see Multiplexing).

The Etemenanki page on VMess describes the protocol implementation in more detail.

A V2ray node with enable_vless = true, or with enable_vless = "1" in SSPanel’s custom_config, serves VLESS.

  • No flow. XTLS flows such as xtls-rprx-vision are not implemented. A panel flow (or [node.api].vless_flow when SSPanel sends a legacy string) refuses the whole node with node requests kernel-unsupported feature: VLESS XTLS flow. A client that sends a flow anyway fails its handshake.
  • Encryption: clients must use encryption: "none".
  • Users: the ID is the user’s UUID. Users with an unparseable UUID are skipped, as for VMess.
  • Commands: TCP, UDP, and mux.

See VLESS for the protocol implementation.

  • Password: the user’s UUID from the panel, exactly as the panel lists it. This is the XrayR convention, and it is the password Xboard gives Trojan clients.
  • TLS: always on, so a Trojan node needs [node.controller.cert] with mode = "file".
  • Transports: TCP on UniProxy panels; TCP, WebSocket or gRPC on SSPanel.
  • UDP: served through Trojan’s UDP associate command.
  • Mux: a client signals mux.cool by connecting to v1.mux.cool, and katana treats that connection as a mux carrier.

See Trojan for the protocol implementation.

A Shadowsocks node is available on UniProxy panels only. It is TCP only: katana binds no UDP socket for it, so a client’s UDP relay does not work through a katana Shadowsocks node.

The panel’s cipher decides between the two Shadowsocks generations:

cipher Family User’s key
aes-128-gcm, aes-256-gcm AEAD (SIP004) The user’s UUID, as the password
chacha20-ietf-poly1305 (also chacha20-poly1305) AEAD (SIP004) The user’s UUID, as the password
xchacha20-ietf-poly1305 (also xchacha20-poly1305) AEAD (SIP004) The user’s UUID, as the password
2022-blake3-aes-128-gcm 2022 multi-user (SIP022) The first 16 characters of the UUID
2022-blake3-aes-256-gcm 2022 multi-user (SIP022) The first 32 characters of the UUID
2022-blake3-chacha20-poly1305 Refused The 2022 spec defines multiple users only for the AES ciphers
anything else Refused node requests kernel-unsupported feature: shadowsocks cipher "rc4-md5"

The AEAD names are matched case-insensitively, and aead_aes_128_gcm, aead_aes_256_gcm and aead_chacha20_poly1305 are accepted as aliases. The 2022 names must be written exactly as shown, in lowercase.

A 2022 node always runs in multi-user mode, with one port for every user. Each client connection carries an identity header that tells katana which user it is. Two keys are involved:

  • The server key is the panel’s server_key, a base64 PSK of 16 bytes for 2022-blake3-aes-128-gcm and 32 bytes for 2022-blake3-aes-256-gcm. A longer key is folded down to that length; a shorter one fails with shadowsocks-2022: PSK too short (0 < 32), and invalid base64 fails with a decode PSK: error.
  • The user key is the first 16 or 32 characters of the user’s UUID string, used as raw bytes.

This is the same derivation Xboard uses when it builds the client’s password: base64(first N characters of the UUID), joined to the server key with a colon. For the UUID 11111111-2222-3333-4444-555555555555 on a 2022-blake3-aes-128-gcm node:

user key bytes: 11111111-2222-33
client password: <server_key>:MTExMTExMTEtMjIyMi0zMw==

You do not configure any of this in katana. It only has to agree with the panel, and with Xboard it does.

katana accepts obfs values of empty, plain and none. Any other value is refused when katana reads the node info, before anything is built:

node 1: node_info failed: newV2board: shadowsocks obfs "http" is not supported

katana does not read plugin or plugin_opts. A SIP003 plugin configured in the panel is not applied, and clients that use it cannot connect.

See Shadowsocks for the protocol implementation.

VMess, VLESS and Trojan nodes accept mux.cool connections from Xray-compatible clients. There is no setting to turn this on: katana recognises the mux command (VMess and VLESS) or the v1.mux.cool destination (Trojan) on every connection.

  • Each sub-connection inside a mux carrier is its own flow: it is routed, audited, rate-limited and counted against the authenticated user exactly like a separate connection.
  • UDP sub-connections are supported, including XUDP, where each packet carries its own address.
  • A carrier holds up to 256 sub-connections at once. A client that opens another is refused that one sub-connection; the carrier and its other sub-connections continue.
  • Only mux.cool is implemented. sing-box multiplexing (Xboard’s multiplex setting) is neither read nor supported.

katana fails closed: when a panel asks for something it cannot deliver, the node does not start, rather than starting without the feature the clients expect. This table lists every refusal and the message katana logs:

Feature Where it comes from Error
REALITY UniProxy tls = 2, SSPanel enable_reality = true node requests kernel-unsupported feature: REALITY
XTLS flow Panel flow; [node.api].vless_flow for an SSPanel legacy string node requests kernel-unsupported feature: VLESS XTLS flow
HTTPUpgrade network = "httpupgrade" node requests kernel-unsupported feature: httpupgrade transport
SplitHTTP, XHTTP network = "splithttp" or "xhttp" node requests kernel-unsupported feature: splithttp transport
Other transports network values such as quic, kcp, h2 node requests kernel-unsupported feature: transport "quic"
PROXY protocol A node that asks to accept it; no panel field sets this in katana 3.0.1 node requests kernel-unsupported feature: PROXY protocol accept
ACME certificates [node.controller.cert].mode of dns, http or tls node requests kernel-unsupported feature: ACME cert mode "dns"
SNI enforcement [node.controller.cert].reject_unknown_sni = true node requests kernel-unsupported feature: cert.reject_unknown_sni
Unknown Shadowsocks cipher Panel cipher node requests kernel-unsupported feature: shadowsocks cipher "rc4-md5"
2022 ChaCha20 multi-user cipher = "2022-blake3-chacha20-poly1305" shadowsocks-2022: multi-user requires an aes-gcm method, or PSK too short without a key
Shadowsocks obfs Panel obfs other than plain or none newV2board: shadowsocks obfs "http" is not supported
Shadowsocks on SSPanel node_type = "Shadowsocks" with panel_type = "SSPanel" sspanel: Shadowsocks node type is not supported
TLS without a file certificate A TLS node whose mode is not "file", including the default "none" TLS node requires cert.mode = "file"
TLS without paths mode = "file" with an empty cert_file or key_file TLS node requires cert.cert_file and cert.key_file

Most of these settings come from the panel, so katana --test cannot see them: it checks the config file, builds the outbounds, panel clients and routers, and validates [node.hysteria], but it does not contact the panel. A config for a REALITY node passes --test and fails at startup.

The error appears in the log with the node’s ID. A refusal found while building the listener looks like this:

ERROR katana::manager::node: node 1: initial start failed: node requests kernel-unsupported feature: REALITY; retrying in 1s

A refusal found while parsing the panel’s answer, such as a Shadowsocks obfs, is logged at startup as node 1: node_info failed: followed by the message and the same ; retrying in note. If it appears later, on a poll, katana logs a warning (node 1: node_info:) and keeps serving the settings it already has. Other nodes in the same file are not affected.

A node that has not come up keeps trying. katana waits 1 second after the first failed attempt and doubles the wait after each further failure, up to 60 seconds, or up to update_periodic when that is shorter. Every attempt reads the node info and the user list from the panel afresh, so once you fix the node in the panel it comes up at the next attempt, without a restart of katana. Saving a change to the node’s [[node]] table in the config file starts the next attempt at once.

If a running node’s settings change in the panel to something refused, the node loses its listener and logs node 1: rebuild failed: followed by the reason. It tries again at every poll, so the node comes back once the panel is fixed. Troubleshooting covers the other startup errors.

katana’s integration tests run the real katana binary against a fake panel and connect with independent client implementations. Every test sends a payload through the node and checks the echoed bytes. The Xray tests also check that the panel received a traffic report for the user.

Client Protocol Transport TLS Mux
Xray-core VMess TCP, WebSocket, gRPC No TCP only
Xray-core VMess TCP Yes No
Xray-core VLESS WebSocket Yes Yes
Xray-core VLESS gRPC Yes No
Xray-core Trojan TCP Yes Yes
Official Hysteria 2 client Hysteria 2 QUIC Yes Not applicable

The Xray clients use VMess security auto and VLESS encryption none, and verify katana’s certificate by pinning its hash. The Xray mux tests use a concurrency of 8. The Hysteria 2 client authenticates with nothing but the user’s UUID, skips certificate verification, and opens two streams on one connection; its node takes its port from [node.hysteria] rather than from the panel.

No test in katana drives a Shadowsocks node with an external client.