subscription.mdx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. ---
  2. title: Subscription
  3. description: Run the 3x-ui subscription server — base64/JSON/Clash formats, ports and paths, TLS, response headers, and custom templates.
  4. icon: Rss
  5. ---
  6. A **subscription** is a single URL that returns all of a client's
  7. configurations. Client apps refresh it periodically, so when you change an
  8. inbound, clients pick up the change automatically. The subscription server runs
  9. as a **separate** server from the panel.
  10. ## Enable and configure
  11. The subscription server is **on by default** (`subEnable`). Configure it in the
  12. panel's subscription settings:
  13. | Setting | Default | Meaning |
  14. | ------------- | ------- | --------------------------------------------------------------- |
  15. | `subPort` | `2096` | Listen port (separate from the panel). |
  16. | `subListen` | _(all)_ | Bind address. |
  17. | `subPath` | _(random per panel)_ | Base path for raw subscription URLs. |
  18. | `subDomain` | _(none)_| Public host; if set, the server only answers for that Host. |
  19. | `subCertFile` / `subKeyFile` | _(none)_ | TLS cert + key — when set, the server serves **HTTPS**. |
  20. | `subEncrypt` | `true` | Base64-encode the raw subscription body. |
  21. | `subUpdates` | `12` | Suggested refresh interval (hours) sent to clients. |
  22. A subscription URL looks like:
  23. ```text
  24. https://<sub-host>:<sub-port>/<sub-path>/<sub-id>
  25. ```
  26. where `<sub-id>` is the client's **Sub ID**.
  27. The same Sub ID is served in several formats on different paths — the **Base64**
  28. list at `subPath` and the **JSON** (Xray-json) config at the JSON path. Build the
  29. URLs and preview both bodies here:
  30. <SubscriptionBuilder />
  31. ## Output formats
  32. The **format is chosen by path**, each with its own enable toggle:
  33. | Format | Path | Enabled by | Output |
  34. | ------------------------------ | ---------------- | ---------------- | --------------------------------------------------- |
  35. | **Raw links** | `subPath` | always (if on) | A list of `vless://`, `vmess://`, … links (base64-encoded when `subEncrypt` is on). |
  36. | **JSON** | `subJsonPath` | `subJsonEnable` | Full Xray client config(s). |
  37. | **Clash / Mihomo** | `subClashPath` | `subClashEnable` | Full Mihomo-compatible YAML profile. |
  38. | **Mihomo (explicit)** | `/mihomo/` | `subClashEnable` | Alias for the full `subClashPath` profile. |
  39. | **Clash for Windows (legacy)** | `/clash-legacy/` | `subClashEnable` | YAML limited to proxy types, transports, and ciphers supported by the legacy Clash core. |
  40. Only enabled inbounds using **VLESS, VMess, Trojan, Shadowsocks, WireGuard, AmneziaWG, MTProto, TUIC, or Hysteria2**
  41. appear in a subscription, ordered by their sub-sort index (TUIC and AmneziaWG are included in raw links and Clash/Mihomo profiles, but omitted from JSON endpoints; MTProto is included in raw links). Requesting `subPath`
  42. with an `Accept: text/html` header (or `?html=1`) returns a human-readable info
  43. page instead of the raw body.
  44. Use `/mihomo/<sub-id>` for Clash Verge Rev, Mihomo, and other maintained
  45. Mihomo-based clients. Use `/clash-legacy/<sub-id>` only for the discontinued
  46. Clash for Windows client. The legacy endpoint keeps compatible VMess, Trojan,
  47. and Shadowsocks nodes and excludes VLESS, Hysteria2, Reality, XHTTP,
  48. HTTPUpgrade, and Shadowsocks 2022. If no compatible node exists, it returns an
  49. explicit `422` response instead of a YAML profile the client cannot import.
  50. To avoid Mihomo-only syntax entering the legacy profile, this endpoint always
  51. uses its minimal `PROXY` group and `MATCH,PROXY` rule and ignores custom Clash
  52. routing settings.
  53. If an administrator has already assigned `/mihomo/` or `/clash-legacy/` to a
  54. different configurable subscription path, that existing path is preserved and
  55. the conflicting alias is skipped with a warning at startup.
  56. Automatic Clash format detection keeps the existing `(?i)(clash|mihomo)`
  57. default matcher so existing subscription URLs continue returning YAML.
  58. It does not distinguish legacy clients from Mihomo-based clients; Clash for
  59. Windows users must use `/clash-legacy/<sub-id>` for a compatible profile.
  60. ### Base64 vs JSON
  61. The **Base64** body is just the newline-joined share links, standard-base64
  62. encoded (toggle with `subEncrypt`). The **JSON** body wraps each client in a
  63. complete Xray client config — a fixed skeleton (local SOCKS/HTTP inbounds bound to 127.0.0.1, DNS,
  64. routing, policy) plus a `proxy` outbound pointing at the inbound. 3x-ui emits a
  65. **single config object for one client and an array for several**, uses the flat
  66. outbound `settings` form (`address`/`port`/`id`, `level: 8`), and strips
  67. `sockopt` from `streamSettings`.
  68. ## Response headers
  69. Subscriptions return standard headers that compatible apps read:
  70. - **`Subscription-Userinfo`** — `upload`, `download`, `total` (bytes; `total=0`
  71. means unlimited) and `expire` (Unix seconds).
  72. - **`Profile-Update-Interval`** — refresh interval in hours (`subUpdates`).
  73. - **`Profile-Title`**, **`Support-Url`**, **`Profile-Web-Page-Url`**,
  74. **`Announce`** — optional branding shown by some clients.
  75. ### Optional month-end expiry display
  76. Under **Subscription → Information**, **Month-end subscription expiry display**
  77. (`subCalendarExpireInclusive`, default `false`) reports the last valid second
  78. of the month in `Subscription-Userinfo` instead of the next month's midnight.
  79. It applies only when every client contributing to the subscription has calendar
  80. renewal day `1`, shares the same fixed expiry, and that expiry is exactly day `1`
  81. at `00:00:00` in the configured panel timezone, immediately after the previous
  82. month's last second. A later repeated midnight during a DST rollback is not
  83. converted. Raw, JSON, Mihomo, and legacy
  84. Clash subscriptions use the same conversion.
  85. For example, the real cutoff `2030-10-01 00:00:00` is presented as
  86. `2030-09-30 23:59:59`. The stored expiry, access cutoff, traffic accounting,
  87. renewal schedule, remark expiry variables, and HTML/JSON info-page cutoff stay
  88. unchanged. Arbitrary times, other renewal days, interval renewal, first-use
  89. durations, unlimited expiries, mixed renewal modes, and different cutoffs are
  90. not converted.
  91. This is an opt-in compatibility tradeoff, not a change to expiry semantics by
  92. default: apps receive a timestamp one second before the real cutoff and may
  93. consider the subscription expired one second early. Apps format it in their own
  94. timezone; matching the panel timezone is needed to display the same month-end
  95. date. Cached subscription information changes only after the app refreshes it.
  96. ## Custom page templates
  97. Point `subThemeDir` at a folder containing a custom info-page template to brand
  98. the HTML subscription page. The per-client remark on each link is fully
  99. templated — see [Share links → remark variables](/docs/config/share-links#remark-template-variables).
  100. <Callout type="info">
  101. Put the subscription server behind TLS (set `subCertFile`/`subKeyFile`, or a
  102. [reverse proxy](/docs/operations/reverse-proxy)) so subscription contents
  103. aren't exposed in transit.
  104. </Callout>