Quick start
This page takes you from an empty server to a katana node that serves real users. You create a VMess node in an Xboard panel (any newV2board-compatible panel works the same way), put a TLS certificate on the server, write a short config file, check it, start katana, and confirm that the panel receives traffic figures.
katana and the panel split the work. The panel decides what the node is: its protocol, port, transport, WebSocket path, whether TLS is on, and which users may connect. The config file says which panel and node katana serves, where the certificate is, and which address to listen on. So most of the node’s shape is set in the panel, and the config file stays short.
sequenceDiagram
participant P as Panel
participant K as katana
participant C as Client
K->>P: GET node config (port, ws path, TLS)
K->>P: GET user list
Note over K: bind the TCP port
C->>K: VMess over WebSocket + TLS
loop every update_periodic seconds
K->>P: GET node config and user list
K->>P: POST traffic per user
end
Before you start
Section titled “Before you start”You need:
- A Linux server with a public address, and root access or another way to bind port
443(see step 6). - A domain name that resolves to the server, for the certificate. This page uses
proxy.example.com. - Administrator access to the panel. This page uses Xboard. V2board and other panels that speak the newV2board UniProxy API work the same way. SSPanel uses different keys, covered in SSPanel.
- Open ports. TCP
443for clients, and TCP80while you obtain a certificate with an HTTP challenge. The server must also be able to reach the panel over HTTPS.
Set up the node
Section titled “Set up the node”-
Create the node in the panel. In Xboard, add a VMess node with these settings. The labels in the Xboard admin screens can differ from the descriptions below, so the table also gives the name of the field Xboard stores:
Panel setting (Xboard field) Value on this page What katana does with it The address clients connect to ( host)proxy.example.comNothing. Clients use it. The port clients connect to ( port)443Nothing. Clients use it. The port the server listens on ( server_port)443Binds this TCP port. TLS on Wraps the listener in TLS with your certificate. Transport ( network)wsServes VMess over WebSocket. WebSocket path /wsAccepts WebSocket upgrades on exactly this path, and answers any other path with 404.Groups ( group_ids)at least one Users in these groups are the node’s users. Xboard keeps two ports per node. katana binds
server_port;portonly goes into subscriptions. Set both to443unless something in front of katana forwards one port to another.Then write down two values for the config file:
- the node ID, shown in the panel’s node list;
- the communication key (Xboard stores it as the
server_tokensetting). It is one key for the whole panel, shared by every node.
Make sure at least one user can use the node. Xboard sends a user to the node only if the user is in one of the node’s groups, is not banned, has not expired, and has traffic left. katana binds nothing while the list is empty.
-
Install katana. Follow Install, then check the binary:
Terminal window katana --versionkatana 3.0.1 -
Get a certificate. katana has no ACME client. Its only certificate mode is
file: you give it a PEM certificate and a PEM private key, and it reads them from disk when it starts the listener. Any tool that produces those files works.Terminal window sudo certbot certonly --standalone -d proxy.example.comsudo install -d -m 700 /etc/katana/certsudo install -m 644 /etc/letsencrypt/live/proxy.example.com/fullchain.pem /etc/katana/cert/fullchain.pemsudo install -m 600 /etc/letsencrypt/live/proxy.example.com/privkey.pem /etc/katana/cert/privkey.pem--standaloneanswers the challenge on TCP port80, so nothing else may be listening there while it runs.Run these as root, so that acme.sh can write into
/etc/katana/cert:Terminal window acme.sh --issue --standalone --server letsencrypt -d proxy.example.cominstall -d -m 700 /etc/katana/certacme.sh --install-cert -d proxy.example.com \--fullchain-file /etc/katana/cert/fullchain.pem \--key-file /etc/katana/cert/privkey.pem--standaloneanswers the challenge on TCP port80, so nothing else may be listening there while it runs.Terminal window sudo install -d -m 700 /etc/katana/certsudo openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:prime256v1 -nodes -days 30 \-subj /CN=proxy.example.com -addext subjectAltName=DNS:proxy.example.com \-keyout /etc/katana/cert/privkey.pem -out /etc/katana/cert/fullchain.pemClients reject this certificate unless you turn off certificate verification in them. Use it only to try katana out.
What katana requires of the files:
cert_fileholds the server certificate first, then any intermediate certificates. Afullchain.pemhas this order.key_fileholds the matching private key in PEM form (PKCS#8, RSA or EC). katana refuses a key that does not match the certificate.- katana does not check the certificate’s names or expiry date. Clients do, so the certificate must cover the name clients use as the TLS server name.
-
Write the config. Save this as
/etc/katana/config.toml, with your panel URL, node ID and key in place of the placeholders:/etc/katana/config.toml # katana quick start: serve one Xboard (newV2board) VMess node over# WebSocket + TLS. The panel decides the port, the transport and the# WebSocket path; this file says which panel and node to serve, and where# the certificate is.[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.controller]listen_ip = "0.0.0.0"update_periodic = 60[node.controller.cert]mode = "file"cert_file = "/etc/katana/cert/fullchain.pem"key_file = "/etc/katana/cert/privkey.pem"Every key in the file is explained in What each key does below.
-
Check the config.
--testreads the file and builds as much of the node as it can without the panel:Terminal window katana --test -c /etc/katana/config.tomlA valid file prints one line on stdout and exits with status
0:Configuration OKAn invalid file prints
configuration error:and the reason on stderr, and exits with status1. A misspelled key, for example, is an error rather than something katana skips:configuration error: config parse error: TOML parse error at line 20, column 1|20 | update_period = 60| ^^^^^^^^^^^^^unknown field `update_period`, expected one of `listen_ip`, `send_ip`, `update_periodic`, `disable_upload_traffic`, `disable_get_rule`, `disable_sniffing`, `cert`Configuration OKdoes not mean the node will come up.--testmakes no panel request, and for a VMess node it checks neithercert.modenor the certificate files: the example passes even when/etc/katana/cert/fullchain.pemdoes not exist yet. What –test checks lists exactly what it covers. -
Start katana. Run it in the foreground for the first start:
Terminal window sudo katana -c /etc/katana/config.tomlBinding a port below
1024, such as443, needs root or theCAP_NET_BIND_SERVICEcapability. Without either, the listener fails withPermission denied (os error 13). Once the node works, run katana as a service instead, as described in Deployment. -
Read the log. katana writes its log to stdout. When the panel answered and the listener is bound, it logs one line for the node:
2026-09-24T20:28:49.297288Z INFO katana::manager::node: node 1: listening on 0.0.0.0:443node 1is thenode_idfrom the config, and0.0.0.0:443islisten_ipplus the port from the panel. This is the only line katana logs for a node that starts normally. At the defaultinfolevel it logs nothing per connection. If the line does not appear within a few seconds, see Startup log lines. -
Connect a client. Import the panel’s subscription link into a VMess client, or enter the values by hand:
Client setting Value Address proxy.example.comPort 443User ID the user’s UUID from the panel alterId 0Security (body cipher) auto,aes-128-gcmorchacha20-poly1305Network ws, path/wsTLS on, server name proxy.example.comkatana speaks AEAD VMess only, which is what
alterId = 0selects. It refuses the ciphersnoneandzero. -
Confirm the traffic report. Load a few pages through the client, then wait one
update_periodicinterval (60 seconds in this config). The user’s upload and download should rise in the panel. Traffic reporting below explains what katana sends and what it logs.
What each key does
Section titled “What each key does”The quick-start config uses eleven keys. katana rejects any key it does not know, in every table, so a typo stops the program instead of being ignored.
| Key | Value here | Meaning |
|---|---|---|
[log].level |
"info" |
Log filter, in tracing filter syntax: "info", "debug", "info,katana=debug". The default is "info". The RUST_LOG environment variable, if set, overrides it at startup; a later edit of this key replaces it without a restart. |
panel_type |
"NewV2board" |
The panel API. "NewV2board" and its alias "V2board" select the UniProxy API that Xboard and V2board serve. "SSpanel" selects mod_mu. Case does not matter. Anything else fails with unknown panel_type. |
[node.api].host |
"https://panel.example.com" |
The panel’s base URL, with the scheme. katana removes a trailing /. |
[node.api].node_id |
1 |
The node ID from the panel. It also names the node in log lines. |
[node.api].key |
"replace-with-the-panel-key" |
The panel’s communication key. katana sends it as the token query parameter. |
[node.api].node_type |
"V2ray" |
The node’s protocol family: "V2ray" (aliases "vmess" and "vless"), "Trojan", "Shadowsocks" or "Hysteria2" (aliases "hysteria" and "hy2"). Case does not matter. Anything else fails with unknown node_type. katana sends the value in lowercase as the node_type query parameter, or vless for a V2ray node with enable_vless = true. Whether a V2ray node serves VMess or VLESS is decided by enable_vless, not by this value. |
[node.controller].listen_ip |
"0.0.0.0" |
The address to bind. The default is "0.0.0.0". |
[node.controller].update_periodic |
60 |
Seconds between panel syncs. Each sync fetches the node config and user list, and reports traffic. The default is 60, and 0 counts as 1. |
[node.controller.cert].mode |
"file" |
Must be "file", in lowercase, for any node with TLS. The default is "none", and a TLS node with any value other than "file" fails when its listener starts. "dns", "http" and "tls" (ACME modes in XrayR) are refused on every node, with or without TLS. For a node that is not Hysteria 2, --test does not check this key. |
[node.controller.cert].cert_file |
path | The PEM certificate chain. |
[node.controller.cert].key_file |
path | The PEM private key. |
Some keys the example leaves out have defaults worth knowing. [node.api].timeout is the limit for each panel request in seconds; 0 or unset means 5. [node.api].enable_vless = true makes a V2ray node serve VLESS instead of VMess. The full list of keys is in Configuration file.
Use absolute paths for cert_file and key_file. katana opens a relative path against its working directory, not against the directory of the config file.
What –test checks
Section titled “What –test checks”katana --test -c <file> runs the checks that need nothing but the local machine. It binds no port and sends no request to the panel.
Checked by --test |
Checked only when the node starts |
|---|---|
| The file exists, is UTF-8 and valid TOML, and contains no unknown key. | Whether the panel is reachable, and whether host, node_id and key are right. |
There is at least one [[node]]. |
The port, transport, path and TLS setting. They come from the panel. |
Each node’s panel_type and node_type are known values. |
For every node type except Hysteria 2: cert.mode, and whether cert_file and key_file exist and hold a matching pair. |
[dns] and every [[outbound]] build, including the DNS ca_file. |
listen_ip, and whether the port can be bound. |
Each node’s [node.route] compiles: rule syntax, outbound tags, and the geoip and geosite files. |
Whether the panel has users for the node. |
For Hysteria 2 nodes: the [node.hysteria] settings, cert.mode, and the certificate and key files. |
Features the panel asks for that katana refuses, such as REALITY or an XTLS flow. |
The certificate check is different for Hysteria 2 because a Hysteria 2 listener always uses TLS, so katana knows without asking the panel that the node needs a certificate. For every other node type, the panel decides whether TLS is on, so katana checks cert.mode and reads the certificate files only when it starts the listener.
An error that names no file can be misleading. If the config file itself is missing, --test prints only the system error:
configuration error: No such file or directory (os error 2)Startup log lines
Section titled “Startup log lines”When a node does not come up, its log lines say at which stage it stopped, and katana tries again by itself (see Retries after a failed start). Each line from a failed start ends with the wait before the next attempt. The table shows the first failure, which always waits 1 second. The katana::manager::node target and the timestamp are left out below.
| Log line | Cause | Fix |
|---|---|---|
INFO node 1: listening on 0.0.0.0:443 |
The node is up. | None. |
ERROR node 1: node_info failed: GET /api/v1/server/UniProxy/config; retrying in 1s |
The panel request failed: wrong host, the panel is unreachable, or the panel rejected the request (wrong key, unknown node_id, or a node of another type under that ID). |
Check the three values, then run the request by hand as shown below. |
ERROR node 1: node_info failed: parse UniProxy config response; retrying in 1s |
The panel answered with something that is not a node config, for example an HTML page. | Check that host is the panel’s base URL and panel_type matches the panel. |
ERROR node 1: node_info failed: newV2board: server port must be > 0; retrying in 1s |
The node has no service port in the panel. | Set the port in the panel. |
ERROR node 1: initial start failed: TLS node requires cert.mode = "file"; retrying in 1s |
TLS is on in the panel, but cert.mode is unset, "none", or any other value than "file" in lowercase. |
Set mode = "file" and both file paths. |
ERROR node 1: initial start failed: node requests kernel-unsupported feature: ACME cert mode "dns"; retrying in 1s |
cert.mode is "dns", "http" or "tls". katana has no ACME client. |
Obtain the certificate with another tool and set mode = "file". |
ERROR node 1: initial start failed: TLS node requires cert.cert_file and cert.key_file; retrying in 1s |
mode = "file", but cert_file or key_file is empty or missing. |
Set both paths. |
ERROR node 1: initial start failed: No such file or directory (os error 2); retrying in 1s |
cert_file or key_file does not exist. The message does not say which. |
Check both paths. |
ERROR node 1: initial start failed: Permission denied (os error 13); retrying in 1s |
katana may not bind the port, or may not read the key file. | Run as root or with CAP_NET_BIND_SERVICE, and check the key file’s permissions. |
ERROR node 1: initial start failed: Address already in use (os error 98); retrying in 1s |
Another program holds the port. | Stop it, or change the port in the panel. |
ERROR node 1: initial start failed: node requests kernel-unsupported feature: REALITY; retrying in 1s |
The panel describes a feature katana does not implement. | Change the node in the panel. Protocols lists what katana serves. |
ERROR node 1: user_list failed: GET /api/v1/server/UniProxy/user; retrying in 1s |
The user list request failed. katana needs the user list to start a node, so it binds nothing until an attempt gets one. | Check the panel, as for node_info failed. |
| no line at all | The panel returned an empty user list, so katana bound nothing. | Give at least one user access to the node. katana binds the port at the first sync that returns a user. |
ERROR node 1: rebuild failed: No such file or directory (os error 2) |
The node started with no users, and the listener failed when a later sync brought users. The causes are the same as for initial start failed. |
Fix the cause. katana tries again at every sync. |
WARN node 1: node_info: GET /api/v1/server/UniProxy/config or WARN node 1: user_list: GET /api/v1/server/UniProxy/user |
A sync after startup failed. The node keeps serving with the node config and users it already has. | Check the panel. |
The panel error lines never include the URL, because the URL carries the key. To see what the panel answers, send the request katana sends yourself. The key ends up in your shell history, so clear it afterwards:
curl -sS 'https://panel.example.com/api/v1/server/UniProxy/config?node_id=1&node_type=v2ray&token=replace-with-the-panel-key'A working node answers with JSON that contains server_port, network, networkSettings and tls. katana sends the configured node_type in lowercase, and Xboard reads v2ray as vmess.
Retries after a failed start
Section titled “Retries after a failed start”A node that fails to start keeps trying until it is up or katana stops. Each attempt requests the node config and the user list afresh and then starts the listener. The first retry comes 1 second after the failure, and the wait doubles after each further failure, up to 60 seconds, or up to update_periodic seconds if that is shorter. With update_periodic = 60, the waits are 1, 2, 4, 8, 16 and 32 seconds, then 60 seconds for every retry after that. The process and any other nodes keep running meanwhile, so a service manager shows katana as running.
Fix the cause, and the node comes up at its next attempt, without a restart:
- A fix outside katana, such as correcting the node in the panel, freeing the port, or putting the certificate files in place, takes effect at the next retry.
- Saving an edit to the node’s
[[node]]entry in the config file makes katana retry at once instead of waiting out the current wait. - A fix to the process itself, such as granting
CAP_NET_BIND_SERVICEor changing the systemd unit, needs a restart of katana, because a running process does not pick it up.
Traffic reporting
Section titled “Traffic reporting”katana meters each user’s traffic as it relays and reports it at every sync, that is, every update_periodic seconds. The first sync comes one full interval after the node started. For newV2board panels the report is one request:
POST /api/v1/server/UniProxy/push{"7":[82,200204]}Each entry maps a panel user ID to [upload, download] in bytes. katana counts the payload it relays, after decryption, so TLS, WebSocket and VMess overhead is not included. Users who moved no bytes since the last report are left out, and when nobody moved any, katana sends no request.
A successful report logs nothing. A failed one logs a warning:
WARN katana::manager::node: node 1: report traffic: POST UniProxy pushkatana keeps the unreported bytes and adds them to the next report, so a failed report delays the figures but does not lose them. When katana stops on SIGINT or SIGTERM, it closes the listener and sends one last report.
If the panel still shows no traffic after two intervals and there is no warning, check that [node.controller].disable_upload_traffic is not true and that the client really goes through this node. Traffic reporting covers the counters in detail.
When a client cannot connect
Section titled “When a client cannot connect”At the default info level, katana logs nothing for a single failed connection; it logs each one at debug. It warns only when more than 10 handshakes fail within one second on a node. That warning names the node by its tag, the node type, listen_ip and port:
WARN katana::manager::proxy: node V2ray_0.0.0.0_443: 12 inbound handshake failures in the last 1s (possible handshake scan/DoS or misconfigured clients)To see why one client fails, set [log].level = "info,katana=debug" for a while (katana applies a new level without a restart), or check the client against the node:
- WebSocket path. The path must match the panel’s path exactly. katana answers any other path with HTTP
404. - WebSocket host. If the node sets a
Hostheader in the panel, the client’sHostmust match it, ignoring case and port. katana answers a mismatch with HTTP404as well. - TLS server name. The certificate must cover the name the client sends.
- User. The UUID must belong to a user the panel currently sends to the node. A user added in the panel reaches katana at the next sync.
- Clock. VMess authentication fails when the client’s clock is more than 120 seconds away from the server’s.
Stop katana
Section titled “Stop katana”Press Ctrl-C, or send SIGTERM. katana logs shutting down, closes the listeners, reports any traffic not yet reported, and exits with status 0.
While katana runs, it watches the config file’s directory and applies edits without a restart. This includes [node.api]: an edit that points the node at a different panel node, such as a new node_id, restarts that node, and any other [node.api] edit takes effect at once. Hot reload explains which edits take effect and which drop connections. A renewed certificate is not picked up this way: katana reads the certificate files when it starts a listener, so restart katana after each renewal.