-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Configuration Objects
The shape of the objects you read with GET /apiv2/<object> and write with
POST /apiv2/save. See API Documentation
for the calls themselves.
There are eight objects: clients, inbounds, outbounds, endpoints, services, tls,
config and settings.
inbounds, outbounds, endpoints and services all work the same way: the panel owns a
few fixed fields (id, type, tag, tls_id) and everything else is passed through to
sing-box unchanged. There is no whitelist, so any option the running sing-box version
supports can be set, and the panel does not need updating for new ones.
The flip side is that the panel cannot tell you a field is wrong — a typo in a sing-box option surfaces when the core restarts and fails. Check the logs after saving.
A client is a subscription: a person, with a link, a traffic budget and a set of inbounds.
| Field | Type | Notes |
|---|---|---|
id |
number | Assigned by the panel |
enable |
boolean | A disabled client's subscription URL returns an error |
name |
string | This is the subscription ID — it is the last segment of the URL. Must be unique. Renaming breaks the user's existing link |
remark |
string | Shown to the user as the profile title |
desc |
string | Free-text note, panel-side only |
group |
string | Free-text grouping, panel-side only |
config |
JSON | Per-protocol credentials, keyed by inbound type |
inbounds |
JSON array | Inbound ids this client may use, e.g. [1,3]
|
links |
JSON array | Extra links — see below |
volume |
number | Traffic budget in bytes. 0 means unlimited |
expiry |
number | Unix seconds. 0 means no expiry |
up / down
|
number | Current period's usage, in bytes |
totalUp / totalDown
|
number | Lifetime usage, across resets |
createdAt / onlineAt
|
number | Unix seconds; onlineAt is the last time traffic was seen |
delayStart |
boolean | Start counting the expiry from first use instead of from creation |
autoReset |
boolean | Reset usage periodically |
resetDays |
number | Days between resets when autoReset is on |
nextReset |
number | Unix seconds of the next scheduled reset |
The client's credentials, keyed by protocol. Each value is one object, and its fields are copied into the outbound the subscriber receives for any inbound of that type:
{
"vless": { "name": "alice", "uuid": "b831381d-6324-4d53-ad4f-8cda48b30811", "flow": "xtls-rprx-vision" },
"vmess": { "name": "alice", "uuid": "b831381d-6324-4d53-ad4f-8cda48b30811", "alterId": 0 },
"trojan": { "name": "alice", "password": "…" },
"shadowsocks": { "name": "alice", "password": "…" },
"shadowsocks16": { "name": "alice", "password": "…" },
"snell": { "name": "alice", "userkey": "…" }
}Four details worth knowing:
-
nameandalterIdare panel-side only and are never copied into the outbound. -
flowis dropped when the inbound has no TLS, or when it uses a transport — XTLS flow is invalid in both cases, and leaving it in produces a node that cannot connect. - Shadowsocks has two keys:
shadowsocks16is used for the2022-blake3-aes-128-gcmmethod andshadowsocksfor everything else. For the 2022 methods the delivered password is the inbound's password and the client's, joined with:. - Snell uses
userkeyrather than a password. It identifies the client alongside the inbound's sharedpsk, which the panel adds to the outbound itself, so the subscriber receives both.
Each entry is { "type": …, "remark": …, "uri": … }:
type |
Meaning |
|---|---|
local |
A link to one of this panel's inbounds. Included in the plain-link subscription only |
external |
A single link to another server. Included in all three subscription formats |
sub |
The URL of another subscription; its links are fetched and merged in |
| Field | Type | Notes |
|---|---|---|
id |
number | Assigned by the panel |
type |
string | sing-box inbound type: vless, vmess, trojan, hysteria2, shadowsocks, … |
tag |
string | Unique. This is the node name users see in their client |
tls_id |
number | References a tls object. 0 for none |
addrs |
JSON array | Public addresses this inbound is reachable at. See below |
out_json |
JSON | The outbound template handed to subscribers for this inbound |
| (any other field) | — | Passed through to sing-box as an inbound option |
out_json is what actually reaches the user: it is the outbound the client will dial this
inbound with. An inbound with an empty out_json is not offered to subscribers.
One inbound can be published at several addresses — a direct IP, a CDN hostname, a second port. Each entry produces its own node in the subscription:
| Field | Notes |
|---|---|
server |
Hostname or IP the client dials |
server_port |
Port the client dials |
remark |
Appended to the node tag, so users can tell the addresses apart |
tls |
Optional. Merged over the outbound's TLS options — useful when one address needs a different SNI |
An empty addrs list means one node, using the address already in out_json.
Node tags are built as <client remark><inbound tag><addr remark>. If two would collide,
the later ones get a -2, -3 suffix — addresses that already carry distinct remarks are
left alone.
{
"type": "vless",
"tag": "vless-reality",
"listen": "::",
"listen_port": 443,
"tls_id": 2,
"addrs": [{ "server": "example.com", "server_port": 443, "remark": "Germany" }],
"out_json": {
"type": "vless",
"server": "example.com",
"server_port": 443,
"flow": "xtls-rprx-vision"
}
}| Field | Type | Notes |
|---|---|---|
id |
number | Assigned by the panel |
type |
string | sing-box outbound type |
tag |
string | Unique |
| (any other field) | — | Passed through to sing-box |
These are the server's own outbounds — how your server reaches the internet — not what subscribers receive.
| Field | Type | Notes |
|---|---|---|
id |
number | Assigned by the panel |
type |
string |
wireguard, tailscale, openconnect, openvpn, … |
tag |
string | Unique |
ext |
JSON | Panel-side extras |
| (any other field) | — | Passed through to sing-box |
Endpoints have no tls_id, unlike inbounds and services. OpenConnect and OpenVPN each
define their own TLS options with their own field names, which the panel's shared TLS
object cannot express — so those endpoints carry their own tls object written in
sing-box's own field names.
| Field | Type | Notes |
|---|---|---|
id |
number | Assigned by the panel |
type |
string | sing-box service type, e.g. derp, resolved, ssm-api
|
tag |
string | Unique |
tls_id |
number | References a tls object |
| (any other field) | — | Passed through to sing-box |
A named certificate pair, referenced by inbounds and services through tls_id. Splitting
it out means one certificate can serve many inbounds and be renewed in one place.
| Field | Type | Notes |
|---|---|---|
id |
number | Assigned by the panel |
name |
string | Label shown in the panel |
server |
JSON | Server-side TLS options: enabled, server_name, certificate_path, key_path, reality, acme… |
client |
JSON | Client-side options embedded in subscription links: enabled, server_name, insecure, utls… |
{
"name": "example.com",
"server": {
"enabled": true,
"server_name": "example.com",
"certificate_path": "/etc/ssl/example.com/fullchain.pem",
"key_path": "/etc/ssl/example.com/privkey.pem"
},
"client": {
"enabled": true,
"server_name": "example.com",
"insecure": false
}
}The sing-box configuration skeleton for the server's own core — log, dns, route,
experimental. Inbounds, outbounds, endpoints and services are merged into it from their
own tables when the core starts.
Saving config restarts the core in the background once the change is committed. If the
new configuration is rejected, the save is rolled back and the core keeps running the
previous one.
Panel settings as a flat key/value object. See Settings Reference.
{ "subPort": "2096", "subUpdates": "12", "subEncode": "true" }Values are strings, including booleans and numbers. Changing webPort, webPath,
webCertFile or webKeyFile restarts the panel.