-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Subscription Service
The subscription service is a separate HTTP server from the panel. It runs on its own port, with its own path and its own TLS certificate, so you can expose subscriptions to the internet without exposing the panel.
http(s)://<sub domain or host>:<sub port>/<sub path>/<client name>
With the default installation that is:
http://<your server>:2096/sub/<client name>
The last segment is the client's name, not its id. This is why renaming a client
breaks that user's link — the name is the subscription ID. A client must also be
enabled; a disabled client's URL returns 400 Error!.
The panel shows the finished URL for each client. It is built from subURI when you set
one, otherwise from the protocol (https when both subCertFile and subKeyFile are
set), subDomain when set, subPort and subPath. Set subURI when the panel cannot
know the public address itself — behind a reverse proxy or a CDN, for example.
One URL serves three formats, selected by the format query parameter:
| URL | Format | For |
|---|---|---|
…/sub/<name> |
Plain links, one per line | v2rayN, v2rayNG, Nekoray, Streisand and most link-based clients |
…/sub/<name>?format=json |
sing-box configuration | sing-box, SFI/SFA/SFM, Hiddify |
…/sub/<name>?format=clash |
Clash.Meta YAML | Clash.Meta, Mihomo, FlClash |
Any other format value returns 400 Error!.
Each of the client's inbound links is emitted as a vless://, vmess://, trojan://…
URI, one per line, followed by any external links attached to the client. The whole body
is Base64-encoded unless you turn subEncode off — most clients expect the encoded
form, so leave it on unless you are debugging.
With subShowInfo enabled, the remaining traffic and days are appended to each link's
remark, so they show up in the client's node list:
vless://…#Germany 12.4GB📊 27Days⏳
A client with neither a volume limit nor an expiry shows ♾ instead.
Both are generated from a template you control, merged with the outbounds generated for that client:
Every subscription response — including HEAD, which clients use to refresh usage without
downloading the configuration — carries:
| Header | Content |
|---|---|
Subscription-Userinfo |
upload=<bytes>; download=<bytes>; total=<bytes>; expire=<unix seconds> |
Profile-Update-Interval |
Hours between refreshes, from subUpdates
|
Profile-Title |
The client's remark, or its name when no remark is set |
Content-Disposition |
attachment with the same title as the filename |
total=0 means unlimited, and expire=0 means no expiry — that is how clients know not
to draw a usage bar or a countdown.
A client can carry links the panel did not generate. Each entry has a type:
| Type | Meaning |
|---|---|
local |
A link to one of this panel's inbounds. Appears in the plain-link format only |
external |
A single link to some other server. Appears in all three formats |
sub |
The URL of another subscription. Its links are fetched and merged into this one |
This is how you hand a user one link that covers several panels.
| Setting | Default | Effect |
|---|---|---|
subListen |
all interfaces | Listen address of the subscription server |
subPort |
2096 |
Listen port |
subPath |
/sub/ |
URL path prefix |
subDomain |
empty | When set, requests with a different Host are rejected |
subCertFile / subKeyFile
|
empty | TLS certificate; both must be set for HTTPS |
subURI |
empty | Overrides the URL shown in the panel |
subUpdates |
12 |
Profile-Update-Interval, in hours |
subEncode |
true |
Base64-encode the plain-link format |
subShowInfo |
false |
Append traffic/expiry to link remarks |
subJsonExt |
empty | The JSON subscription template |
subClashExt |
empty | The Clash subscription template |
subClashNoDefGrp |
false |
Do not add the default Proxy / Auto groups |
subClashSprtAll |
false |
Expand the all keyword in a group's proxies
|
subClashUdp |
false |
Mark generated Clash proxies as UDP-capable |
See Settings Reference for the full list.
400 Error! — the client name in the URL does not match an enabled client. Check the
spelling and that the client is enabled.
The client fetches but shows no nodes — the client has no inbounds assigned, or the assigned inbounds have no outbound JSON to hand out.
A Snell node is missing from a Clash subscription — Clash has no place for a per-user Snell key, so Snell nodes appear in the JSON format only.
sing-box refuses the downloaded config — download it and run sing-box check -c config.json. That reports the exact field, and the
JSON template page
explains the structure the panel expects.
Usage bar does not move in the client — the client is caching. Profile-Update-Interval
only suggests a refresh period; most clients also refresh on demand.