Skip to content

Subscription Service

Alireza Ahmadi edited this page Sep 16, 2026 · 2 revisions

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.

The subscription URL

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.

Formats

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!.

Plain links

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.

JSON and Clash

Both are generated from a template you control, merged with the outbounds generated for that client:

Response headers

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.

External links and sub-subscriptions

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.

Settings that shape the output

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.

Troubleshooting

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.

Clone this wiki locally