Coming from XrayR or V2bX
katana speaks the same panel APIs as XrayR and V2bX, so a node moves over without any change on the panel: the same node ID, the same key, the same users and the same client subscriptions. What changes is the file on the node. XrayR’s YAML (and V2bX’s JSON) becomes one TOML file, the Xray JSON files for routing and outbounds become tables in that file, and a handful of XrayR features have no counterpart.
This page is for you if you run XrayR or V2bX today. It maps every XrayR key to its katana key, shows a complete node side by side, translates route.json and custom_outbound.json, and lists what katana ignores or refuses so that nothing silently changes behaviour. V2bX has its own section near the end.
The files, before and after
Section titled “The files, before and after”XrayR spreads a node over several files. katana reads exactly one.
flowchart LR
subgraph X["XrayR"]
Y["config.yml: Log and Nodes"]
R["route.json"]
O["custom_outbound.json"]
D["dns.json"]
I["custom_inbound.json"]
end
subgraph K["katana: one config.toml"]
L["[log]"]
N["one [[node]] per Nodes entry"]
NR["[node.route] inside each node"]
OB["[[outbound]], shared"]
DNS["[dns], shared"]
end
Gone["no equivalent"]
Y --> L
Y --> N
R --> NR
O --> OB
D --> DNS
I --> Gone
Four differences shape everything below.
- Key names are snake_case and strict.
ApiHostbecomeshost,NodeIDbecomesnode_id. Every table rejects keys it does not know, so a leftover XrayR key stops katana withunknown fieldinstead of being ignored. - Routing is per node. XrayR applies one
route.jsonto every node. In katana each[[node]]has its own[node.route]; outbounds and DNS stay shared. - Routes and outbounds are katana’s own syntax, not Xray JSON. The matchers are fewer and a rule matches when any of its matchers matches.
- Certificates come from files. katana has no ACME client.
CertMode: dns,httpandtlsare refused.
Migrate a node
Section titled “Migrate a node”-
Collect what XrayR uses. Note each entry under
Nodes, and whetherRouteConfigPath,OutboundConfigPath,DnsConfigPathorInboundConfigPathpoint at a file. Check each node’sCertMode. -
Put certificates in files. If XrayR obtained certificates through ACME (
CertMode: dns,httportls), set up an ACME client of your choice, such as certbot or acme.sh, and note the paths of the full-chain certificate and the private key, both PEM. Until the new client takes over renewal, you can point katana at copies of the files XrayR obtained: it keeps them ascert/certificates/<domain>.crtand<domain>.keyunder its configuration directory, typically/etc/XrayR. -
Write
/etc/katana/config.toml. Translate each node with the tables below. Put[node.route]into every node that needs routing, and the outbounds once at the top level. -
Check the file.
Terminal window katana --test -c /etc/katana/config.tomlIt prints
Configuration OK, orconfiguration error:followed by the first problem.--testdoes not contact the panel and, except for Hysteria 2 nodes, does not read the certificate files, so problems with what the panel sends or with the certificate appear only when the node starts. -
Swap the services. Stop XrayR first: both bind the node’s port, so they cannot run side by side. Then start katana and watch for each node’s listening line:
INFO katana::manager::node: node 1: listening on 0.0.0.0:443If a line reads
node 1: node_info failed: …; retrying in 1sornode 1: initial start failed: …; retrying in 1sinstead, the text before; retryingnames the cause, and the node tries again by itself; see Common errors. A node whose user list is empty binds nothing and writes no listening line until a poll returns users,update_periodicseconds later.
Deployment covers installing katana as a service.
One node, side by side
Section titled “One node, side by side”This XrayR node serves VLESS from an Xboard or V2board panel with a certificate from files and a local audit list. The katana file below it does the same.
Log: Level: warning AccessPath: ErrorPath:Nodes: - PanelType: "NewV2board" ApiConfig: ApiHost: "https://panel.example.com" ApiKey: "replace-with-the-panel-key" NodeID: 1 NodeType: V2ray Timeout: 30 EnableVless: true VlessFlow: "" SpeedLimit: 0 DeviceLimit: 0 RuleListPath: /etc/XrayR/rulelist ControllerConfig: ListenIP: 0.0.0.0 SendIP: 0.0.0.0 UpdatePeriodic: 60 EnableDNS: false DNSType: AsIs EnableProxyProtocol: false EnableFallback: false CertConfig: CertMode: file CertDomain: "proxy.example.com" CertFile: /etc/XrayR/cert/proxy.example.com.cert KeyFile: /etc/XrayR/cert/proxy.example.com.key[log]level = "warn" # XrayR's "warning"
[[node]]panel_type = "NewV2board"
[node.api]host = "https://panel.example.com"node_id = 1key = "replace-with-the-panel-key"node_type = "V2ray"enable_vless = truetimeout = 30rule_list_path = "/etc/katana/rulelist"
[node.controller]listen_ip = "0.0.0.0"update_periodic = 60
[node.controller.cert]mode = "file"cert_file = "/etc/katana/proxy.example.com.cert"key_file = "/etc/katana/proxy.example.com.key"What happened to the other keys:
VlessFlow: "",SpeedLimit: 0andDeviceLimit: 0are the defaults, so the katana file leaves them out.send_ipwould be accepted but does nothing.EnableDNS,DNSType,EnableProxyProtocol,EnableFallbackandCertDomainhave no katana key. Writing them fails the parse.AccessPathandErrorPathhave no counterpart: katana writes its log to standard output.
In YAML, a node’s settings nest under its list entry. In TOML, [node.api], [node.controller] and [node.controller.cert] attach to the [[node]] written most recently above them, so keep each node’s tables together, directly under its [[node]] line. A second node starts with another [[node]].
PanelType
Section titled “PanelType”katana speaks two panel APIs. panel_type is compared without regard to case.
XrayR PanelType |
katana panel_type |
API |
|---|---|---|
NewV2board |
"NewV2board" |
UniProxy (Xboard, V2board) |
V2board |
"V2board", an alias of "NewV2board" |
UniProxy |
SSpanel |
"SSpanel" |
mod_mu |
PMpanel, Proxypanel, V2RaySocks, GoV2Panel, BunPanel |
not supported | none |
An unsupported or missing value fails --test with unknown panel_type "pmpanel", the value shown in lower case. At startup katana logs the same message for that node, skips it and runs the others; it exits only if every node fails this way. The panel pages, Xboard and V2board and SSPanel, list the fields katana reads from each.
NodeType
Section titled “NodeType”XrayR NodeType |
katana node_type |
Served as |
|---|---|---|
V2ray |
"V2ray" |
VMess, or VLESS with enable_vless = true |
Vmess |
"V2ray" ("vmess" is also accepted) |
VMess |
Vless |
"V2ray" with enable_vless = true |
VLESS without flow. XrayR served VLESS for NodeType: Vless alone; katana needs enable_vless. On a UniProxy panel, enable_vless also makes katana read the transport settings from network_settings instead of networkSettings; see VLESS over WebSocket or gRPC on current Xboard. |
Trojan |
"Trojan" |
Trojan; each user’s password is their UUID, as in XrayR |
Shadowsocks |
"Shadowsocks" |
AEAD ciphers or Shadowsocks 2022, over TCP only, without plugins. UniProxy panels only; an SSPanel node fails with sspanel: Shadowsocks node type is not supported |
Shadowsocks-Plugin |
not supported | fails with unknown node_type "Shadowsocks-Plugin" |
| none | "Hysteria2" |
Hysteria 2 over QUIC; see Hysteria 2 |
Protocols describes each protocol in detail.
ApiConfig to [node.api]
Section titled “ApiConfig to [node.api]”| XrayR key | katana key | Notes |
|---|---|---|
ApiHost |
host |
The panel’s base URL with its scheme. A trailing / is removed. |
ApiKey |
key |
Sent as token to UniProxy panels, and as key and muKey to SSPanel. |
NodeID |
node_id |
An unsigned 32-bit integer. |
NodeType |
node_type |
See NodeType. |
Timeout |
timeout |
Seconds for one panel request. 0 or unset means 5 seconds, as in XrayR. XrayR retries a failed request three times; katana sends it once. A failed poll is tried again at the next poll, and a failed first start after a wait that starts at 1 second and doubles, up to 60 seconds or update_periodic. |
EnableVless |
enable_vless |
Same meaning. |
VlessFlow |
vless_flow |
Leave it empty; katana has no XTLS flow. UniProxy nodes ignore the local value. On an SSPanel node that falls back to the legacy server string, a non-empty value refuses the node with node requests kernel-unsupported feature: VLESS XTLS flow. XrayR’s sample file sets xtls-rprx-vision, so check this one. |
SpeedLimit |
speed_limit |
Mbps. Above 0, it replaces every user’s panel limit, as in XrayR. See Speed limits. |
DeviceLimit |
device_limit |
Accepted and ignored. katana enforces no device limit. |
RuleListPath |
rule_list_path |
The same file format: one regular expression per line. katana also skips blank lines and lines starting with #, and logs and skips a line that does not compile. The string a rule is tested against changes: XrayR tested tcp:example.com:443, katana tests example.com, the host alone. A rule that relies on the tcp: prefix or on a port, such as :25$, never matches in katana. See Audit rules. |
DisableCustomConfig |
disable_custom_config |
SSPanel only. Same meaning. |
ControllerConfig to [node.controller]
Section titled “ControllerConfig to [node.controller]”| XrayR key | katana key | Notes |
|---|---|---|
ListenIP |
listen_ip |
Default "0.0.0.0". |
SendIP |
send_ip |
Accepted and ignored. Outbound connections leave from the address the operating system picks. |
UpdatePeriodic |
update_periodic |
Seconds, default 60, minimum 1. One timer drives the node poll, the user poll, the audit rules and the traffic report. |
DisableUploadTraffic |
disable_upload_traffic |
Same meaning. |
DisableGetRule |
disable_get_rule |
Same meaning; it also stops katana reading rule_list_path. |
DisableSniffing |
disable_sniffing |
Same switch, different effect. XrayR replaced the destination with the sniffed name. katana reads the TLS SNI or the HTTP Host header of a flow addressed by IP, uses it only to match domain_suffix and geosite rules, and still dials the IP. See Routing. |
CertConfig |
[node.controller.cert] |
See the next section. |
EnableDNS, DNSType |
none | Use the top-level [dns] section, and address_family on an outbound (see Outbounds). |
EnableProxyProtocol |
none | katana does not accept the PROXY protocol. Put nothing in front of a node that sends it. |
EnableFallback, FallBackConfigs |
none | katana has no fallbacks. |
DisableIVCheck |
none | |
AutoSpeedLimitConfig |
none | Speed limits come only from the panel and speed_limit. |
GlobalDeviceLimitConfig |
none | No device limit, and no Redis. |
EnableREALITY, REALITYConfigs, DisableLocalREALITYConfig |
none | katana does not serve REALITY. A panel node with REALITY turned on is refused at start with node requests kernel-unsupported feature: REALITY. |
Every “none” row is a parse error if you copy the key across, for example:
configuration error: config parse error: TOML parse error at line 18, column 1 |18 | enable_dns = true | ^^^^^^^^^^unknown field `enable_dns`, expected one of `listen_ip`, `send_ip`, `update_periodic`, `disable_upload_traffic`, `disable_get_rule`, `disable_sniffing`, `cert`CertConfig to [node.controller.cert]
Section titled “CertConfig to [node.controller.cert]”| XrayR key | katana key | Notes |
|---|---|---|
CertMode |
mode |
"none" (default) or "file", written in lower case. "dns", "http" and "tls" are refused. |
CertFile |
cert_file |
PEM certificate, full chain. |
KeyFile |
key_file |
PEM private key. |
RejectUnknownSni |
reject_unknown_sni |
false only. true refuses the node with node requests kernel-unsupported feature: cert.reject_unknown_sni. |
CertDomain, Provider, Email, DNSEnv |
none | ACME settings. Remove them; they are parse errors. |
Top-level settings
Section titled “Top-level settings”| XrayR key | katana | Notes |
|---|---|---|
Log.Level |
[log].level |
A tracing filter. error, info and debug carry over. Write warn for XrayR’s warning, and off for none: katana reads an unknown word as a target name, so level = "warning" hides every line. See The [log] section. |
Log.AccessPath, Log.ErrorPath |
none | katana logs to standard output. It writes no access log. |
DnsConfigPath |
[dns] |
One resolver for the whole process: the system resolver (default), or plain DNS, DNS over TLS or DNS over HTTPS to one server. Xray’s dns.json features, such as per-domain servers and hosts, have no counterpart. |
RouteConfigPath |
[node.route] in each node |
See Routing and outbounds. |
OutboundConfigPath |
[[outbound]] |
See Outbounds. |
InboundConfigPath |
none | katana serves only the nodes the panel describes. |
ConnectionConfig |
none | Timeouts are fixed. A client has 10 seconds for its TLS, WebSocket or gRPC handshake and 10 seconds more to send a complete proxy request. A relayed flow that carries nothing in either direction for 300 seconds is closed; XrayR’s default ConnIdle was 30. |
Nodes |
[[node]], repeated |
One [[node]] block per list entry. |
Routing and outbounds
Section titled “Routing and outbounds”XrayR hands route.json and custom_outbound.json to Xray. katana has its own routing, configured in TOML, with a smaller set of matchers. The example below is XrayR’s sample routing, translated.
[ { "tag": "IPv4_out", "protocol": "freedom", "settings": {} }, { "tag": "IPv6_out", "protocol": "freedom", "settings": { "domainStrategy": "UseIPv6" } }, { "tag": "socks5-egress", "protocol": "socks", "settings": { "servers": [{ "address": "127.0.0.1", "port": 1080 }] } }, { "protocol": "blackhole", "tag": "block" }]{ "domainStrategy": "IPOnDemand", "rules": [ { "type": "field", "outboundTag": "block", "ip": ["geoip:private"] }, { "type": "field", "outboundTag": "block", "protocol": ["bittorrent"] }, { "type": "field", "outboundTag": "socks5-egress", "domain": ["geosite:openai"] }, { "type": "field", "outboundTag": "IPv6_out", "domain": ["geosite:netflix"] }, { "type": "field", "outboundTag": "IPv4_out", "network": "udp,tcp" } ]}# IPv4_out and block need no entry: freedom without a domainStrategy is the# built-in "direct", and "block" is built in.[[outbound]]tag = "ipv6-out"protocol = "direct"address_family = "ipv6_only" # Xray's UseIPv6
[[outbound]]tag = "socks5-egress"protocol = "socks"server = "127.0.0.1"port = 1080
[[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" # the catch-all IPv4_out rulegeoip = "/etc/katana/geoip.dat"geosite = "/etc/katana/geosite.dat"
[[node.route.rule]]outbound = "block"geoip = ["private"]
# The bittorrent rule has no equivalent: katana does not detect BitTorrent.
[[node.route.rule]]outbound = "socks5-egress"geosite = ["openai"]
[[node.route.rule]]outbound = "ipv6-out"geosite = ["netflix"]A second node that should route the same way needs its own copy of the [node.route] table and its rules. The [[outbound]] entries are defined once and every node can use them.
Outbounds
Section titled “Outbounds”| Xray outbound | katana [[outbound]] |
|---|---|
freedom |
The built-in direct (alias freedom). For a different address policy, declare protocol = "direct" (or "freedom") under a new tag with address_family. |
freedom with domainStrategy |
address_family: UseIPv4 becomes "ipv4_only", UseIPv6 becomes "ipv6_only", UseIPv4v6 becomes "prefer_ipv4" and UseIPv6v4 becomes "prefer_ipv6". "auto" (the default) tries every resolved address in the resolver’s order. To change the policy of unmatched traffic, declare the outbound under a new tag and point [node.route].default at it. |
blackhole |
The built-in block (alias blackhole). Remove the JSON entry. |
socks |
protocol = "socks" with server, port, and optionally username and password. |
http |
protocol = "http". |
vmess, vless |
protocol = "vmess" or "vless", with server, port and uuid from vnext. VMess security accepts auto, aes-128-gcm and chacha20-poly1305, and katana reads auto as aes-128-gcm; none and zero fail with unsupported vmess security "none". VLESS has no flow. |
shadowsocks |
protocol = "shadowsocks" with method and password; a 2022-blake3-… method selects Shadowsocks 2022. TCP only: a UDP flow routed to it fails. |
wireguard |
protocol = "wireguard", one peer: secretKey becomes private_key, address becomes local_address, and the peer’s publicKey, preSharedKey, endpoint and keepAlive become public_key, pre_shared_key, server and port, and keepalive. mtu and reserved keep their names. |
trojan and others |
Not supported: unknown outbound protocol "trojan". |
streamSettings, mux, sendThrough |
Not supported. Every proxy outbound except WireGuard reaches its upstream over plain TCP. |
The tags direct, freedom, block and blackhole are reserved. Copying XrayR’s block blackhole across fails with duplicate/reserved outbound tag block; under any other tag it fails with outbound needs a non-empty server and non-zero port (got "":0), because blackhole is not an outbound protocol in katana. Tags are compared exactly, so a rule that still names IPv6_out after you renamed the outbound fails with route references unknown outbound tag: IPv6_out. Outbounds documents every outbound key.
An Xray rule with domain and port needs both to match. A katana rule matches when any of its matchers matches: domain_suffix = ["example.com"] and port = ["443"] in one rule send all of example.com and all port-443 traffic to its outbound. Split such a rule, or accept the wider match.
| Xray rule field | katana [[node.route.rule]] |
|---|---|
outboundTag |
outbound. Required. |
domain, "domain:example.com" |
domain_suffix = ["example.com"]: the domain and its subdomains. Drop the domain: prefix: katana takes the string literally, so "domain:example.com" passes --test and never matches. |
domain, "geosite:cn" |
geosite = ["cn"], and [node.route].geosite set to the file. "cn@ads" style attributes work. Leave off the geosite: prefix; geosite = ["geosite:cn"] fails with geosite code not found: geosite:cn. |
domain, "full:…" |
No exact match. domain_suffix is the nearest, and it also matches subdomains. |
domain, "regexp:…", "keyword:…" or a bare string |
No equivalent. An Xray bare string matches anywhere in the name; domain_suffix does not. |
ip, a CIDR or an address |
cidr = ["10.0.0.0/8"]; a bare address is one host. The host bits must be zero: Xray accepts 10.0.0.1/8, katana fails with invalid cidr "10.0.0.1/8": host part of address was not zero. |
ip, "geoip:cn" or "geoip:!cn" |
geoip = ["cn"] or geoip = ["!cn"], and [node.route].geoip set to the file. |
port, "53,443,1000-2000" |
port = ["53", "443", "1000-2000"]: one port or range per string, and always a string. "53,443" fails with invalid port spec: "53,443", and port = [443] with invalid type: integer `443`, expected a string. |
network, source, sourcePort, user, inboundTag, protocol, attrs, balancerTag |
No equivalent. |
domainStrategy |
No equivalent. See the caution below. |
balancers |
No equivalent. |
- The geodata files are the same v2ray-format
geoip.datandgeosite.datXrayR uses, so you can copy them. katana does not look for them in a default directory; set[node.route].geoipandgeositeto absolute paths. A rule that uses one without its path fails witha geoip matcher is used but no geoip file is configured. - Rules apply in order and the first match wins, as in Xray. With no match, the flow takes
[node.route].default, which isdirectwhen unset. - Routes that the panel publishes with the
blockaction are audit rules in katana, not routes, as in XrayR; see Audit rules. Routes with thednsaction, which XrayR turned into DNS servers, are ignored.
Routing covers every routing key.
What katana ignores or refuses
Section titled “What katana ignores or refuses”XrayR settings fall into four groups. The first stops --test; the second and third pass --test and keep the node from starting; the last is harmless.
| Group | Keys and values | What happens |
|---|---|---|
| No such key | EnableDNS, DNSType, EnableProxyProtocol, EnableFallback, FallBackConfigs, DisableIVCheck, AutoSpeedLimitConfig, GlobalDeviceLimitConfig, EnableREALITY, REALITYConfigs, DisableLocalREALITYConfig, CertDomain, Provider, Email, DNSEnv, AccessPath, ErrorPath, ConnectionConfig, the *ConfigPath keys, and any PascalCase name |
Parse error, unknown field. --test fails, and katana does not start. |
| Refused by your file at node start | mode = "dns", "http" or "tls"; reject_unknown_sni = true; mode = "none" on a TLS node; a non-empty vless_flow on an SSPanel node that uses the legacy server string |
The node logs initial start failed: …; retrying in <N>s and keeps retrying. It comes up once you fix and save the file, which also makes it try again at once. Other nodes run. For Hysteria 2 nodes --test checks the certificate settings too. |
| Refused by what the panel describes | REALITY; an XTLS flow; any transport other than TCP, WebSocket and gRPC, such as httpupgrade, xhttp or h2; a Shadowsocks plugin such as obfs: http; node_type = "Shadowsocks" with SSPanel |
The node logs initial start failed: node requests kernel-unsupported feature: …, or node_info failed: … for the last two, followed by ; retrying in <N>s, and keeps retrying. It comes up at the next attempt after you change the node in the panel, or node_type in the file. |
| Accepted and ignored | send_ip, device_limit; vless_flow on UniProxy nodes and on SSPanel nodes read from custom_config |
No effect. |
Coming from V2bX
Section titled “Coming from V2bX”V2bX always talks to a UniProxy panel, so every V2bX node becomes a katana node with panel_type = "NewV2board". V2bX has no PanelType key, and katana has no default: leaving panel_type out fails with unknown panel_type "".
Node keys
Section titled “Node keys”V2bX accepts a node’s keys either flat or split into ApiConfig and Options; the mapping is the same either way.
| V2bX key | katana key | Notes |
|---|---|---|
ApiHost |
[node.api].host |
V2bX defaults to http://127.0.0.1; katana has no default. |
ApiKey |
[node.api].key |
|
NodeID |
[node.api].node_id |
|
NodeType |
[node.api].node_type |
See the next table. |
Timeout |
[node.api].timeout |
V2bX defaults to 30 seconds, katana to 5. |
RuleListPath |
[node.api].rule_list_path |
|
ListenIP |
[node.controller].listen_ip |
|
SendIP |
[node.controller].send_ip |
Accepted and ignored. |
CertConfig |
[node.controller.cert] |
As for XrayR. V2bX’s CertMode: "self" has no counterpart: a TLS node needs mode = "file". |
LimitConfig.SpeedLimit |
[node.api].speed_limit |
Different rule: see the caution below. |
EnableSniff, DisableSniffing |
[node.controller].disable_sniffing |
Note the inverted sense of the sing-box core’s EnableSniff. katana never overrides the destination, so SniffOverrideDestination has no counterpart. |
Hysteria2ConfigPath |
[node.hysteria] |
Credential format, UDP relay and masquerade page. See Hysteria 2. |
Log.Level |
[log].level |
V2bX’s debug, info, warn and error carry over unchanged. Log.Output has no counterpart; katana logs to standard output. A core’s own Log settings have none either. |
Core, CoreName, Cores |
none | katana has one built-in kernel. |
ApiSendIP, Include, Name |
none | |
LimitConfig.DeviceLimit, ConnLimit, EnableRealtime, EnableIpRecorder, EnableDynamicSpeedLimit |
none | No device, connection or dynamic limits. |
DeviceOnlineMinTraffic, ReportMinTraffic |
none | katana reports every user with non-zero traffic. |
EnableProxyProtocol, EnableFallback, FallBackConfigs, EnableTFO, EnableUot, DisableIVCheck |
none | |
EnableDNS, DNSType, DomainStrategy |
none | Use [dns], and address_family on a direct outbound. |
The Xray core’s RouteConfigPath and OutboundConfigPath files translate exactly as shown for XrayR. A sing-box core’s OriginalPath configuration has to be rewritten by hand into [[outbound]] and [node.route].
Panel routes also read differently. V2bX turns a protocol:bittorrent entry in a block route into a protocol rule and strips a regexp: prefix from the others. katana, like XrayR, joins a block route’s entries into one regular expression over the requested host, so an entry with either prefix never matches. Routes with the dns action are ignored.
Node types
Section titled “Node types”V2bX NodeType |
katana node_type |
|---|---|
vmess |
"V2ray" |
vless |
"V2ray" with enable_vless = true. "vless" alone serves VMess; see NodeType. |
trojan |
"Trojan" |
shadowsocks |
"Shadowsocks" |
hysteria2 |
"Hysteria2" |
hysteria |
Not supported. katana serves only Hysteria 2; its "hysteria" is an alias of "Hysteria2". |
tuic, anytls |
Not supported: unknown node_type "tuic". |
Side by side
Section titled “Side by side”{ "Log": { "Level": "info", "Output": "" }, "Cores": [{ "Type": "xray", "Log": { "Level": "error" } }], "Nodes": [ { "Core": "xray", "ApiHost": "https://panel.example.com", "ApiKey": "replace-with-the-panel-key", "NodeID": 1, "NodeType": "vless", "Timeout": 30, "ListenIP": "0.0.0.0", "SendIP": "0.0.0.0", "EnableProxyProtocol": false, "EnableDNS": false, "LimitConfig": { "SpeedLimit": 0, "DeviceLimit": 0 }, "CertConfig": { "CertMode": "file", "CertFile": "/etc/V2bX/fullchain.cer", "KeyFile": "/etc/V2bX/cert.key" } } ]}[log]level = "info"
[[node]]panel_type = "NewV2board" # V2bX always uses UniProxy
[node.api]host = "https://panel.example.com"node_id = 1key = "replace-with-the-panel-key"node_type = "V2ray" # V2bX "vless"enable_vless = truetimeout = 30
[node.controller]listen_ip = "0.0.0.0"update_periodic = 60 # the panel's push and pull intervals are not read
[node.controller.cert]mode = "file"cert_file = "/etc/katana/fullchain.cer"key_file = "/etc/katana/cert.key"V2bX takes its poll and report intervals from the panel’s base_config. katana ignores those and uses update_periodic, default 60 seconds, for both; set it to the interval you had.
What changes for clients and the panel
Section titled “What changes for clients and the panel”| Area | With katana |
|---|---|
| Client configurations | Unchanged for VMess, VLESS without flow, Trojan, Shadowsocks and Hysteria 2. The credentials still come from the panel’s user UUIDs. |
| Shadowsocks UDP | Not served. katana binds no UDP socket for a Shadowsocks node. |
| Trojan on UniProxy panels | Served over TCP with TLS, as in XrayR. The panel’s transport setting for the node is not read. |
| Hysteria 2 authentication | The client’s password is the user’s UUID by default, as with V2bX. [node.hysteria].credential = "user_pass" switches to the user:pass form. |
| Online users and device counts | Not reported. The panel shows no online users or IPs for the node. |
| Node status | Not reported: no CPU, memory or disk figures in the panel. |
| Audit rules | Matched against the destination as the client addressed it, never against a sniffed name. XrayR, which overrode the destination with the sniffed name, matched that name. |
| Audit hits | Reported to SSPanel for the panel’s own rules. UniProxy has no endpoint for them, so a UniProxy panel receives none; the flows are still refused. |
| Speed limits | Per user, from the panel, with the local override; enforced as one budget per user across all their connections. See Speed limits. |
| Editing the config file | XrayR restarts every node on a change. katana applies each change to the node it concerns, [node.api] edits included, without a restart. An edit that points the block at another panel node (panel_type, host, node_id, key, and on Xboard and V2board the node type katana asks for) replaces that node. katana keeps the running configuration if the new file does not parse, or if an outbound or a node in it does not build. See Node identity and reload and Hot reload. |
Common errors
Section titled “Common errors”A line from a failed node start ends with ; retrying in <N>s, which the table leaves out.
| Message | Cause and fix |
|---|---|
unknown field `PanelType`, expected one of `panel_type`, … |
An XrayR key name. Use the snake_case name from the tables above. |
unknown field `enable_dns`, … (or cert_domain, enable_proxy_protocol, access_path …) |
A setting katana does not have. Remove the key. |
unknown panel_type "pmpanel" (or "") |
A panel katana does not speak, or panel_type left out. |
unknown node_type "Shadowsocks-Plugin" |
A node type katana does not serve. |
duplicate/reserved outbound tag block |
An [[outbound]] redefines a built-in tag. Delete it and use the built-in. |
outbound needs a non-empty server and non-zero port (got "":0) |
An [[outbound]] translated from Xray’s blackhole, or a proxy outbound without server and port. Use the built-in block. |
unknown outbound protocol "trojan" |
An outbound protocol katana does not have. |
outbound ipv6-out invalid address_family "UseIPv6" |
Xray’s names. Use ipv4_only, ipv6_only, prefer_ipv4, prefer_ipv6 or auto. |
route references unknown outbound tag: IPv6_out |
A rule names an outbound that is not defined, often after renaming. |
invalid port spec: "53,443" |
Split the list: port = ["53", "443"]. |
geosite code not found: geosite:netflix |
Drop the geosite: prefix. |
a geoip matcher is used but no geoip file is configured |
Set [node.route].geoip to the .dat file. The same holds for geosite. |
node 1: initial start failed: node requests kernel-unsupported feature: ACME cert mode "dns" |
Use mode = "file" with certificate files, then save the file. |
node 1: initial start failed: TLS node requires cert.mode = "file" |
The panel describes a TLS node and the file has mode = "none". |
node 1: hysteria2 node requires cert.mode = "file" |
A Hysteria 2 node without mode = "file". --test reports this one. |
node 1: initial start failed: node requests kernel-unsupported feature: VLESS XTLS flow |
Clear the flow in the panel, and vless_flow in the file for SSPanel. |
node 1: node_info failed: newV2board: shadowsocks obfs "http" is not supported |
Remove the plugin from the Shadowsocks node in the panel. |
| No log lines at all | level = "warning" or "none". Use warn or off. |
Troubleshooting covers errors that are not specific to a migration.