Files
3x-ui/docs/content/docs/en/config/subscription.mdx
T
Farhan Zare 0f6e1ae8d7 fix(sub): bind JSON local inbounds to 127.0.0.1 and keep mux.cool off Vision outbounds (#6418)
* fix(sub): bind JSON local inbounds to 127.0.0.1 and keep mux.cool off Vision outbounds

The JSON subscription's local SOCKS/HTTP inbounds had no listen address, so
every client that runs the profile verbatim bound an unauthenticated proxy on
0.0.0.0, and iOS packet-tunnel clients could not reach it at all (Happ iOS:
CONNECTED with zero traffic, same symptom as #6379 — on the same device the
mixed inbound also worked once bound to 127.0.0.1). Bind both to loopback,
which is what every client's own generated config does.

The global subJsonMux was also applied to VLESS outbounds carrying
xtls-rprx-vision. XTLS flows do not support mux.cool: Xray answers the mux
handshake with "common/mux: unexpected network TCP" and the tunnel passes
nothing, on every platform (verified with Happ iOS/Android/macOS, V2Box iOS
and desktop Xray 26.6.27 against a 3x-ui 3.7.0 box with per-client traffic
counters). Skip the mux block whenever the outbound carries a flow.

Refs #6379

* fix(sub): keep XUDP settings when disabling TCP mux on Vision outbounds

Clearing the whole mux object also dropped xudpConcurrency, xudpProxyUDP443
and any per-host muxParams override. Xray reads those only under
mux.enabled, so set concurrency to -1 instead: TCP mux.cool (which XTLS flows
reject) is off, XUDP and the UDP/443 policy stay. The test now decodes each
outbound into a fresh map.

---------

Co-authored-by: Farhan Zare <farhan.zare@openscreen.com>
2026-09-05 20:44:48 +02:00

87 lines
4.1 KiB
Plaintext

---
title: Subscription
description: Run the 3x-ui subscription server — base64/JSON/Clash formats, ports and paths, TLS, response headers, and custom templates.
icon: Rss
---
A **subscription** is a single URL that returns all of a client's
configurations. Client apps refresh it periodically, so when you change an
inbound, clients pick up the change automatically. The subscription server runs
as a **separate** server from the panel.
## Enable and configure
The subscription server is **on by default** (`subEnable`). Configure it in the
panel's subscription settings:
| Setting | Default | Meaning |
| ------------- | ------- | --------------------------------------------------------------- |
| `subPort` | `2096` | Listen port (separate from the panel). |
| `subListen` | _(all)_ | Bind address. |
| `subPath` | _(random per panel)_ | Base path for raw subscription URLs. |
| `subDomain` | _(none)_| Public host; if set, the server only answers for that Host. |
| `subCertFile` / `subKeyFile` | _(none)_ | TLS cert + key — when set, the server serves **HTTPS**. |
| `subEncrypt` | `true` | Base64-encode the raw subscription body. |
| `subUpdates` | `12` | Suggested refresh interval (hours) sent to clients. |
A subscription URL looks like:
```text
https://<sub-host>:<sub-port>/<sub-path>/<sub-id>
```
where `<sub-id>` is the client's **Sub ID**.
The same Sub ID is served in several formats on different paths — the **Base64**
list at `subPath` and the **JSON** (Xray-json) config at the JSON path. Build the
URLs and preview both bodies here:
<SubscriptionBuilder />
## Output formats
The **format is chosen by path**, each with its own enable toggle:
| Format | Path | Enabled by | Output |
| --------------------- | --------- | ---------------- | --------------------------------------------------- |
| **Raw links** | `subPath` | always (if on) | A list of `vless://`, `vmess://`, … links (base64-encoded when `subEncrypt` is on). |
| **JSON** | `subJsonPath` | `subJsonEnable` | Full Xray client config(s). |
| **Clash / Mihomo** | `subClashPath` | `subClashEnable` | YAML profile. |
Only enabled inbounds using **VLESS, VMess, Trojan, Shadowsocks, or Hysteria2**
appear in a subscription, ordered by their sub-sort index. Requesting `subPath`
with an `Accept: text/html` header (or `?html=1`) returns a human-readable info
page instead of the raw body.
### Base64 vs JSON
The **Base64** body is just the newline-joined share links, standard-base64
encoded (toggle with `subEncrypt`). The **JSON** body wraps each client in a
complete Xray client config — a fixed skeleton (local SOCKS/HTTP inbounds bound to 127.0.0.1, DNS,
routing, policy) plus a `proxy` outbound pointing at the inbound. 3x-ui emits a
**single config object for one client and an array for several**, uses the flat
outbound `settings` form (`address`/`port`/`id`, `level: 8`), and strips
`sockopt` from `streamSettings`.
## Response headers
Subscriptions return standard headers that compatible apps read:
- **`Subscription-Userinfo`** — `upload`, `download`, `total` (bytes; `total=0`
means unlimited) and `expire` (Unix seconds).
- **`Profile-Update-Interval`** — refresh interval in hours (`subUpdates`).
- **`Profile-Title`**, **`Support-Url`**, **`Profile-Web-Page-Url`**,
**`Announce`** — optional branding shown by some clients.
## Custom page templates
Point `subThemeDir` at a folder containing a custom info-page template to brand
the HTML subscription page. The per-client remark on each link is fully
templated — see [Share links → remark variables](/docs/config/share-links#remark-template-variables).
<Callout type="info">
Put the subscription server behind TLS (set `subCertFile`/`subKeyFile`, or a
[reverse proxy](/docs/operations/reverse-proxy)) so subscription contents
aren't exposed in transit.
</Callout>