docs: vendor the documentation site into the monorepo

Fold the standalone 3x-ui-docs project (Next.js 16 + Fumadocs, deployed to
docs.sanaei.dev) into docs/ so the panel and its documentation share a single
source of truth, the way sing-box keeps its docs in-tree. The old repo becomes
redundant and can be retired.

- Import the full site under docs/ (app, components, content, lib, public,
  scripts, config). The self-contained pnpm project sits alongside the existing
  engineering notes with no filename collisions.
- Re-point "Edit on GitHub" links from MHSanaei/3x-ui-docs to this repo's
  docs/content/docs path (docs/lib/shared.ts, docs/app/.../page.tsx).
- Add docs-ci.yml and docs-deploy.yml under .github/workflows/, scoped to
  docs/** and run with working-directory: docs, since GitHub only runs
  workflows from the repo-root .github/. deploy-static.yml's GitHub Pages
  publish (CNAME docs.sanaei.dev) carries over unchanged.

Follow-up (outside this commit): attach the docs.sanaei.dev custom domain to
this repository's Pages (or set the Vercel project's root directory to docs),
confirm the site is live from the monorepo, then delete MHSanaei/3x-ui-docs.
This commit is contained in:
MHSanaei
2026-07-07 23:07:14 +02:00
parent 2c49dbf54e
commit 9b91f0f42e
283 changed files with 44179 additions and 0 deletions
+67
View File
@@ -0,0 +1,67 @@
---
title: Clients
description: Manage 3x-ui clients — credentials, traffic and expiry limits, IP limits, groups, bulk actions, external links, and online status.
icon: Users
---
A **client** is a single user, identified by a unique **email**. In the current
panel, clients are first-class records that can be attached to **multiple
inbounds** at once, with per-client traffic accounting.
## Client fields
| Field | Applies to | Meaning |
| -------------- | --------------------- | ------------------------------------------------------------------ |
| **Email** | all | Unique identifier used for accounting and lookups. |
| **ID (UUID)** | VLESS, VMess | The client credential. |
| **Password** | Trojan, Shadowsocks | The client credential. |
| **Auth** | Hysteria2 | The client credential. |
| **Flow** | VLESS | XTLS flow, e.g. `xtls-rprx-vision`. |
| **Limit IP** | all | Max simultaneous source IPs (enforced via Fail2ban). |
| **Total (GB)** | all | Traffic quota; the client is disabled when exhausted. |
| **Expiry** | all | Date after which the client stops working. |
| **Reset** | all | Auto-renew period in **days** (rolls the quota over). |
| **Telegram ID**| all | Links the client to a Telegram user for self-service/notifications.|
| **Sub ID** | all | Subscription identifier grouping this client's links. |
| **Group** | all | Optional client group for organization and bulk filtering. |
| **Comment** | all | Free-text note. |
<Callout type="info">
Reaching the **traffic** or **expiry** limit disables the client; the panel can
restart Xray automatically when clients are auto-disabled
(`restartXrayOnClientDisable`, on by default).
</Callout>
## Limits and IP control
- **Traffic / expiry** caps disable the client when hit; a **Reset** period
auto-renews the quota.
- **Limit IP** caps simultaneous source IPs. Enforcement relies on Fail2ban —
see [Security](/docs/operations/security). You can view a client's recent IPs
and clear them from the client's actions.
- **Online status** and **last-online** times are tracked per client (and per
node in multi-node setups).
## Share links and external links
Every client has share links and a QR code for its inbounds, plus a combined
[subscription](/docs/config/subscription). You can also attach **external
links** to a client — extra `vless://`, `vmess://`, `trojan://`, `ss://`,
`hysteria2://`, or `wireguard://` links, or a remote subscription URL — so they
appear alongside the panel-generated ones in the client's subscription.
To inspect exactly what a link contains, paste it into the
[share-link inspector](/docs/config/share-links).
## Bulk actions
For managing many clients at once, the panel supports bulk **create, enable,
disable, delete, attach/detach** (to inbounds), **reset traffic**, and
**adjust** (add days / add bytes / set flow). Maintenance actions also let you
delete **depleted** clients (quota/expiry exhausted) and **orphaned** clients
(not attached to any inbound).
<Callout type="warn">
A client's share link contains its credential. Treat links and QR codes like
passwords, and rotate the credential if one leaks.
</Callout>
+97
View File
@@ -0,0 +1,97 @@
---
title: Inbounds & Protocols
description: Create inbounds in 3x-ui — protocols, transports, traffic reset and expiry, and fallbacks that serve multiple protocols on one port.
icon: ArrowDownToLine
---
An **inbound** is a listener that accepts client connections on a port using a
particular protocol and transport. Most of your day-to-day work is creating and
managing inbounds and the clients inside them.
## Create an inbound
<Steps>
<Step>
### Add an inbound
Open **Inbounds → Add**, give it a remark, pick a **protocol**, and choose a
**port** and listen address.
</Step>
<Step>
### Choose a transport and security
Pick the transport (TCP, WebSocket, gRPC, HTTPUpgrade, XHTTP, …) and the security
layer (none, TLS, or REALITY). See [Transports](/docs/config/transports) and
[REALITY](/docs/config/reality).
</Step>
<Step>
### Add clients
Add one or more clients, each with its own credential, limits, and share link.
See [Clients](/docs/config/clients).
</Step>
<Step>
### Set traffic limit, expiry, and reset
Optionally cap total traffic and set an expiry date for the inbound, and choose a
periodic **traffic reset** schedule: `never` (default), `hourly`, `daily`,
`weekly`, or `monthly`.
</Step>
</Steps>
## Supported protocols
The inbound editor accepts these protocols:
| Protocol | Notes |
| ---------------------- | ------------------------------------------------------------------------ |
| **VLESS** | Lightweight; the basis for REALITY + XTLS-Vision. Recommended. |
| **VMess** | Older but very widely supported by clients. |
| **Trojan** | TLS-based; supports XTLS and fallbacks. |
| **Shadowsocks** | Includes Shadowsocks-2022 (`2022-blake3-*`) ciphers. |
| **WireGuard** | Modern tunnel. |
| **Hysteria2** | Selected as `hysteria`; the panel emits `hysteria2://` links. |
| **HTTP** | HTTP proxy. |
| **Mixed (SOCKS/HTTP)** | A combined SOCKS + HTTP listener. |
| **Dokodemo-door / Tunnel** | Port forwarding / traffic redirect. |
| **MTProto** | Telegram MTProto proxy, served by a bundled `mtg` process (not Xray). |
<Callout type="info">
Hysteria2 isn't a separate protocol internally — it's the `hysteria` protocol
with the transport version set to 2, and the panel generates `hysteria2://`
share links for it.
</Callout>
## Fallbacks — multiple protocols on one port
Fallbacks let a single TLS port (e.g. `443`) serve more than one protocol — for
example VLESS **and** Trojan — by routing unmatched handshakes to a child
inbound. In 3x-ui, fallbacks are managed in the panel (a master inbound's
**Fallbacks** list) rather than hand-written into JSON.
Fallbacks are available only when the master inbound is:
- **VLESS** or **Trojan**,
- on the raw **TCP** transport,
- with **TLS** or **REALITY** security.
Each fallback rule targets a child inbound and can match on `path`, `alpn`, and
`dest`. Client share links for a fallback child are automatically rewritten to
advertise the master's address, port, and TLS.
## Not sure which to pick?
Use the wizard to get a recommendation based on your goals and clients:
<ProtocolWizard />
<Callout type="info">
For censorship resistance with modern clients, **VLESS + REALITY +
XTLS-Vision** is the usual best choice — continue to
[REALITY](/docs/config/reality).
</Callout>
+14
View File
@@ -0,0 +1,14 @@
{
"title": "Configuration",
"icon": "Settings",
"pages": [
"panel",
"ssl-certificates",
"inbounds",
"reality",
"transports",
"clients",
"subscription",
"share-links"
]
}
+77
View File
@@ -0,0 +1,77 @@
---
title: Panel Settings
description: Every 3x-ui panel setting — web server, TLS, display, security, and notifications — with defaults from the source.
icon: SlidersHorizontal
---
**Panel Settings** controls how the panel itself is served and secured (separate
from your inbounds and clients). Settings are stored as key/value pairs; the
defaults below come straight from the panel source. Secrets (tokens, passwords)
are shown only as a "set / not set" indicator and are never returned to the
browser in full.
## Web server
| Setting | Default | Meaning |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | Panel port (165535). The `XUI_PORT` env var overrides it at runtime. |
| `webListen` | _(all interfaces)_ | Bind the panel to a specific IP. |
| `webBasePath` | `/` | URL path the panel is served under (always normalized to `/…/`). |
| `webCertFile` / `webKeyFile` | _(none)_ | TLS certificate + key. When both are set, the panel serves **HTTPS**. |
| `sessionMaxAge` | `360` | Session lifetime in **minutes** (default 6 hours). |
| `trustedProxyCIDRs` | `127.0.0.1/32,::1/128` | IPs/CIDRs whose forwarded headers (real client IP) are trusted. |
| `panelOutbound` | _(none)_ | Route the panel's own egress (update checks, Telegram, geo/sub fetches) through a named Xray outbound. |
After changing the port or base path, the panel URL becomes
`http(s)://<server>:<port><web-base-path>`. You can preset the base path on first
launch with [`XUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars).
### TLS
Serving the panel over HTTPS protects your credentials in transit. Either set
`webCertFile` + `webKeyFile` — the [`x-ui` SSL menu](/docs/config/ssl-certificates)
can obtain a Let's Encrypt certificate for you — or terminate TLS at a
[reverse proxy](/docs/operations/reverse-proxy).
<Callout type="warn">
Never expose the panel over plain HTTP on the public internet. Use TLS, a
non-default port, and a long random web base path.
</Callout>
## Display
| Setting | Default | Meaning |
| ---------------- | ------------------------------------------------ | ------------------------------------------------------------- |
| `pageSize` | `25` | Rows per page in lists (`0` disables pagination). |
| `expireDiff` | `0` | Days before expiry to start warning. |
| `trafficDiff` | `0` | Percent of quota remaining at which to start warning. |
| `remarkTemplate` | `{{INBOUND}}-{{EMAIL}}\|📊{{TRAFFIC_LEFT}}\|⏳{{DAYS_LEFT}}D` | Default client remark template (see [Share links](/docs/config/share-links#remark-template-variables)). |
| `timeLocation` | `Local` | Time zone for stats and expiry. |
| `datepicker` | `gregorian` | Calendar for date inputs (Gregorian or Jalali/Persian). |
## Security & authentication
Credentials, two-factor auth, the brute-force limiter, sessions, and LDAP are
covered in [First login](/docs/guide/first-login) and
[Security](/docs/operations/security). In short:
- Passwords are stored as **bcrypt** hashes; changing them logs out all sessions.
- **2FA (TOTP)** can be required at login.
- An **LDAP** fallback can authenticate users when the local password check fails.
- API access uses **API tokens** managed under Panel Settings (see the
[API reference](/docs/reference/api/api-tokens)).
## Notifications & subscription
These have their own settings groups and pages:
<Cards>
<Card title="Telegram bot" href="/docs/operations/telegram-bot" description="Token, chat IDs, alerts, and reports." />
<Card title="Subscription" href="/docs/config/subscription" description="Subscription server, formats, and paths." />
<Card title="Security" href="/docs/operations/security" description="2FA, IP limits, and hardening." />
</Cards>
<Callout type="info">
Email (SMTP) notifications are also configurable (host, port, encryption,
recipients) with the same event types as the Telegram bot.
</Callout>
+135
View File
@@ -0,0 +1,135 @@
---
title: REALITY
description: Set up a VLESS + REALITY inbound with XTLS-Vision in 3x-ui — keys, short IDs, SNI, fingerprints, and common pitfalls.
icon: ShieldCheck
---
**REALITY** is an Xray transport security that disguises your proxy as ordinary
traffic to a real, popular website. Unlike classic TLS, your server needs **no
certificate of its own** — it borrows the TLS handshake of the target site
(`dest`). Combined with the **XTLS-Vision** flow, it is fast and resistant to
deep-packet inspection.
REALITY is used with **VLESS** (and Trojan). The recommended flow is
`xtls-rprx-vision`.
## Key settings
When you choose **REALITY** as the security mode on a VLESS inbound, 3x-ui
exposes these fields:
| Field | What it is |
| ------------------------ | ------------------------------------------------------------------ |
| **Dest (target)** | A real TLS site to impersonate, e.g. `www.microsoft.com:443`. |
| **SNI / Server Names** | The hostname(s) clients send; must match the target's certificate. |
| **Public / Private key** | An **x25519** keypair. The private key stays on the server. |
| **Short IDs** | Hex strings used to authenticate clients (you can have several). |
| **Flow** | Set to `xtls-rprx-vision`. |
| **Fingerprint (uTLS)** | The client TLS fingerprint to mimic, e.g. `chrome`. |
The private key is generated with Xray's `x25519` utility (the panel can
generate the pair for you):
```bash title="generate an x25519 keypair"
xray x25519
```
## Set it up in the panel
<Steps>
<Step>
### Create a VLESS inbound
Add a new inbound, choose protocol **VLESS**, and set **Security** to
**reality**.
</Step>
<Step>
### Choose a target (dest) and SNI
Pick a reputable site that supports TLS 1.3 and HTTP/2 and is reachable from your
server and your clients (for example `www.microsoft.com:443`). Set the server
names / SNI to match that site's certificate.
</Step>
<Step>
### Generate keys and short IDs
Generate the x25519 keypair and one or more short IDs. Keep the **private key**
secret; clients only ever receive the **public key**.
</Step>
<Step>
### Set the flow and fingerprint
Use the `xtls-rprx-vision` flow and a common uTLS fingerprint such as `chrome`.
</Step>
<Step>
### Add a client and share the link
Create a client, then use its share link or QR code in a compatible app
(v2rayNG, Hiddify, Mihomo, and others).
</Step>
</Steps>
## What the configuration looks like
On the server, a REALITY inbound's `streamSettings` looks roughly like this:
```json title="server inbound (excerpt)"
{
"network": "tcp",
"security": "reality",
"realitySettings": {
"dest": "www.microsoft.com:443",
"serverNames": ["www.microsoft.com"],
"privateKey": "<x25519 private key>",
"shortIds": ["<hex short id>"],
"fingerprint": "chrome"
}
}
```
The matching client share link carries the **public** parameters:
```text title="vless:// (excerpt)"
vless://<uuid>@<server>:443?security=reality&pbk=<public-key>&sid=<short-id>&sni=www.microsoft.com&fp=chrome&spx=%2F&flow=xtls-rprx-vision#my-reality
```
- `pbk` — REALITY **public** key
- `sid` — short ID (matches one on the server)
- `sni` — server name (matches the target's certificate)
- `fp` — client fingerprint
- `spx` — spiderX path
- `flow` — `xtls-rprx-vision`
## Common pitfalls
<Callout type="warn">
- **Bad target.** The `dest` must be a real site that supports **TLS 1.3** and
**HTTP/2**, is reachable, and isn't blocked in your region. Pick a site you do
not own and that sees lots of traffic.
- **SNI mismatch.** The SNI / server names must match the target's real
certificate, or the handshake gives the disguise away.
- **Leaked private key.** Only ever distribute the **public** key to clients.
- **Wrong flow.** REALITY + XTLS-Vision needs `flow = xtls-rprx-vision` on both
the inbound client entry and the share link.
</Callout>
## Generate a config
Use the generator below to create a fresh X25519 keypair, UUID, and short ID,
then copy the server inbound JSON and the client share link. Everything is
computed **in your browser** — no keys or links are sent anywhere.
<RealityConfigGenerator />
<Callout type="info">
The **private key** belongs only on your server. Share the generated
`vless://` link (which contains the **public** key) with clients.
</Callout>
@@ -0,0 +1,82 @@
---
title: Share Links
description: 3x-ui share-link formats (vless, vmess, trojan, ss, hysteria2, mtproto), the remark template variables, and an in-browser link inspector.
icon: Link
---
3x-ui generates a **share link** (and QR code) for each client. Client apps such
as v2rayNG, Hiddify, and Mihomo import these links to configure themselves.
## Link formats
| Scheme | Shape |
| -------------- | --------------------------------------------------------------- |
| `vless://` | `vless://<uuid>@<host>:<port>?<params>#<remark>` |
| `vmess://` | `vmess://<base64-json>` (a base64-encoded JSON object) |
| `trojan://` | `trojan://<password>@<host>:<port>?<params>#<remark>` |
| `ss://` | `ss://<userinfo>@<host>:<port>?<params>#<remark>` (SIP002; Shadowsocks-2022 uses percent-encoded userinfo) |
| `hysteria2://` | `hysteria2://<auth>@<host>:<port>?<params>#<remark>` |
| `tg://proxy` | `tg://proxy?server=…&port=…&secret=…` (MTProto) |
The query parameters carry the transport and security settings — `security`,
`sni`, `fp`, `pbk`, `sid`, `spx`, `flow`, `type`, `path`, `host`, `alpn`, and
more.
## Inspect a link
Paste any share link to decode every field. Parsing happens **entirely in your
browser** — the link is never sent over the network.
<ShareLinkInspector />
<Callout type="warn">
Share links contain everything needed to connect as a client, including the
client's credential. Treat them like passwords.
</Callout>
## Remark template variables
The text after `#` in each link (the **remark**) is generated from a template
you control in Panel Settings (`remarkTemplate`). The default is:
```text
{{INBOUND}}-{{EMAIL}}|📊{{TRAFFIC_LEFT}}|⏳{{DAYS_LEFT}}D
```
Tokens use `{{UPPER_CASE}}` syntax. The template is split on `|` into segments;
a segment whose only value is the unlimited marker `∞` (for `TRAFFIC_LEFT`,
`TRAFFIC_TOTAL`, `DAYS_LEFT`, or `TIME_LEFT`) is dropped, so unlimited clients
don't show empty decorations.
### Available tokens
| Token | Value |
| ----- | ----- |
| `{{EMAIL}}` / `{{USERNAME}}` | Client email (identifier) |
| `{{INBOUND}}` | Inbound remark |
| `{{HOST}}` | Host-row remark (managed hosts) |
| `{{ID}}` / `{{SHORT_ID}}` | Client UUID / its first 8 chars |
| `{{TELEGRAM_ID}}` · `{{SUB_ID}}` · `{{COMMENT}}` | Telegram ID, subscription ID, comment |
| `{{STATUS}}` / `{{STATUS_EMOJI}}` | `active`/`expired`/`depleted`/`disabled` (or ✅⏳🚫) |
| `{{DAYS_LEFT}}` / `{{TIME_LEFT}}` | Days, or `Xd Xh Xm`, remaining (`∞` if unlimited) |
| `{{EXPIRE_DATE}}` / `{{JALALI_EXPIRE_DATE}}` / `{{EXPIRE_UNIX}}` | Expiry as Gregorian / Jalali date / Unix seconds |
| `{{CREATED_UNIX}}` | Creation time (Unix seconds) |
| `{{TRAFFIC_USED}}` / `{{TRAFFIC_LEFT}}` / `{{TRAFFIC_TOTAL}}` | Human-readable usage (`∞` if unlimited) |
| `{{TRAFFIC_USED_BYTES}}` / `{{TRAFFIC_LEFT_BYTES}}` / `{{TRAFFIC_TOTAL_BYTES}}` | Same, in bytes |
| `{{UP}}` / `{{DOWN}}` | Upload / download (human-readable) |
| `{{RESET_DAYS}}` · `{{USAGE_PERCENTAGE}}` | Reset period (days) · used percent |
| `{{PROTOCOL}}` / `{{TRANSPORT}}` / `{{SECURITY}}` | e.g. `VLESS` / `ws` / `REALITY` |
<Callout type="info">
Usage tokens (traffic, days, status) appear in the subscription **body** but
are stripped from the display/QR view, so a shared QR doesn't leak a client's
remaining quota. Date tokens follow the `datepicker` setting (Gregorian or
Jalali).
</Callout>
## Related
<Cards>
<Card title="REALITY" href="/docs/config/reality" description="Generate a VLESS + REALITY config and link." />
<Card title="Subscription" href="/docs/config/subscription" description="Serve all of a client's links from one URL." />
</Cards>
@@ -0,0 +1,181 @@
---
title: SSL Certificates
description: Get and renew TLS certificates for the 3x-ui panel and inbounds — with the x-ui ACME menu (domain or bare IP), a Cloudflare DNS-01 wildcard, or manual Certbot.
icon: ShieldCheck
---
A TLS certificate lets you serve the **panel** over HTTPS (so your login and API
traffic are encrypted) and terminate TLS on **inbounds** (VLESS-TLS, Trojan,
Shadowsocks-TLS, and friends). There are three ways to obtain one:
- **The `x-ui` menu** — built-in [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment)
client. Easiest for a single domain or a bare IP.
- **Cloudflare DNS-01** — also from the menu; needed for **wildcard** certs or
when port 80 is blocked / the server sits behind Cloudflare's proxy.
- **Manual Certbot** — if you'd rather manage `acme.sh`/Certbot yourself.
<Callout type="info">
If you put the panel behind Nginx or Caddy, let the proxy handle the
certificate instead — see [Reverse proxy](/docs/operations/reverse-proxy).
[REALITY](/docs/config/reality) inbounds need **no** certificate at all; they
borrow a real site's TLS. This page is for the panel and for classic TLS
inbounds.
</Callout>
## The `x-ui` SSL menu (Let's Encrypt)
Run `x-ui` and choose **`20` — SSL Certificate Management**. It drives
[acme.sh](https://github.com/acmesh-official/acme.sh) and offers:
| Option | What it does |
| ------------------------------ | ------------------------------------------------------------------- |
| Get SSL (Domain) | Issue a certificate for a domain via HTTP validation. |
| Get SSL for IP Address | Issue a short-lived (6-day, auto-renewing) cert for a **bare IP**. |
| Revoke | Revoke an existing certificate. |
| Force Renew | Renew now, before expiry. |
| Show Existing Domains | List certificates already on the server. |
| Set Cert paths for the panel | Point the panel's TLS at an issued cert (sets the fields for you). |
### Issue a certificate for a domain
<Steps>
<Step>
### Point the domain at the server
Create an `A` (and/or `AAAA`) record for your domain that resolves to this
server's public IP. Validation fails until DNS has propagated.
</Step>
<Step>
### Free up port 80
HTTP validation needs **port 80** reachable from the internet and not already in
use. Stop anything bound to it for the duration, and allow it through the
[firewall](/docs/reference/ports-firewall).
</Step>
<Step>
### Run the issuer
`x-ui` → `20` → **Get SSL (Domain)**, then enter the domain. acme.sh requests
the certificate and saves it under `/root/cert/<domain>/` as `fullchain.pem`
(the certificate chain) and `privkey.pem` (the private key).
</Step>
<Step>
### Wire it into the panel
Choose **Set Cert paths for the panel** to fill in `webCertFile` and
`webKeyFile` and restart the panel, or set them yourself in
[Panel Settings](/docs/config/panel#tls). The panel serves HTTPS as soon as both
are set.
</Step>
</Steps>
### Issue a certificate for a bare IP
No domain? Choose **Get SSL for IP Address** to obtain a short-lived
certificate (valid ~6 days, renewed automatically) bound to the server's IP.
Useful for reaching the panel over HTTPS before you've set up a domain.
## Cloudflare (DNS-01 wildcard)
DNS validation proves you control the domain by creating a TXT record instead of
answering on port 80 — so it works **behind Cloudflare's proxy**, on servers
where port 80 is blocked, and for **wildcard** certificates (`*.example.com`).
Your domain's DNS must be managed by Cloudflare, and you need one of:
- a **scoped API token** with the `Zone:DNS:Edit` permission (recommended), or
- your account **email + Global API Key**.
<Steps>
<Step>
### Create a scoped API token
In the Cloudflare dashboard go to **My Profile → API Tokens →
[Create Token](https://dash.cloudflare.com/profile/api-tokens)**, pick the
**Edit zone DNS** template, scope it to the zone you're issuing for, and create
it. Copy the token — it's shown only once.
</Step>
<Step>
### Run the Cloudflare issuer
`x-ui` → **`21` — Cloudflare SSL Certificate**. When asked, choose **`t`** for an
API token (the default) or **`g`** for the Global API Key, then enter your
domain (and, for the Global API Key, your account email and key). acme.sh creates
the TXT record, validates, and cleans it up.
</Step>
<Step>
### Point the panel at it
As with the domain flow, use **Set Cert paths for the panel** (menu `20`) or set
`webCertFile` / `webKeyFile` in [Panel Settings](/docs/config/panel#tls).
</Step>
</Steps>
<Callout type="info">
Prefer a scoped token over the Global API Key — it only grants DNS edits on the
zone you choose, so a leak can't touch the rest of your Cloudflare account.
</Callout>
## Manual (Certbot)
If you'd rather not use the menu, issue a certificate with Certbot's standalone
plugin (again, this needs port 80 free and the domain resolving to the server):
```bash
apt-get install certbot -y
certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com
certbot renew --dry-run
```
Certbot writes the certificate to `/etc/letsencrypt/live/yourdomain.com/`
(`fullchain.pem` and `privkey.pem`). Point the panel at those two files in
[Panel Settings](/docs/config/panel#tls), and set up renewal — `certbot renew`
runs on a systemd timer by default.
## Using the certificate
- **Panel** — set `webCertFile` (the full chain) and `webKeyFile` (the private
key) in [Panel Settings](/docs/config/panel#tls). Both must be set for the
panel to switch to HTTPS. Menu option **`11` — View Current Settings** prints
the paths currently in use.
- **Inbounds** — when you enable TLS on an inbound, reference the same
certificate and key files (or paste their contents) in the inbound's TLS
settings. See [Inbounds](/docs/config/inbounds) and
[Transports](/docs/config/transports).
<Callout type="warn">
Certificates expire (Let's Encrypt: 90 days; IP certs: ~6 days). The menu and
Certbot both renew automatically, but the panel keeps reading the **files** at
their fixed paths — so renew **in place** rather than moving the files, and the
panel picks up the new cert on its next restart. **Force Renew** (menu `20`)
triggers a renewal on demand.
</Callout>
## Next steps
<Cards>
<Card
title="Panel Settings"
href="/docs/config/panel#tls"
description="webCertFile / webKeyFile and the rest of the web-server settings."
/>
<Card
title="Reverse proxy"
href="/docs/operations/reverse-proxy"
description="Let Nginx or Caddy terminate TLS for you instead."
/>
<Card
title="REALITY"
href="/docs/config/reality"
description="Stealth TLS for inbounds — no certificate required."
/>
</Cards>
@@ -0,0 +1,86 @@
---
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` | `/sub/` | 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/<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** | `/sub/` | always (if on) | A list of `vless://`, `vmess://`, … links (base64-encoded when `subEncrypt` is on). |
| **JSON** | `/json/` | `subJsonEnable` | Full Xray client config(s). |
| **Clash / Mihomo** | `/clash/` | `subClashEnable` | YAML profile. |
Only enabled inbounds using **VLESS, VMess, Trojan, Shadowsocks, or Hysteria2**
appear in a subscription, ordered by their sub-sort index. Requesting `/sub/`
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 mixed/HTTP inbounds, 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>
+199
View File
@@ -0,0 +1,199 @@
---
title: Transports & Security
description: Every transport 3x-ui exposes — TCP, mKCP, WebSocket, gRPC, HTTPUpgrade, XHTTP, Hysteria — with their settings, plus FinalMask obfuscation, sockopt, TLS/REALITY, XTLS-Vision, and VLESS encryption.
icon: Network
---
A **transport** decides how packets are carried between client and server, a
**security** layer decides how they're encrypted and disguised, and **FinalMask**
can obfuscate what's left. The panel only offers valid combinations; this page
lists every transport's settings and the rules the panel enforces.
## Transports
Pick the transport (the inbound's `network`) in the inbound/outbound form. Each
network writes its own settings key on the wire (`tcpSettings`, `kcpSettings`, …).
| Transport | Settings key | When to use it |
| --------------- | --------------------- | ---------------------------------------------------------------------- |
| **TCP (Raw)** | `tcpSettings` | Lowest overhead. The basis for REALITY + XTLS-Vision and fallbacks; optional HTTP/1.1 header camouflage. |
| **mKCP** | `kcpSettings` | Reliable protocol over **UDP** — trades bandwidth for lower latency on lossy links. Carries no TLS/REALITY. |
| **WebSocket** | `wsSettings` | Works through CDNs and HTTP reverse proxies; very compatible. |
| **gRPC** | `grpcSettings` | HTTP/2-based; multiplexes well and proxies cleanly through Nginx. |
| **HTTPUpgrade** | `httpupgradeSettings` | CDN-friendly HTTP/1.1 `Upgrade`; lighter than full WebSocket. |
| **XHTTP** | `xhttpSettings` | Modern stream-multiplexed HTTP transport; CDN-friendly and REALITY-capable. |
| **Hysteria** | `hysteriaSettings` | QUIC-based transport — only for the **Hysteria2** protocol. |
<Callout type="info">
**WireGuard** and **Tunnel** (dokodemo-door) inbounds expose no transport
selector — their stream carries only security/sockopt. Earlier panels also
exposed a raw **HTTP/2 (`http`)** transport; it has been superseded by **XHTTP**
and is no longer selectable.
</Callout>
### TCP (Raw) — `tcpSettings`
| Field | Default | Meaning |
| ------------------------------ | ------- | ----------------------------------------------------------------------- |
| `acceptProxyProtocol` | `false` | Accept the PROXY protocol from an upstream proxy so the real client IP is preserved. |
| `header.type` | `none` | `none`, or `http` for HTTP/1.1 camouflage. |
| `header.request` / `response` | — | When `type: http`: method, path, version and a header map that mimic a normal HTTP exchange. |
### mKCP — `kcpSettings`
| Field | Default | Meaning |
| ------------------ | ----------- | ---------------------------------------------------------------- |
| `mtu` | `1350` | Maximum transmission unit, in bytes (5761460). |
| `tti` | `20` | Transmission time interval, in ms (10100). Lower = more responsive, more overhead. |
| `uplinkCapacity` | `5` | Upload bandwidth budget, in **MB/s**. |
| `downlinkCapacity` | `20` | Download bandwidth budget, in **MB/s**. |
| `cwndMultiplier` | `1` | Congestion-window multiplier; raise to push harder on good links. |
| `maxSendingWindow` | `2097152` | Upper bound on in-flight packets. |
<Callout type="info">
mKCP can't carry TLS or REALITY. To disguise it, add a **FinalMask** UDP mask —
the `mkcp-legacy` mask reproduces the classic header obfuscation that older Xray
stored in `kcpSettings.header`/`seed` (those fields no longer exist here).
</Callout>
### WebSocket — `wsSettings`
| Field | Default | Meaning |
| --------------------- | ------- | ---------------------------------------------------------------- |
| `path` | `/` | Request path — route on it when several services share one host. |
| `host` | _(none)_| `Host` header override (useful behind a CDN). |
| `headers` | `{}` | Extra request headers. |
| `heartbeatPeriod` | `0` | Seconds between keepalive pings; `0` disables them. |
| `acceptProxyProtocol` | `false` | Accept the PROXY protocol from an upstream. |
### gRPC — `grpcSettings`
| Field | Default | Meaning |
| ------------- | ------- | --------------------------------------------------------- |
| `serviceName` | _(none)_| gRPC service path; acts like a secret route. |
| `authority` | _(none)_| `:authority` pseudo-header override. |
| `multiMode` | `false` | Multiplex several streams over one connection. |
### HTTPUpgrade — `httpupgradeSettings`
| Field | Default | Meaning |
| --------------------- | ------- | --------------------------------------------- |
| `path` | `/` | Request path. |
| `host` | _(none)_| `Host` header override. |
| `headers` | `{}` | Extra request headers. |
| `acceptProxyProtocol` | `false` | Accept the PROXY protocol from an upstream. |
HTTPUpgrade is a one-shot HTTP/1.1 `Upgrade` with no WebSocket framing — there's
no heartbeat field.
### XHTTP — `xhttpSettings`
XHTTP (SplitHTTP) has a large field set; the panel fills sensible defaults. The
ones you'll usually touch:
| Field | Default | Meaning |
| ---------------------- | ----------- | ---------------------------------------------------------------------- |
| `path` | `/` | Request path. |
| `host` | _(none)_ | `Host` header override. |
| `mode` | `auto` | `auto`, `packet-up`, `stream-up`, or `stream-one`. `packet-up` is the most CDN-compatible; `stream-*` are lower latency. |
| `xPaddingBytes` | `100-1000` | Random padding range that blurs packet sizes. |
| `scMaxBufferedPosts` | `30` | Server-side buffer for uploaded POSTs. |
| `scStreamUpServerSecs` | `20-80` | Stream-up server window (dash range). |
| `xmux` (`enableXmux`) | _(off)_ | Connection multiplexing — `maxConcurrency` `16-32`, `maxConnections` `6`, … Turn on for high concurrency. |
Session-ID fields (`sessionIDPlacement`, `sessionIDKey`, `sessionIDTable`,
`sessionIDLength`) and the `scMin/MaxEachPostBytes` knobs are advanced; leave them
empty unless you're matching a specific upstream.
### Hysteria — `hysteriaSettings`
Only valid when the protocol is **Hysteria2**.
| Field | Default | Meaning |
| ---------------- | ------- | ----------------------------------------------------------------------- |
| `version` | `2` | Hysteria protocol version. |
| `auth` | _(none)_| Shared authentication string. |
| `udpIdleTimeout` | `60` | Seconds (2600) before idle UDP sessions are dropped. |
| `masquerade` | — | Disguise as an HTTP/3 server: `type` `proxy`/`file`/`string` with `url`/`dir`/`content`, plus `headers` and `statusCode`. |
## FinalMask — late-layer obfuscation
**FinalMask** wraps traffic **after** the transport and security layers, so it can
disguise transports that don't carry TLS (like mKCP) or add a second skin on top of
TLS. Masks are configured per direction:
- **TCP masks** — `fragment`, `sudoku`, `header-custom`.
- **UDP masks** — `salamander`, `mkcp-legacy`, `header-custom`, `xdns`, `xicmp`,
`noise`, `sudoku`, `realm`. (`mkcp-legacy` reproduces the old mKCP header
obfuscation.)
- **QUIC params** — congestion control (`reno`, `bbr`, `brutal`, `force-brutal`),
Brutal up/down rates, `udpHop` (rotate the QUIC port across a range to dodge
port blocking), and receive-window tuning.
FinalMask replaces the per-transport `header`/`seed` obfuscation that older Xray
builds exposed.
## sockopt — low-level socket options
`sockopt` rides alongside any transport and tunes the underlying socket. The most
useful fields:
| Field | Default | Meaning |
| --------------------- | ------- | ---------------------------------------------------------------- |
| `tcpFastOpen` | `false` | Enable TCP Fast Open. |
| `tcpcongestion` | `bbr` | Congestion control: `bbr`, `cubic`, or `reno`. |
| `tproxy` | `off` | Transparent proxy mode: `off`, `redirect`, or `tproxy`. |
| `domainStrategy` | `AsIs` | How addresses resolve (`UseIP`, `ForceIPv4`, …). |
| `dialerProxy` | _(none)_| Chain this outbound's dialing through another outbound tag. |
| `interface` | _(none)_| Bind to a specific network interface. |
| `mark` | `0` | SO_MARK for policy routing (`0` = unset). |
Numeric fields left at `0` are omitted on the wire so Xray keeps OS defaults.
Advanced entries (`happyEyeballs`, `customSockopt[]`, keepalive timers) are
available for special cases.
## Security
The security layer is one of **`none`**, **`tls`**, or **`reality`**, with these
eligibility rules:
| Security | Eligible transports | Eligible protocols |
| ----------- | -------------------------------------------- | --------------------------------------------------- |
| **TLS** | `tcp`, `ws`, `grpc`, `httpupgrade`, `xhttp` | VLESS, VMess, Trojan, Shadowsocks (Hysteria2 is always TLS) |
| **REALITY** | `tcp`, `grpc`, `xhttp` | VLESS, Trojan |
mKCP and Hysteria don't take a separate TLS/REALITY layer — mKCP runs plaintext
(obfuscate with FinalMask), and Hysteria is QUIC/TLS by design. REALITY disguises
your server as a real TLS site and needs no certificate — see
[REALITY](/docs/config/reality).
## XTLS-Vision flow
The `xtls-rprx-vision` flow is fast and DPI-resistant. It's available for
**VLESS** when either:
- the transport is raw **TCP** with **TLS** or **REALITY** security (classic
XTLS-Vision), or
- the transport is **XHTTP** with VLESS encryption enabled (see below).
Set the flow on the VLESS **client**, not the inbound. With classic Vision on
TCP, the panel can also offer a **Vision seed** once a client uses the flow.
## VLESS encryption (ML-KEM)
VLESS supports post-quantum **encryption** (ML-KEM / `mlkem768x25519`), stored in
the inbound's `decryption` (server) and clients' `encryption` (for link
generation). When enabled, it unlocks the Vision flow over XHTTP. Generate the
keys from the panel's VLESS settings.
## Shadowsocks ciphers
Shadowsocks inbounds support both classic ciphers and **Shadowsocks-2022**
(method names starting with `2022-blake3-`). Most ciphers are multi-user;
`2022-blake3-chacha20-poly1305` is single-user.
<Callout type="info">
Transports and security must match on both ends. The client's share link
encodes them (`type=ws`, `security=reality`, `flow=xtls-rprx-vision`, …) —
decode any link with the [share-link inspector](/docs/config/share-links).
</Callout>
+124
View File
@@ -0,0 +1,124 @@
---
title: First Login
description: Find your generated 3x-ui credentials, reach the panel, enable two-factor auth, and harden it before exposing anything.
icon: KeyRound
---
After installation, your first job is to log in and **secure the panel** before
exposing anything else.
## Reach the panel
The panel is served at:
```text
http://<your-server-ip>:<port>/<web-base-path>
```
The default port is **2053** and the default base path is `/` — but a script
install **randomly generates** the username, password, **port**, and web base
path, so check your actual values.
### Find your credentials
A script install prints a credential summary when it finishes and also writes it
to a root-only file:
```bash title="/etc/x-ui/install-result.env (mode 600)"
XUI_USERNAME=...
XUI_PASSWORD=...
XUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=...
XUI_API_TOKEN=...
XUI_DB_TYPE=sqlite
```
If you missed them, use the management tools:
```bash
x-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form
```
For **Docker**, read the generated credentials from the container logs, or run
`docker exec -it <container> x-ui setting -show`.
<Callout type="warn">
If your panel still uses the default `admin` / `admin` (the panel warns when it
does), change it immediately — before creating any inbounds.
</Callout>
## Change credentials, port, and path
A non-default port and a long, random **web base path** make the panel much
harder to find. Change them from **Panel Settings** in the UI, or from the
`x-ui` menu:
- **7 — Reset Username & Password** (optionally disabling 2FA at the same time)
- **8 — Reset Web Base Path** (randomizes it)
- **10 — Change Port**
Changing your username or password **logs out all existing sessions** and, if
two-factor auth was on, disables it.
## Two-factor authentication (2FA)
3x-ui supports TOTP two-factor auth (compatible with Google Authenticator, Aegis,
etc.). Enable it in **Panel Settings** — once enabled, the login page asks for a
6-digit code in addition to your password, and turning it on forces everyone to
log in again. You can disable it from the menu's **Reset Username & Password**
step or with `x-ui setting -resetTwoFactor`.
## Built-in login protection
- **Brute-force limiter:** after **5** failed logins from the same IP/username
within 5 minutes, that combination is blocked for **15 minutes**.
- **Generic errors:** the login page reports "wrong username or password" for
both bad credentials and bad 2FA codes, so it leaks nothing.
- **Sessions** last `sessionMaxAge` minutes (default **360** = 6 hours) and are
invalidated when you change credentials.
- **LDAP** can be enabled as an auth fallback in Panel Settings.
## Essential hardening checklist
<Steps>
<Step>
### Set strong, unique credentials
Replace the generated (or `admin/admin`) username and password with strong values.
</Step>
<Step>
### Use a non-default port and random base path
Move the panel off `2053` and serve it under a long random path.
</Step>
<Step>
### Enable two-factor authentication
Turn on 2FA so a leaked password alone can't grant access.
</Step>
<Step>
### Put the panel behind TLS
Use a valid certificate (via the `x-ui` menu's SSL management, or a reverse
proxy) so the panel is only reachable over HTTPS.
</Step>
<Step>
### Restrict access with a firewall
Open only the ports you actually need, and consider limiting panel access by IP.
</Step>
</Steps>
<Callout type="info">
Want the panel on a clean domain with automatic HTTPS? See
[Reverse proxy](/docs/operations/reverse-proxy). For deeper hardening, see
[Security](/docs/operations/security).
</Callout>
+71
View File
@@ -0,0 +1,71 @@
---
title: Meet 3x-ui
description: A web panel for Xray-core — manage inbounds, protocols, clients, and subscriptions from your browser instead of editing JSON by hand.
icon: Info
---
**3x-ui** is a web control panel that sits on top of
[Xray-core](https://github.com/XTLS/Xray-core), the proxy engine that actually
moves your traffic. Instead of writing and reloading Xray's JSON configuration
by hand, you manage everything — inbounds, protocols, clients, certificates,
subscriptions — from a browser dashboard.
## How the pieces fit together
<Mermaid
chart={`
flowchart LR
Admin["Admin browser"] -->|HTTPS panel| Panel["3x-ui panel"]
Panel -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
Xray -->|proxied traffic| Internet["Internet"]
`}
/>
- **The panel** is the management layer: it stores your configuration in a
database, renders the dashboard, exposes a REST API, and writes the live Xray
configuration.
- **Xray-core** is the data plane: it terminates client connections on your
**inbounds** and forwards traffic to its destination.
- **Client apps** (such as v2rayNG, Clash/Mihomo, Hiddify, and others) connect
using a share link or a subscription that the panel generates for each client.
## What it gives you
- A dashboard for **inbounds** across every major protocol — VLESS, VMess,
Trojan, Shadowsocks, WireGuard, Hysteria2, SOCKS, HTTP, and Dokodemo-door.
- First-class **REALITY** and **XTLS-Vision** support for stealthy, fast
transports.
- **Per-client** traffic quotas, expiry dates, IP limits, online status, and
one-click share links / QR codes.
- **Subscriptions** in VLESS, Clash/Mihomo, and JSON formats.
- Operational tooling: **multi-node** management, a **Telegram bot**, backups,
Fail2ban-based IP limiting, and a documented REST API.
## Under the hood
| Layer | Technology |
| ------------ | -------------------------------------------- |
| Backend | Go with the Gin web framework |
| Frontend | TypeScript / React |
| Database | SQLite (default) or PostgreSQL |
| Proxy engine | Xray-core (bundled and managed by the panel) |
The default SQLite database lives at `/etc/x-ui/x-ui.db`, and the panel listens
on port **2053** by default. Both are configurable — see
[First login](/docs/guide/first-login) and the environment variable reference.
## Who it's for
3x-ui is aimed at anyone running their own Xray server: from a single personal
VPS to operators managing many nodes and clients. If you want the power of
Xray-core without living in JSON config files, this is for you.
<Callout type="info">
3x-ui is an enhanced fork of the original X-UI project, adding broader protocol
support, improved stability, per-client traffic accounting, multi-node
management, and many quality-of-life features.
</Callout>
Ready to install? Continue to [Installation](/docs/guide/installation).
+148
View File
@@ -0,0 +1,148 @@
---
title: Installation
description: Install 3x-ui via the official script (stable, pinned, or dev-latest), unattended/cloud-init, or Docker — and choose SQLite or PostgreSQL.
icon: Download
---
3x-ui runs on a wide range of Linux distributions — Ubuntu, Debian, Armbian,
Fedora, CentOS, RHEL, AlmaLinux, Rocky Linux, Oracle Linux, Amazon Linux,
Virtuozzo, Arch, Manjaro, openSUSE (Tumbleweed/Leap), Alpine — and Windows,
across `amd64`, `386`, `arm64`, `armv7`, `armv6`, `armv5`, and `s390x`.
<Callout type="warn">
Run the script installer as **root** (or with `sudo`). It installs a service,
sets up the `x-ui` management command, and enables the panel on boot.
</Callout>
<Tabs items={['Script', 'Docker', 'Manual']}>
<Tab value="Script">
The official script is the recommended path. During installation it generates a
**random** username, password, and access (web base) path, sets up the service,
and installs the `x-ui` management command.
```bash title="latest stable"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
Install a **specific version** by appending its tag:
```bash title="pinned version"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
```
Install the rolling **dev** build (the latest per-commit pre-release from `main`
— not a stable release) by passing `dev-latest`:
```bash title="rolling dev build"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
```
When it finishes, note the printed login details and run `x-ui` to open the
[management menu](/docs/guide/update-uninstall#the-x-ui-management-menu), then
continue to [First login](/docs/guide/first-login).
</Tab>
<Tab value="Docker">
The default Compose setup uses SQLite. Clone the repo (or copy its
`docker-compose.yml` and `Dockerfile`) and start it:
```bash
docker compose up -d
```
To run with the bundled **PostgreSQL** service, uncomment the two `XUI_DB_*`
lines in `docker-compose.yml` and start with the profile:
```bash
docker compose --profile postgres up -d
```
Prefer the prebuilt image? It's published to the GitHub Container Registry. The
image bundles Fail2ban (for [IP limits](/docs/operations/security)), which bans
with `iptables` and therefore needs `NET_ADMIN` (and `NET_RAW` for IPv6) —
otherwise bans are logged but never applied:
```bash title="docker run"
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
ghcr.io/mhsanaei/3x-ui:latest
```
The `db/` volume holds the SQLite database (`/etc/x-ui/x-ui.db`) and `cert/`
holds TLS certificates, so your data survives upgrades.
</Tab>
<Tab value="Manual">
For advanced users, download a release archive for your architecture from the
[releases page](https://github.com/MHSanaei/3x-ui/releases), extract it, and run
the binary as a systemd service. The install script automates exactly these
steps, so it's preferred unless you have a specific reason to install by hand.
</Tab>
</Tabs>
## Build your install command
Tailor the command to your setup:
<InstallCommandBuilder />
## Choose a database
You pick the storage backend at install time:
- **SQLite** (default) — a single file at `/etc/x-ui/x-ui.db`. Zero setup.
- **PostgreSQL** — for high client counts or multi-node setups. The installer
can install it locally or use a DSN you provide.
See [Database](/docs/reference/database) for details and SQLite→PostgreSQL
migration.
## Unattended / cloud-init
The installer also runs **non-interactively** for automation. Set
`XUI_NONINTERACTIVE=1` (or run with no TTY) and it installs end-to-end with zero
prompts, generating random credentials and writing them to
`/etc/x-ui/install-result.env`:
```bash
XUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
The repo's [`deploy/`](https://github.com/MHSanaei/3x-ui/tree/main/deploy)
directory has ready-made **cloud-init** user-data for unattended installs on any
cloud (Hetzner, AWS, DigitalOcean, Vultr, GCP, Azure, Oracle).
## Next steps
<Cards>
<Card
title="First login"
href="/docs/guide/first-login"
description="Reach the panel and secure it."
/>
<Card
title="Update & uninstall"
href="/docs/guide/update-uninstall"
description="The x-ui menu, updates, and removal."
/>
<Card
title="REALITY"
href="/docs/config/reality"
description="Configure your first stealthy inbound."
/>
</Cards>
+5
View File
@@ -0,0 +1,5 @@
{
"title": "Getting Started",
"icon": "Rocket",
"pages": ["index", "installation", "first-login", "update-uninstall"]
}
@@ -0,0 +1,99 @@
---
title: Update & Uninstall
description: Manage 3x-ui with the x-ui menu and CLI — update (stable, dev, or legacy), change settings, and uninstall cleanly.
icon: RefreshCw
---
After a script install, the `x-ui` command is your control center. Run it with
no arguments for the interactive menu, or pass a subcommand for a one-shot action.
```bash
x-ui
```
## The `x-ui` management menu
The menu (items `0``28`) shows the panel/Xray status at the top, then:
| # | Item | What it does |
| ----- | -------------------------------------- | --------------------------------------------------------- |
| 1 | Install | (Re)install from the remote script |
| 2 | Update | Update to the latest **stable** release |
| 3 | Update to Dev Channel (latest commit) | Update to the rolling `dev-latest` build |
| 4 | Update Menu | Update just the `x-ui` menu script |
| 5 | Legacy Version | Install a specific older version (prompts for a tag) |
| 6 | Uninstall | Remove 3x-ui (see below) |
| 7 | Reset Username & Password | Set new credentials; optionally disable 2FA |
| 8 | Reset Web Base Path | Randomize the web base path |
| 9 | Reset Settings | Reset panel settings (your account is preserved) |
| 10 | Change Port | Change the panel port |
| 11 | View Current Settings | Show username, port, web base path, cert paths |
| 1214 | Start / Stop / Restart | Control the panel service |
| 15 | Restart Xray | Reload only Xray-core |
| 16 | Check Status | Service status |
| 17 | Logs Management | View debug logs / clear logs |
| 1819 | Enable / Disable Autostart | Toggle start-on-boot |
| 20 | SSL Certificate Management | Let's Encrypt (domain or IP), custom paths, renew/revoke |
| 21 | Cloudflare SSL Certificate | DNS-01 wildcard cert via Cloudflare |
| 22 | IP Limit Management | Fail2ban-based per-client IP limits |
| 23 | Firewall Management | `ufw` install and port rules |
| 24 | SSH Port Forwarding Management | Bind the panel to localhost and tunnel over SSH |
| 25 | PostgreSQL Management | Install/migrate/manage PostgreSQL |
| 26 | Enable BBR | Toggle the BBR congestion-control sysctl |
| 27 | Update Geo Files | Update geoip/geosite data (Loyalsoldier, IR, RU) |
| 28 | Speedtest by Ookla | Run an Ookla speed test |
| 0 | Exit | — |
Some of these have their own pages: [SSL certificates](/docs/config/ssl-certificates)
(items 2021), [Security](/docs/operations/security) (IP limits, firewall),
[Reverse proxy](/docs/operations/reverse-proxy) and [Panel settings](/docs/config/panel)
(TLS), and [Database](/docs/reference/database) (PostgreSQL).
## CLI subcommands
For scripts and quick actions, `x-ui` also takes a subcommand directly:
| Command | Action |
| -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | Control the service |
| `x-ui restart-xray` | Reload only Xray-core |
| `x-ui status` | Show status |
| `x-ui settings` | Show current settings |
| `x-ui enable` / `disable` | Toggle autostart on boot |
| `x-ui log` | Tail the debug log |
| `x-ui banlog` | Show Fail2ban ban log |
| `x-ui update` | Update to the latest stable release |
| `x-ui update-dev` | Update to the rolling `dev-latest` build |
| `x-ui legacy` | Install a specific older version (prompts) |
| `x-ui update-all-geofiles` | Update all geo files, restart if changed |
| `x-ui migrate-db --dsn …` | Migrate SQLite → PostgreSQL (see [Database](/docs/reference/database)) |
| `x-ui install` / `uninstall` | Install / uninstall |
## Updating
- **Stable:** menu option **2** or `x-ui update`. Re-running the install script
also updates in place.
- **Dev channel:** menu option **3** or `x-ui update-dev` — the rolling
`dev-latest` per-commit build (not a stable release).
- **A specific older version:** menu option **5** (Legacy Version).
Updating preserves your database and settings. Take a
[backup](/docs/operations/backup-restore) before a major-version jump.
<Callout type="info">
Docker users update differently — pull the new image and recreate the
container (`docker compose pull && docker compose up -d`) rather than using the
`x-ui` update commands.
</Callout>
## Uninstalling
Menu option **6** or `x-ui uninstall`. It stops and disables the service, removes
the service unit, and deletes `/etc/x-ui/` and the install folder. If the panel
used a locally-installed PostgreSQL, it offers to purge that too (a separate,
irreversible confirmation).
<Callout type="warn">
Uninstalling removes the database (`/etc/x-ui/x-ui.db`) and your configuration.
[Back up](/docs/operations/backup-restore) first if you might need it.
</Callout>
@@ -0,0 +1,64 @@
---
title: Contributing
description: How to contribute to 3x-ui and to translate this documentation.
icon: GitPullRequestArrow
---
3x-ui is community-driven. Contributions to the panel and to these docs are
welcome.
## Support the developer
3x-ui is free and open source, built and maintained in the open. If it's useful
to you, consider supporting continued development:
- **Donate** at [donate.sanaei.dev](https://donate.sanaei.dev/) — the page shows
current funding **goals and targets** you can help reach.
- **Star** the [repository](https://github.com/MHSanaei/3x-ui) and share the
project.
- **Join** the Telegram channel [@XrayUI](https://t.me/XrayUI) to follow news and
help others.
## Contribute to 3x-ui
- Read the project's `CONTRIBUTING.md` in the
[repository](https://github.com/MHSanaei/3x-ui).
- Open issues for bugs and feature requests with clear reproduction steps.
- Use Conventional Commits and keep pull requests focused.
## Translate the documentation
This site is built for translation. Content lives under `content/docs/<locale>/`
(`en`, `fa`, `ru`, `zh`), and untranslated pages **fall back to English**, so you
can translate incrementally.
<Steps>
<Step>
### Copy a page
Copy a page from `content/docs/en/...` to the same path under your locale, e.g.
`content/docs/fa/guide/installation.mdx`.
</Step>
<Step>
### Translate the prose only
Translate the body and the frontmatter `title`/`description`. **Do not** translate
code, commands, environment variable names, protocol names, or share links.
</Step>
<Step>
### Mind direction
Persian (`fa`) renders right-to-left. Keep code blocks and links left-to-right
(the layout already handles this), and check the page in both directions.
</Step>
</Steps>
<Callout type="info">
Missing a page in your locale is fine — it falls back to English rather than
404ing. Translate the highest-traffic pages first (installation, first login,
REALITY).
</Callout>
+47
View File
@@ -0,0 +1,47 @@
---
title: FAQ
description: Frequently asked questions about 3x-ui — licensing, supported systems, databases, and clients.
icon: CircleQuestionMark
---
## Is 3x-ui free and open source?
Yes. 3x-ui is open source under the GPL-3.0 license. The source is on
[GitHub](https://github.com/MHSanaei/3x-ui).
## What systems does it run on?
Most major Linux distributions (Ubuntu, Debian, CentOS/RHEL and derivatives,
Fedora, Arch, Alpine, and more) across `amd64`, `arm64`, and other architectures.
It also runs as a Docker container. See [Installation](/docs/guide/installation).
## SQLite or PostgreSQL?
SQLite is the default and is fine for most deployments. PostgreSQL is available
for larger setups via `XUI_DB_TYPE=postgres` and `XUI_DB_DSN` — see the
[environment variables](/docs/reference/env-vars).
## Which client apps work with it?
Any Xray-compatible client — for example v2rayNG, Hiddify, and Clash/Mihomo.
Import a client's share link or QR code, or use a
[subscription](/docs/config/subscription).
## How is 3x-ui different from x-ui?
3x-ui is an enhanced fork of the original X-UI project. It adds broader protocol
support, improved stability, per-client traffic accounting, multi-node
management, a 13-language UI, and many quality-of-life features.
## How do I update?
Re-run the install script (it updates in place), or pull the new Docker image.
See [Installation](/docs/guide/installation) and the
[releases page](https://github.com/MHSanaei/3x-ui/releases).
## Where can I get help?
Join the official Telegram channel [@XrayUI](https://t.me/XrayUI) for
announcements and community support, or open an issue on
[GitHub](https://github.com/MHSanaei/3x-ui/issues). For common problems, start
with [Troubleshooting](/docs/help/troubleshooting).
+5
View File
@@ -0,0 +1,5 @@
{
"title": "Help",
"icon": "LifeBuoy",
"pages": ["troubleshooting", "faq", "migration", "contributing"]
}
+52
View File
@@ -0,0 +1,52 @@
---
title: Migration
description: Migrate to 3x-ui from x-ui, between servers, or between 3x-ui versions.
icon: ArrowRightLeft
---
## Between servers
Moving to a new server is a database move:
<Steps>
<Step>
### Back up the old server
Copy the database (default `/etc/x-ui/x-ui.db`) and your certificates. See
[Backup & restore](/docs/operations/backup-restore).
</Step>
<Step>
### Install 3x-ui on the new server
Use the same install method and a compatible version. See
[Installation](/docs/guide/installation).
</Step>
<Step>
### Restore the database
Stop the panel, put the database in place, restore certificates, and start the
panel. Update any IP/domain-specific settings.
</Step>
</Steps>
## Between 3x-ui versions
Within the same backend, upgrading is usually just re-running the installer or
pulling a new image — the panel migrates its own database. Across **major**
versions, read the [release notes](https://github.com/MHSanaei/3x-ui/releases)
first and take a backup.
## From x-ui
Importing an older x-ui panel's database directly into 3x-ui is **not
supported** — the schemas differ. Install 3x-ui fresh and recreate
inbounds/clients, exporting share links from the old panel as you go.
<Callout type="warn">
Always take a backup before any migration, and keep the old server running
until you've verified the new one.
</Callout>
@@ -0,0 +1,42 @@
---
title: Troubleshooting
description: Fix common 3x-ui problems — the panel won't start, 502 errors, certificate issues, and clients that can't connect.
icon: Wrench
---
A checklist for the most common issues. When in doubt, raise the log level
(`XUI_LOG_LEVEL=debug`) and check the panel and Xray logs.
## The panel won't start
- Check the service status and logs (`x-ui` menu → status/logs).
- Make sure the **panel port isn't already in use** by another service.
- Verify the database path is writable (default `/etc/x-ui/x-ui.db`).
## 502 / panel unreachable behind a proxy
- Confirm the panel is actually listening on the upstream port (e.g. `2053`).
- Ensure your [reverse proxy](/docs/operations/reverse-proxy) passes WebSocket
upgrade headers and points at the correct port and **web base path**.
- Check the firewall isn't blocking the proxy → panel connection.
## Certificate problems
- The domain's DNS must point at the server before issuing a certificate.
- Ports 80/443 must be reachable for HTTP/TLS validation (or use DNS validation).
- For REALITY, remember it needs **no certificate** — the issue is usually a bad
`dest`/SNI instead (see [REALITY pitfalls](/docs/config/reality)).
## A client can't connect
- Decode the client's link with the
[share-link inspector](/docs/config/share-links) and confirm every parameter.
- Check the **transport and security match** on both ends.
- Make sure the client hasn't hit its **traffic, expiry, or IP limit**.
- Confirm the inbound port is open in the firewall.
<Callout type="info">
Still stuck? Search the
[GitHub issues](https://github.com/MHSanaei/3x-ui/issues) — your symptom has
probably been seen before.
</Callout>
+54
View File
@@ -0,0 +1,54 @@
---
title: 3x-ui Documentation
description: Official documentation for 3x-ui — an advanced web panel for managing Xray-core servers, proxies, clients, and subscriptions.
icon: House
---
**3x-ui** is an open-source web panel for deploying and managing
[Xray-core](https://github.com/XTLS/Xray-core) servers. It gives you a modern
dashboard for inbounds, protocols, clients, traffic accounting, subscriptions,
and more — without hand-editing Xray JSON on the command line.
This site is the official documentation and a set of **interactive, in-browser
tools** (config generators) that run entirely on your device — no data ever
leaves the page.
## Start here
<Cards>
<Card
title="What is 3x-ui?"
href="/docs/guide"
description="The big picture: Xray-core, the panel, and who it's for."
/>
<Card
title="Installation"
href="/docs/guide/installation"
description="Install via script, Docker, or manually."
/>
<Card
title="First login"
href="/docs/guide/first-login"
description="Reach the panel and harden it before anything else."
/>
<Card
title="REALITY"
href="/docs/config/reality"
description="Set up VLESS + REALITY with XTLS-Vision."
/>
</Cards>
## Highlights
- **Every major protocol** — VLESS, VMess, Trojan, Shadowsocks, WireGuard,
Hysteria2, SOCKS, HTTP, and Dokodemo-door.
- **REALITY & XTLS-Vision** — modern, censorship-resistant transports.
- **Per-client controls** — traffic quotas, expiry dates, IP limits, share
links, and QR codes.
- **Subscriptions** — VLESS, Clash/Mihomo, and JSON formats.
- **Operations** — multi-node management, Telegram bot, backups, and a REST API.
<Callout type="info">
New to Xray? Read [What is 3x-ui?](/docs/guide) first — it explains how the panel, Xray-core, and
your client apps fit together.
</Callout>
+3
View File
@@ -0,0 +1,3 @@
{
"pages": ["index", "guide", "config", "operations", "reference", "help"]
}
@@ -0,0 +1,57 @@
---
title: Backup & Restore
description: Back up and restore your 3x-ui database and certificates, manually or via the Telegram bot.
icon: DatabaseBackup
---
Your entire configuration — inbounds, clients, settings — lives in the panel's
database. Back it up regularly so you can recover or migrate.
## What to back up
- **The database** — SQLite at `/etc/x-ui/x-ui.db` by default (or your
PostgreSQL database if you use that backend).
- **Certificates** — anything under `/root/cert/` (or wherever you store TLS
certs).
## Manual backup
You can download a backup from the panel's overview, or copy the database file
directly from the server:
```bash title="copy the SQLite database"
cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
```
To restore, stop the panel, put the database back in place, and start it again.
<Callout type="warn">
Restore a backup onto the **same major version** it came from when possible.
Across major upgrades, let the panel run its migrations rather than forcing an
old schema.
</Callout>
## Telegram backup
If you've configured the [Telegram bot](/docs/operations/telegram-bot), enable
**`tgBotBackup`** to attach a backup to the periodic report (on the `tgRunTime`
schedule, default daily). The bot sends both the **database** and the **Xray
`config.json`** to your admin chat, so you always have an off-server copy. Admins
can also request a backup on demand from the bot's menu.
## SQLite dump / restore
The `x-ui migrate-db` command converts the SQLite database to and from a plain
SQL text dump (handy for inspection or transferring between machines):
```bash
x-ui migrate-db --dump /root/x-ui.sql # SQLite -> SQL text
x-ui migrate-db --restore /root/x-ui.sql # SQL text -> SQLite
```
To move to PostgreSQL instead, see [Database](/docs/reference/database).
<Callout type="info">
Whatever method you use, store backups **off the server** and test a restore
occasionally — an untested backup isn't a backup.
</Callout>
+12
View File
@@ -0,0 +1,12 @@
{
"title": "Operations",
"icon": "ServerCog",
"pages": [
"reverse-proxy",
"multi-node",
"outbounds-routing",
"backup-restore",
"telegram-bot",
"security"
]
}
@@ -0,0 +1,97 @@
---
title: Multi-node & Managed Hosts
description: Manage multiple 3x-ui panels from one master, with API-token or mTLS trust, heartbeats, and per-inbound host overrides for subscriptions.
icon: Boxes
---
3x-ui can manage **multiple servers** from a single master panel, and override
how each inbound is advertised in subscriptions with **managed hosts**.
## Nodes
A **node** is another 3x-ui panel that your master panel manages over the node's
API. The master polls each node and shows its status, versions, CPU/memory,
uptime, and traffic in one place.
### Add a node
Provide the node's connection details:
| Field | Notes |
| ----------------- | --------------------------------------------------------------------- |
| **Name** | Unique label (e.g. `de-fra-1`). |
| **Scheme** | `https` (default) or `http`. |
| **Address / Port**| The node panel's host and port. |
| **Base path** | The node's web base path. |
| **API token** | A Bearer token created on the node (not needed in mTLS mode). |
| **TLS verify** | `verify` (default), `skip`, `pin` (pin a cert SHA-256), or `mtls`. |
| **Inbound sync** | `all` inbounds, or `selected` by tag. |
| **Outbound tag** | Optionally reach the node **through** a named outbound (egress bridge).|
The master verifies reachability when you add or test a node. It then sends a
**heartbeat** every few seconds, updating the node's status (`online` / `offline`)
and emitting `node.up` / `node.down` events (see the
[Telegram bot](/docs/operations/telegram-bot)).
<Callout type="info">
Nodes are identified by a stable per-panel GUID, so a node keeps its identity
across restarts. A node can itself manage further nodes — the master surfaces
those as read-only **transitive** sub-nodes (Node 1 → Node 2 → Node 3).
</Callout>
### Mutual TLS (mTLS) between master and node
For the strongest trust, use `tlsVerifyMode = mtls` (requires `https`):
<Steps>
<Step>
### Get the master's CA
On the master, fetch its node-auth CA certificate (the CA private key never
leaves the panel).
</Step>
<Step>
### Trust it on the node
Paste that CA into the node's "trusted CA" setting. It takes effect on the node's
next restart.
</Step>
<Step>
### Switch the node to mTLS
Set the node's TLS verify mode to `mtls`. The master now presents a client
certificate instead of an API token.
</Step>
</Steps>
## Managed hosts
A **managed host** is an override endpoint attached to an inbound. At
subscription time, each enabled host renders an additional share link / proxy
with its own address, port, TLS, SNI, host header, path, and more — superseding
the older "external proxy" list. Use them to:
- front an inbound through a **CDN** (Cloudflare) with a different address/SNI,
- advertise **multiple domains** or per-region endpoints for one inbound,
- tweak ALPN, fingerprint, ECH, or mux per endpoint.
Each host has a remark (which supports the same
[template variables](/docs/config/share-links#remark-template-variables)), an
enable toggle, a sort order, and can be **excluded from specific subscription
formats** or **scoped to specific nodes**.
<Callout type="info">
Hosts whose address/port point at a CDN let you keep the real server address
private while clients connect through the CDN edge.
</Callout>
## Related
<Cards>
<Card title="Outbounds & routing" href="/docs/operations/outbounds-routing" description="WARP, NordVPN, outbound subscriptions, and routing." />
<Card title="Subscription" href="/docs/config/subscription" description="How hosts shape subscription output." />
</Cards>
@@ -0,0 +1,157 @@
---
title: Outbounds & Routing
description: Shape egress in 3x-ui — WARP and NordVPN outbounds, outbound subscriptions (server pools), routing rules, and load balancers.
icon: Route
---
Inbounds accept clients; **outbounds** decide where their traffic goes next.
3x-ui can route traffic through Cloudflare WARP, NordVPN, or arbitrary outbound
pools imported from a subscription, and select between them with routing rules
and balancers.
## Editing outbounds & routing
Outbounds, routing rules, balancers, DNS, and logging all live in the **Xray
configuration** (the config template you edit under Xray Settings). There's no
separate per-rule UI — you edit the JSON, and the panel reloads Xray. The panel
also offers an **outbound connectivity test** and a **route test** (ask the
running core which outbound a given destination would use).
## Build an outbound
Every outbound is a JSON object with up to four parts: a **`tag`** (referenced by
routing rules and balancers), a **`protocol`**, protocol-specific **`settings`**,
and — for proxy protocols — **`streamSettings`** that must match the remote
inbound's transport and security. Two outbounds are almost always present:
- **`freedom`** sends traffic straight to its destination — the default egress.
Optionally set a `domainStrategy` (e.g. `UseIP`) to control how hostnames resolve.
- **`blackhole`** drops traffic. Route unwanted destinations (ads, torrents) here.
```json title="freedom + blackhole"
{
"outbounds": [
{ "tag": "direct", "protocol": "freedom", "settings": {} },
{ "tag": "block", "protocol": "blackhole", "settings": {} }
]
}
```
A **proxy** outbound (VLESS, VMess, Trojan, Shadowsocks) forwards to another
server — handy for chaining or sending select traffic abroad. Mind the wire
shapes 3x-ui uses: **VLESS is the flat form** (`address`/`port`/`id`/`flow`/
`encryption`), **VMess uses `settings.vnext[]`**, and **Trojan/Shadowsocks use
`settings.servers[]`**. The `streamSettings` must mirror the destination's
[transport and security](/docs/config/transports).
Assemble any outbound below and paste the JSON into **Xray Settings → Outbounds**:
<OutboundGenerator />
## Cloudflare WARP
WARP lets your server egress through Cloudflare's network. 3x-ui can register a
WARP account for you and wire it into a WireGuard outbound tagged **`warp`**:
<Steps>
<Step>
### Add a `warp`-tagged outbound
Create a WireGuard outbound with the tag `warp` in your Xray config.
</Step>
<Step>
### Register WARP
From the panel's WARP controls, register an account. 3x-ui fills the outbound's
keys, addresses, reserved bytes, and peer endpoint automatically.
</Step>
<Step>
### (Optional) auto-rotate the IP
Set a WARP update interval (in **days**) to periodically rotate the WARP IP. A
free license can also be applied.
</Step>
</Steps>
Route the traffic you want (for example specific domains) to the `warp` outbound
with a routing rule.
## NordVPN
3x-ui can fetch NordVPN (NordLynx/WireGuard) credentials from an access token (or
accept a private key directly) and list countries/servers, so you can build a
NordVPN outbound.
## Outbound subscriptions (server pools)
An **outbound subscription** imports a remote share-link subscription and injects
its servers as **outbounds** into the running Xray config — without touching your
saved template. This is the recommended way to subscribe to a *pool* of servers.
| Field | Default | Meaning |
| ---------------- | ------- | -------------------------------------------------------------- |
| `url` | — | The remote subscription URL (SSRF-guarded). |
| `tagPrefix` | auto | Prefix for generated outbound tags (e.g. `hk-`); blank = `subN-`. |
| `updateInterval` | `600` | Refresh interval in **seconds**. |
| `prepend` | `false` | Place these outbounds before your manual ones. |
| `priority` | `0` | Merge order (lower first). |
Imported outbounds get **stable tags**: the same server keeps the same tag across
refreshes, so exact-tag routing/balancer selectors stay pinned — while
prefix/wildcard selectors (e.g. `hk-*`) automatically pick up new servers as the
pool changes. Supported link schemes: `vmess`, `vless`, `trojan`, `ss`,
`hysteria2` (`hy2`), and `wireguard` (`wg`). The panel refreshes enabled
subscriptions on a timer and reloads Xray when something changes.
## Routing rules
**Routing rules** decide which outbound (or balancer) each connection uses. Each
rule is a `field`-type matcher: set any of `domain`, `ip`, `port`, `network`,
`protocol`, `inboundTag`, `sourceIP`, … and point it at an **`outboundTag`** or a
**`balancerTag`**. Rules are evaluated **top-to-bottom — the first match wins**, so
put specific rules above general ones.
```json title="route ads to blackhole, private IPs direct"
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{ "type": "field", "domain": ["geosite:category-ads-all"], "outboundTag": "block" },
{ "type": "field", "ip": ["geoip:private"], "outboundTag": "direct" }
]
}
}
```
## Balancers
A **balancer** groups outbounds by a **selector** (tag prefixes, including the
wildcard pools from outbound subscriptions) and spreads or fails traffic over them
with a **strategy**:
| Strategy | Picks… | Needs a monitor |
| ------------- | ----------------------------------------------- | ------------------------ |
| `random` | a random member per connection | no |
| `roundRobin` | members in rotation | no |
| `leastPing` | the lowest-latency member | **`observatory`** |
| `leastLoad` | the most stable member by sampled load | **`burstObservatory`** |
Reference a balancer from a rule via `balancerTag`. `leastPing` and `leastLoad`
need a health monitor, which Xray places at the **top level** of the config
(`observatory` / `burstObservatory`, **not** inside `routing`). The panel can
report balancer status and **override** a balancer to a specific outbound for
testing.
Build the routing block — rules, balancers, and the matching observatory — here:
<RoutingBuilder />
<Callout type="warn">
Outbounds that reach external services are fetched with SSRF protection — by
default private/internal addresses are blocked unless you explicitly allow them
per source.
</Callout>
@@ -0,0 +1,51 @@
---
title: Reverse Proxy
description: Put the 3x-ui panel and subscription behind Nginx or Caddy with Let's Encrypt TLS.
icon: Waypoints
---
A reverse proxy lets you serve the panel and subscription on a clean domain with
automatic HTTPS, and hide the real ports behind ports 80/443. Prefer to let the
panel terminate TLS directly? Get a certificate with the
[`x-ui` SSL menu](/docs/config/ssl-certificates) instead.
## Generate a config
<ReverseProxyGenerator />
<Callout type="info">
The panel uses WebSockets for live updates, so the proxy must pass the
`Upgrade`/`Connection` headers (the Nginx output above already does). Caddy
handles WebSocket upgrades automatically.
</Callout>
## Nginx + certificate
With Nginx, obtain a certificate with `certbot` (or `acme.sh`) and reference it
in the server block:
```bash title="certbot"
certbot certonly --nginx -d panel.example.com
```
Reload Nginx after installing the certificate, and set up automatic renewal
(`certbot renew` runs on a timer by default).
## Caddy
Caddy obtains and renews certificates for you — point a Caddyfile at the panel
and it just works:
```text title="Caddyfile"
panel.example.com {
reverse_proxy 127.0.0.1:2053
}
```
## Tips
- Keep the panel's **web base path** even behind a proxy; defense in depth.
- If you terminate TLS at the proxy, you may want `XUI_SKIP_HSTS=true` on the
panel — see the [environment variables reference](/docs/reference/env-vars).
- Proxy the [subscription](/docs/config/subscription) server too, so its contents
are served over HTTPS.
@@ -0,0 +1,66 @@
---
title: Security
description: Harden 3x-ui — panel auth and 2FA, Fail2ban IP limits, firewall rules, BBR, and staying current.
icon: ShieldCheck
---
A proxy panel is a high-value target. A few layers of hardening go a long way.
## Panel hardening
- Strong, unique credentials and **two-factor auth** (TOTP).
- A non-default panel port and a long, random web base path.
- TLS on the panel (directly or via a [reverse proxy](/docs/operations/reverse-proxy)).
- The built-in **login limiter** blocks an IP/username after 5 failed attempts
in 5 minutes (for 15 minutes), and the panel can route its own egress through
an outbound.
See [First login](/docs/guide/first-login) for the full checklist.
## Fail2ban & IP limits
Set an **IP limit** per client (see [Clients](/docs/config/clients)) to cap the
number of simultaneous source IPs. Enforcement is handled by **Fail2ban**, which
3x-ui installs and configures for you (enabled by default on script installs, and
on Docker via `XUI_ENABLE_FAIL2BAN=true`).
Manage it from the `x-ui` menu (**22 — IP Limit Management**): install/configure,
change the ban duration (default **30 minutes**), ban/unban an IP, view ban logs,
and check status. Under the hood:
- The jail is named **`3x-ipl`**; ban logs live at `/var/log/x-ui/3xipl.log` and
`/var/log/x-ui/3xipl-banned.log` (also via `x-ui banlog`).
- Bans cover all TCP/UDP **except** your SSH and panel ports, so a ban can't lock
you out of the server or panel.
<Callout type="warn">
On Docker, Fail2ban bans with `iptables`, which needs the `NET_ADMIN` (and
`NET_RAW`) capability — `docker-compose.yml` grants them. With a bare
`docker run`, add `--cap-add=NET_ADMIN --cap-add=NET_RAW` or bans are logged
but never applied.
</Callout>
## Firewall
Open only the ports you actually use: SSH, the panel port, the subscription
port, and your inbound ports. The `x-ui` menu (**23 — Firewall Management**) wraps
`ufw`, or generate rules here:
<FirewallRulesGenerator />
<Callout type="warn">
Make sure SSH stays allowed before enabling a default-deny firewall, or you can
lock yourself out. Test with a second session open.
</Callout>
## Network tuning (BBR)
The `x-ui` menu (**26 — Enable BBR**) toggles Google's BBR congestion control
(`net.ipv4.tcp_congestion_control = bbr`, `net.core.default_qdisc = fq`), which
often improves throughput on congested links.
## Keep current
Update 3x-ui and Xray-core regularly — security fixes land in new releases. Watch
the [releases page](https://github.com/MHSanaei/3x-ui/releases) and see
[Update & uninstall](/docs/guide/update-uninstall).
@@ -0,0 +1,112 @@
---
title: Telegram Bot
description: Connect a Telegram bot to 3x-ui for commands, periodic reports, event alerts (login, CPU, node up/down), backups, and client self-service.
icon: Send
---
3x-ui can drive a Telegram bot for monitoring, alerts, backups, and remote
management. Admins get full control; regular users (linked by Telegram ID) can
check their own usage and links.
<Callout type="info">
Looking for news and community support? Join the official Telegram channel
[@XrayUI](https://t.me/XrayUI). That's separate from the bot below, which you
run yourself to manage your own panel.
</Callout>
## Set it up
<Steps>
<Step>
### Create a bot
Message [@BotFather](https://t.me/BotFather), send `/newbot`, and copy the **bot
token**.
</Step>
<Step>
### Find your Telegram ID
Get your numeric Telegram user ID (the bot's own `/id` command reports it once
connected). This is your **admin** ID.
</Step>
<Step>
### Configure the panel
In Panel Settings, enable the Telegram bot and set the **token** and **admin chat
ID(s)** (comma-separated). Save, then message your bot.
</Step>
</Steps>
Validate your token, admin IDs, and report schedule before pasting them into the
panel:
<TelegramSetupHelper />
## Commands
These appear in the Telegram command menu: `/start`, `/help`, `/status`, `/id`.
Additional commands:
| Command | Who | Action |
| ------------------ | ------ | ------------------------------------------------------------ |
| `/start`, `/help` | anyone | Greeting and the menu of inline buttons |
| `/status` | anyone | Confirm the bot is alive |
| `/id` | anyone | Show your Telegram numeric ID |
| `/usage <arg>` | both | Admins search clients; users look up their own usage |
| `/inbound <remark>`| admin | Show an inbound's details |
| `/restart` | admin | Restart Xray |
Admins also get inline-button flows for server usage, sorted traffic reports,
resetting traffic, DB backups, ban logs, listing inbounds/clients, online
clients, "depleting soon", and a full **add-client** wizard. Regular users get
buttons for their own usage, subscription links, individual links, and QR codes.
## Reports & alerts
- **Periodic report** — on the `tgRunTime` schedule (default `@daily`), the bot
sends admins server usage (host, versions, uptime, load, memory, online
clients, traffic), a list of exhausted/expiring clients, and — if
`tgBotBackup` is on — a database + Xray config backup. Clients linked by
Telegram ID get their own expiry/quota warnings.
- **Event alerts** — selected by `tgEnabledEvents` (default `login.attempt,cpu.high`):
| Event | When |
| --------------- | ------------------------------------------------------- |
| `login.attempt` | A panel login succeeds or fails (with IP and username) |
| `cpu.high` | CPU exceeds `tgCpu` percent (default 80) |
| `memory.high` | Memory exceeds `tgMemory` percent (default 80) |
| `xray.crash` | Xray-core crashes |
| `outbound.down` / `outbound.up` | An outbound goes down / recovers |
| `node.down` / `node.up` | A node goes offline / comes back |
The warning lead times come from `expireDiff` (days before expiry) and
`trafficDiff` (GB of quota remaining); both default to `0` (off).
## Settings
| Setting | Default | Meaning |
| -------------- | -------------------------- | ---------------------------------------------- |
| `tgBotEnable` | `false` | Master on/off. |
| `tgBotToken` | _(secret)_ | Bot API token. |
| `tgBotChatId` | _(none)_ | Comma-separated **admin** Telegram IDs. |
| `tgBotProxy` | _(none)_ | `socks5://`, `http://`, or `https://` proxy. |
| `tgBotAPIServer` | _(default)_ | Custom Telegram Bot API server. |
| `tgRunTime` | `@daily` | Report schedule (cron / `@daily` / `@every …`).|
| `tgBotBackup` | `false` | Attach a DB backup to the periodic report. |
| `tgCpu` / `tgMemory` | `80` / `80` | CPU / memory alert thresholds (percent). |
| `tgLang` | `en-US` | Bot language. |
| `tgEnabledEvents` | `login.attempt,cpu.high`| Which events to deliver. |
<Callout type="warn">
The bot token controls your bot — keep it secret and only add **trusted** admin
chat IDs. Login alerts never include passwords.
</Callout>
<Callout type="info">
Email (SMTP) notifications mirror the same events (`smtpEnabledEvents`) if you'd
rather receive alerts by email — configure SMTP in Panel Settings.
</Callout>
@@ -0,0 +1,79 @@
---
title: API Tokens
description: >-
Manage Bearer tokens used for programmatic auth (bots, central panels acting
on this node, CI). Each token has a unique name and an enabled flag — disable
to revoke without deleting, delete to revoke permanently. Tokens are stored as
SHA-256 hashes and the plaintext is returned only once, in the create response
— it cannot be retrieved afterwards, so copy it then. Send one as
<code>Authorization: Bearer &lt;token&gt;</code> on any /panel/api/* request —
the token is a full-admin credential.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every API token, enabled or not. The token value is never returned
— only metadata.
url: >-
#list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata
- depth: 2
title: >-
Mint a new API token. Name must be unique and 1-64 characters; the token
string is server-generated and returned only in this response — it is
stored hashed and cannot be retrieved later.
url: >-
#mint-a-new-api-token-name-must-be-unique-and-1-64-characters-the-token-string-is-server-generated-and-returned-only-in-this-response--it-is-stored-hashed-and-cannot-be-retrieved-later
- depth: 2
title: >-
Permanently delete a token. Any caller using it stops authenticating
immediately.
url: >-
#permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately
- depth: 2
title: >-
Toggle a token enabled/disabled without deleting it. Disabled tokens are
rejected by checkAPIAuth on the next request.
url: >-
#toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request
structuredData:
headings:
- content: >-
List every API token, enabled or not. The token value is never
returned — only metadata.
id: >-
list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata
- content: >-
Mint a new API token. Name must be unique and 1-64 characters; the
token string is server-generated and returned only in this response —
it is stored hashed and cannot be retrieved later.
id: >-
mint-a-new-api-token-name-must-be-unique-and-1-64-characters-the-token-string-is-server-generated-and-returned-only-in-this-response--it-is-stored-hashed-and-cannot-be-retrieved-later
- content: >-
Permanently delete a token. Any caller using it stops authenticating
immediately.
id: >-
permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately
- content: >-
Toggle a token enabled/disabled without deleting it. Disabled tokens
are rejected by checkAPIAuth on the next request.
id: >-
toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/setting/apiTokens","method":"get"},{"path":"/panel/api/setting/apiTokens/create","method":"post"},{"path":"/panel/api/setting/apiTokens/delete/{id}","method":"post"},{"path":"/panel/api/setting/apiTokens/setEnabled/{id}","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,74 @@
---
title: Authentication
description: >-
Two authentication modes are supported. UI sessions use a cookie set by the
login endpoint. Programmatic clients (bots, scripts, remote panels)
authenticate with a Bearer token taken from Settings → Security → API Token.
Both work for every endpoint under /panel/api/*.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Authenticate with username + password and receive a session cookie.
Required before any cookie-based API call.
url: >-
#authenticate-with-username--password-and-receive-a-session-cookie-required-before-any-cookie-based-api-call
- depth: 2
title: Clear the session cookie. Requires the CSRF header for browser sessions.
url: '#clear-the-session-cookie-requires-the-csrf-header-for-browser-sessions'
- depth: 2
title: >-
Mint a CSRF token for the current session. The SPA replays it in the
X-CSRF-Token header on unsafe requests. Bearer-token callers can skip
this — the middleware short-circuits CSRF for authenticated API
requests.
url: >-
#mint-a-csrf-token-for-the-current-session-the-spa-replays-it-in-the-x-csrf-token-header-on-unsafe-requests-bearer-token-callers-can-skip-this--the-middleware-short-circuits-csrf-for-authenticated-api-requests
- depth: 2
title: >-
Returns whether 2FA is enabled on the panel — used by the login page to
decide whether to show the OTP field.
url: >-
#returns-whether-2fa-is-enabled-on-the-panel--used-by-the-login-page-to-decide-whether-to-show-the-otp-field
structuredData:
headings:
- content: >-
Authenticate with username + password and receive a session cookie.
Required before any cookie-based API call.
id: >-
authenticate-with-username--password-and-receive-a-session-cookie-required-before-any-cookie-based-api-call
- content: >-
Clear the session cookie. Requires the CSRF header for browser
sessions.
id: clear-the-session-cookie-requires-the-csrf-header-for-browser-sessions
- content: >-
Mint a CSRF token for the current session. The SPA replays it in the
X-CSRF-Token header on unsafe requests. Bearer-token callers can skip
this — the middleware short-circuits CSRF for authenticated API
requests.
id: >-
mint-a-csrf-token-for-the-current-session-the-spa-replays-it-in-the-x-csrf-token-header-on-unsafe-requests-bearer-token-callers-can-skip-this--the-middleware-short-circuits-csrf-for-authenticated-api-requests
- content: >-
Returns whether 2FA is enabled on the panel — used by the login page
to decide whether to show the OTP field.
id: >-
returns-whether-2fa-is-enabled-on-the-panel--used-by-the-login-page-to-decide-whether-to-show-the-otp-field
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/login","method":"post"},{"path":"/logout","method":"post"},{"path":"/csrf-token","method":"get"},{"path":"/getTwoFactorEnable","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,37 @@
---
title: Backup
description: Operations that interact with the configured Telegram bot.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Send a fresh DB backup to every Telegram chat configured as an admin
recipient. No body, no params.
url: >-
#send-a-fresh-db-backup-to-every-telegram-chat-configured-as-an-admin-recipient-no-body-no-params
structuredData:
headings:
- content: >-
Send a fresh DB backup to every Telegram chat configured as an admin
recipient. No body, no params.
id: >-
send-a-fresh-db-backup-to-every-telegram-chat-configured-as-an-admin-recipient-no-body-no-params
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/backuptotgbot","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,627 @@
---
title: Clients
description: >-
Manage clients as first-class entities that can be attached to one or more
inbounds. A single client row drives the settings.clients entry in every
inbound it belongs to. Endpoints live under /panel/api/clients.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every client with its attached inbound IDs and traffic record. The
reverse field, if set, is returned as a nested JSON object (legacy
JSON-encoded-string form is still accepted on write).
url: >-
#list-every-client-with-its-attached-inbound-ids-and-traffic-record-the-reverse-field-if-set-is-returned-as-a-nested-json-object-legacy-json-encoded-string-form-is-still-accepted-on-write
- depth: 2
title: >-
Filter, sort, and paginate clients on the server. Each item is a slim
row (no uuid/password/auth/flow/security/reverse/tgId) so the clients
page can ship 25-ish rows in a few KB instead of the full table. The
response also includes a summary computed across the full DB row set so
dashboard counters stay stable as the user paginates or filters. Page
size capped at 200; fetch /get/:email to obtain the full per-client
payload for an edit/info modal.
url: >-
#filter-sort-and-paginate-clients-on-the-server-each-item-is-a-slim-row-no-uuidpasswordauthflowsecurityreversetgid-so-the-clients-page-can-ship-25-ish-rows-in-a-few-kb-instead-of-the-full-table-the-response-also-includes-a-summary-computed-across-the-full-db-row-set-so-dashboard-counters-stay-stable-as-the-user-paginates-or-filters-page-size-capped-at-200-fetch-getemail-to-obtain-the-full-per-client-payload-for-an-editinfo-modal
- depth: 2
title: >-
Fetch one client by email, including the inbound IDs and external config
IDs it is attached to.
url: >-
#fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to
- depth: 2
title: >-
Create a new client and attach it to one or more inbounds in a single
call. Body is JSON. Per-protocol secrets (UUID for VLESS/VMess, password
for Trojan/Shadowsocks, auth for Hysteria) are generated server-side
when omitted, so callers can send only the universal fields.
url: >-
#create-a-new-client-and-attach-it-to-one-or-more-inbounds-in-a-single-call-body-is-json-per-protocol-secrets-uuid-for-vlessvmess-password-for-trojanshadowsocks-auth-for-hysteria-are-generated-server-side-when-omitted-so-callers-can-send-only-the-universal-fields
- depth: 2
title: >-
Update an existing client by email. Changes propagate to every attached
inbound. Body is the JSON client payload — supply the full set of fields
you want to keep (the server replaces the row, it does not patch).
url: >-
#update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
- depth: 2
title: >-
Delete a client by email. Removes it from every attached inbound and
drops its traffic record unless keepTraffic=1 is passed.
url: >-
#delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
- depth: 2
title: >-
Attach an existing client to one or more additional inbounds. Body is
JSON.
url: >-
#attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json
- depth: 2
title: Detach a client from one or more inbounds without deleting the client.
url: '#detach-a-client-from-one-or-more-inbounds-without-deleting-the-client'
- depth: 2
title: >-
Replace a client's external links (per-client share links and remote
subscription URLs surfaced in their subscription). Sends the full set;
the server replaces all rows.
url: >-
#replace-a-clients-external-links-per-client-share-links-and-remote-subscription-urls-surfaced-in-their-subscription-sends-the-full-set-the-server-replaces-all-rows
- depth: 2
title: >-
Reset the up/down counters for every client globally. Quotas and expiry
are not affected. Triggers an Xray restart if any counter actually
moved.
url: >-
#reset-the-updown-counters-for-every-client-globally-quotas-and-expiry-are-not-affected-triggers-an-xray-restart-if-any-counter-actually-moved
- depth: 2
title: >-
Delete every client whose traffic quota is exhausted (used >= total,
when reset is disabled) or whose expiry has passed. Returns the deleted
count and triggers an Xray restart when any client was on a running
inbound.
url: >-
#delete-every-client-whose-traffic-quota-is-exhausted-used--total-when-reset-is-disabled-or-whose-expiry-has-passed-returns-the-deleted-count-and-triggers-an-xray-restart-when-any-client-was-on-a-running-inbound
- depth: 2
title: >-
Delete every client that is not attached to any inbound, along with its
traffic record, IP log, and external links. Useful for clearing clients
left unattached after their inbounds were removed. Returns the deleted
count. Cannot be undone.
url: >-
#delete-every-client-that-is-not-attached-to-any-inbound-along-with-its-traffic-record-ip-log-and-external-links-useful-for-clearing-clients-left-unattached-after-their-inbounds-were-removed-returns-the-deleted-count-cannot-be-undone
- depth: 2
title: >-
Return every client as a {client, inboundIds} array — the same shape
/bulkCreate and /import accept — so the payload round-trips straight
back through /import. Clients with no inbound attachment are included
with an empty inboundIds list. The UI shows this in a CodeMirror viewer
(copy / download); programmatic callers get the array in obj.
url: >-
#return-every-client-as-a-client-inboundids-array--the-same-shape-bulkcreate-and-import-accept--so-the-payload-round-trips-straight-back-through-import-clients-with-no-inbound-attachment-are-included-with-an-empty-inboundids-list-the-ui-shows-this-in-a-codemirror-viewer-copy--download-programmatic-callers-get-the-array-in-obj
- depth: 2
title: >-
Import clients from a JSON body { "data": "<json>" }, where data is a
string-encoded array produced by /export ([{client, inboundIds}]). Items
with inboundIds are created and attached to those inbounds; items with
an empty inboundIds list are restored as unattached client records.
Existing emails are never overwritten — they are returned in skipped.
Triggers a single Xray restart at the end if any target inbound was
running.
url: >-
#import-clients-from-a-json-body--data-json--where-data-is-a-string-encoded-array-produced-by-export-client-inboundids-items-with-inboundids-are-created-and-attached-to-those-inbounds-items-with-an-empty-inboundids-list-are-restored-as-unattached-client-records-existing-emails-are-never-overwritten--they-are-returned-in-skipped-triggers-a-single-xray-restart-at-the-end-if-any-target-inbound-was-running
- depth: 2
title: >-
Shift expiry and/or traffic quota for many clients in one call.
addDays/addBytes may be negative. Clients with unlimited expiry
(expiryTime=0) or unlimited traffic (totalGB=0) are skipped for the
corresponding field — bulk extend never converts unlimited to limited.
The optional flow directive sets the XTLS flow on every client: "none"
clears it, "xtls-rprx-vision"/"xtls-rprx-vision-udp443" set it where the
inbound supports it (omit or "" to leave it unchanged). Returns the
adjusted count and per-email skip reasons.
url: >-
#shift-expiry-andor-traffic-quota-for-many-clients-in-one-call-adddaysaddbytes-may-be-negative-clients-with-unlimited-expiry-expirytime0-or-unlimited-traffic-totalgb0-are-skipped-for-the-corresponding-field--bulk-extend-never-converts-unlimited-to-limited-the-optional-flow-directive-sets-the-xtls-flow-on-every-client-none-clears-it-xtls-rprx-visionxtls-rprx-vision-udp443-set-it-where-the-inbound-supports-it-omit-or--to-leave-it-unchanged-returns-the-adjusted-count-and-per-email-skip-reasons
- depth: 2
title: >-
Enable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to add each user. Note that enabling a
client whose quota is exhausted or whose expiry has passed only flips
the flag — the traffic loop will disable it again on the next tick.
Returns the changed count and per-email skip reasons.
url: >-
#enable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-add-each-user-note-that-enabling-a-client-whose-quota-is-exhausted-or-whose-expiry-has-passed-only-flips-the-flag--the-traffic-loop-will-disable-it-again-on-the-next-tick-returns-the-changed-count-and-per-email-skip-reasons
- depth: 2
title: >-
Disable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to remove each user. Returns the
changed count and per-email skip reasons.
url: >-
#disable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-remove-each-user-returns-the-changed-count-and-per-email-skip-reasons
- depth: 2
title: >-
Delete many clients in one call. The server processes the list
sequentially so each delete sees the committed state of the previous one
— avoids the race the per-email fan-out had on the panel side. Pass
keepTraffic=true to retain the xray_client_traffic rows after deletion.
url: >-
#delete-many-clients-in-one-call-the-server-processes-the-list-sequentially-so-each-delete-sees-the-committed-state-of-the-previous-one--avoids-the-race-the-per-email-fan-out-had-on-the-panel-side-pass-keeptraffictrue-to-retain-the-xray_client_traffic-rows-after-deletion
- depth: 2
title: >-
Create many clients in one call. Body is a JSON array of {client,
inboundIds} payloads — the same shape /add accepts. Items are processed
sequentially; per-email skip reasons are returned for items that fail
(e.g., duplicate email). Triggers a single Xray restart at the end if
any inbound was running.
url: >-
#create-many-clients-in-one-call-body-is-a-json-array-of-client-inboundids-payloads--the-same-shape-add-accepts-items-are-processed-sequentially-per-email-skip-reasons-are-returned-for-items-that-fail-eg-duplicate-email-triggers-a-single-xray-restart-at-the-end-if-any-inbound-was-running
- depth: 2
title: >-
Add many clients to a group in one call. Updates clients.group_name and
patches the matching client entry inside every owning inbound's settings
JSON in a single transaction. If the group name does not yet exist (in
client_groups or as a derived label), it is auto-created as a persistent
group. To clear the group label, use /groups/bulkRemove instead.
url: >-
#add-many-clients-to-a-group-in-one-call-updates-clientsgroup_name-and-patches-the-matching-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-if-the-group-name-does-not-yet-exist-in-client_groups-or-as-a-derived-label-it-is-auto-created-as-a-persistent-group-to-clear-the-group-label-use-groupsbulkremove-instead
- depth: 2
title: >-
Clear the group label on many clients in one call. Inverse of
/groups/bulkAdd. Clients themselves are kept — only the group label is
cleared from clients.group_name and from each owning inbound's settings
JSON. Groups become empty if all their members are removed.
url: >-
#clear-the-group-label-on-many-clients-in-one-call-inverse-of-groupsbulkadd-clients-themselves-are-kept--only-the-group-label-is-cleared-from-clientsgroup_name-and-from-each-owning-inbounds-settings-json-groups-become-empty-if-all-their-members-are-removed
- depth: 2
title: >-
Attach many existing clients to many inbounds in one call. Each client
keeps its identity (email/UUID/password/subId) and a shared traffic row;
all clients are added to a target inbound in a single AddInboundClient
call. Clients already present on a target are reported under skipped.
Returns per-email attached/skipped/errors lists and triggers a single
Xray restart if any target inbound was running.
url: >-
#attach-many-existing-clients-to-many-inbounds-in-one-call-each-client-keeps-its-identity-emailuuidpasswordsubid-and-a-shared-traffic-row-all-clients-are-added-to-a-target-inbound-in-a-single-addinboundclient-call-clients-already-present-on-a-target-are-reported-under-skipped-returns-per-email-attachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- depth: 2
title: >-
Mirror of bulkAttach: detach many existing clients from many inbounds in
one call. For each email, intersects the client's current inbounds with
the requested set and detaches from those only; (email, inbound) pairs
where the client is not currently attached are silently no-ops. Emails
not attached to any of the requested inbounds are reported under
skipped. Client records are kept even if they become orphaned — use
bulkDel for full removal. Returns per-email detached/skipped/errors
lists and triggers a single Xray restart if any target inbound was
running.
url: >-
#mirror-of-bulkattach-detach-many-existing-clients-from-many-inbounds-in-one-call-for-each-email-intersects-the-clients-current-inbounds-with-the-requested-set-and-detaches-from-those-only-email-inbound-pairs-where-the-client-is-not-currently-attached-are-silently-no-ops-emails-not-attached-to-any-of-the-requested-inbounds-are-reported-under-skipped-client-records-are-kept-even-if-they-become-orphaned--use-bulkdel-for-full-removal-returns-per-email-detachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- depth: 2
title: >-
Zero up/down counters for many clients in one call. Loops the
single-reset path so each client is re-enabled across its attached
inbounds and pushed to Xray/remote nodes. Returns the count of
successfully reset clients.
url: >-
#zero-updown-counters-for-many-clients-in-one-call-loops-the-single-reset-path-so-each-client-is-re-enabled-across-its-attached-inbounds-and-pushed-to-xrayremote-nodes-returns-the-count-of-successfully-reset-clients
- depth: 2
title: >-
List all client groups with their member counts. Merges persisted groups
(rows in client_groups, including empty placeholders) with the distinct
group_name values currently set on clients. Sorted alphabetically
(case-insensitive).
url: >-
#list-all-client-groups-with-their-member-counts-merges-persisted-groups-rows-in-client_groups-including-empty-placeholders-with-the-distinct-group_name-values-currently-set-on-clients-sorted-alphabetically-case-insensitive
- depth: 2
title: >-
Return just the email list of clients that currently belong to the given
group. Useful for fanning a single bulk action over an entire group
without round-tripping the full client list.
url: >-
#return-just-the-email-list-of-clients-that-currently-belong-to-the-given-group-useful-for-fanning-a-single-bulk-action-over-an-entire-group-without-round-tripping-the-full-client-list
- depth: 2
title: >-
Create a new empty (placeholder) group. The group becomes selectable in
client forms and the filter drawer even before any client is added to
it. Errors if a group with the same name already exists.
url: >-
#create-a-new-empty-placeholder-group-the-group-becomes-selectable-in-client-forms-and-the-filter-drawer-even-before-any-client-is-added-to-it-errors-if-a-group-with-the-same-name-already-exists
- depth: 2
title: >-
Rename a group. The new name is applied to the client_groups row AND
propagated to every matching client (both clients.group_name and the
client entry inside every owning inbound's settings JSON) in a single
transaction. Returns the number of clients whose label was updated.
url: >-
#rename-a-group-the-new-name-is-applied-to-the-client_groups-row-and-propagated-to-every-matching-client-both-clientsgroup_name-and-the-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-returns-the-number-of-clients-whose-label-was-updated
- depth: 2
title: >-
Remove a group. Deletes the client_groups row and clears the group label
from every matching client (both clients.group_name and the inbound
settings JSON). The clients themselves are NOT deleted — use /bulkDel
after filtering by group for that. Returns the count of clients whose
label was cleared.
url: >-
#remove-a-group-deletes-the-client_groups-row-and-clears-the-group-label-from-every-matching-client-both-clientsgroup_name-and-the-inbound-settings-json-the-clients-themselves-are-not-deleted--use-bulkdel-after-filtering-by-group-for-that-returns-the-count-of-clients-whose-label-was-cleared
- depth: 2
title: >-
Zero out a single clients up/down counters. Re-enables the client
across every attached inbound and pushes the change to Xray (or the
remote node) so depleted users can connect again immediately.
url: >-
#zero-out-a-single-clients-updown-counters-re-enables-the-client-across-every-attached-inbound-and-pushes-the-change-to-xray-or-the-remote-node-so-depleted-users-can-connect-again-immediately
- depth: 2
title: >-
Manually adjust a clients upload + download counters. Useful for
migrations from external accounting systems.
url: >-
#manually-adjust-a-clients-upload--download-counters-useful-for-migrations-from-external-accounting-systems
- depth: 2
title: >-
List source IPs that have connected with the given clients credentials.
Returns an array of "ip (timestamp)" strings.
url: >-
#list-source-ips-that-have-connected-with-the-given-clients-credentials-returns-an-array-of-ip-timestamp-strings
- depth: 2
title: Reset the recorded IP list for a client.
url: '#reset-the-recorded-ip-list-for-a-client'
- depth: 2
title: >-
List the emails of currently connected clients (last seen within the
heartbeat window), deduped across every node.
url: >-
#list-the-emails-of-currently-connected-clients-last-seen-within-the-heartbeat-window-deduped-across-every-node
- depth: 2
title: >-
Online client emails grouped by the panelGuid of the node that
physically hosts each client. The local panel uses its own GUID; each
node (at any depth in a chain) uses its GUID. Lets the inbounds page
attribute online status to the real node instead of the intermediate one
it syncs through.
url: >-
#online-client-emails-grouped-by-the-panelguid-of-the-node-that-physically-hosts-each-client-the-local-panel-uses-its-own-guid-each-node-at-any-depth-in-a-chain-uses-its-guid-lets-the-inbounds-page-attribute-online-status-to-the-real-node-instead-of-the-intermediate-one-it-syncs-through
- depth: 2
title: >-
Per-client source IPs grouped by the panelGuid of the node that observed
them. Lets the central panel attribute and enforce per-client IP limits
using the real visitor IPs each node sees, instead of the address of the
intermediate panel it syncs through.
url: >-
#per-client-source-ips-grouped-by-the-panelguid-of-the-node-that-observed-them-lets-the-central-panel-attribute-and-enforce-per-client-ip-limits-using-the-real-visitor-ips-each-node-sees-instead-of-the-address-of-the-intermediate-panel-it-syncs-through
- depth: 2
title: >-
Inbound tags that carried traffic within the heartbeat window, grouped
by the hosting node's panelGuid. Pairs with onlinesByGuid so the
inbounds page only marks a multi-inbound client online on the inbounds
it actually used. Nodes that do not report per-inbound activity are
absent.
url: >-
#inbound-tags-that-carried-traffic-within-the-heartbeat-window-grouped-by-the-hosting-nodes-panelguid-pairs-with-onlinesbyguid-so-the-inbounds-page-only-marks-a-multi-inbound-client-online-on-the-inbounds-it-actually-used-nodes-that-do-not-report-per-inbound-activity-are-absent
- depth: 2
title: Map of client email → last-seen unix timestamp.
url: '#map-of-client-email--last-seen-unix-timestamp'
- depth: 2
title: Traffic counters for a client identified by email.
url: '#traffic-counters-for-a-client-identified-by-email'
- depth: 2
title: >-
Return every protocol URL (vless://, vmess://, trojan://, ss://,
hysteria://, hy2://) for clients matching the subscription ID. Same
result set as /sub/<subId>, but as a JSON array — no base64. When an
inbound has streamSettings.externalProxy set, one URL is emitted per
external proxy. Empty array when the subId has no enabled clients.
url: >-
#return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-subsubid-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
- depth: 2
title: >-
Return every URL for one client across all attached inbounds — the same
strings the Copy URL button copies in the panel UI. Supported protocols:
vmess, vless, trojan, shadowsocks, hysteria. If
streamSettings.externalProxy is set, returns one URL per external proxy.
Protocols without a URL form (socks, http, mixed, wireguard, dokodemo,
tunnel) contribute nothing.
url: >-
#return-every-url-for-one-client-across-all-attached-inbounds--the-same-strings-the-copy-url-button-copies-in-the-panel-ui-supported-protocols-vmess-vless-trojan-shadowsocks-hysteria-if-streamsettingsexternalproxy-is-set-returns-one-url-per-external-proxy-protocols-without-a-url-form-socks-http-mixed-wireguard-dokodemo-tunnel-contribute-nothing
structuredData:
headings:
- content: >-
List every client with its attached inbound IDs and traffic record.
The reverse field, if set, is returned as a nested JSON object (legacy
JSON-encoded-string form is still accepted on write).
id: >-
list-every-client-with-its-attached-inbound-ids-and-traffic-record-the-reverse-field-if-set-is-returned-as-a-nested-json-object-legacy-json-encoded-string-form-is-still-accepted-on-write
- content: >-
Filter, sort, and paginate clients on the server. Each item is a slim
row (no uuid/password/auth/flow/security/reverse/tgId) so the clients
page can ship 25-ish rows in a few KB instead of the full table. The
response also includes a summary computed across the full DB row set
so dashboard counters stay stable as the user paginates or filters.
Page size capped at 200; fetch /get/:email to obtain the full
per-client payload for an edit/info modal.
id: >-
filter-sort-and-paginate-clients-on-the-server-each-item-is-a-slim-row-no-uuidpasswordauthflowsecurityreversetgid-so-the-clients-page-can-ship-25-ish-rows-in-a-few-kb-instead-of-the-full-table-the-response-also-includes-a-summary-computed-across-the-full-db-row-set-so-dashboard-counters-stay-stable-as-the-user-paginates-or-filters-page-size-capped-at-200-fetch-getemail-to-obtain-the-full-per-client-payload-for-an-editinfo-modal
- content: >-
Fetch one client by email, including the inbound IDs and external
config IDs it is attached to.
id: >-
fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to
- content: >-
Create a new client and attach it to one or more inbounds in a single
call. Body is JSON. Per-protocol secrets (UUID for VLESS/VMess,
password for Trojan/Shadowsocks, auth for Hysteria) are generated
server-side when omitted, so callers can send only the universal
fields.
id: >-
create-a-new-client-and-attach-it-to-one-or-more-inbounds-in-a-single-call-body-is-json-per-protocol-secrets-uuid-for-vlessvmess-password-for-trojanshadowsocks-auth-for-hysteria-are-generated-server-side-when-omitted-so-callers-can-send-only-the-universal-fields
- content: >-
Update an existing client by email. Changes propagate to every
attached inbound. Body is the JSON client payload — supply the full
set of fields you want to keep (the server replaces the row, it does
not patch).
id: >-
update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
- content: >-
Delete a client by email. Removes it from every attached inbound and
drops its traffic record unless keepTraffic=1 is passed.
id: >-
delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
- content: >-
Attach an existing client to one or more additional inbounds. Body is
JSON.
id: >-
attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json
- content: Detach a client from one or more inbounds without deleting the client.
id: detach-a-client-from-one-or-more-inbounds-without-deleting-the-client
- content: >-
Replace a client's external links (per-client share links and remote
subscription URLs surfaced in their subscription). Sends the full set;
the server replaces all rows.
id: >-
replace-a-clients-external-links-per-client-share-links-and-remote-subscription-urls-surfaced-in-their-subscription-sends-the-full-set-the-server-replaces-all-rows
- content: >-
Reset the up/down counters for every client globally. Quotas and
expiry are not affected. Triggers an Xray restart if any counter
actually moved.
id: >-
reset-the-updown-counters-for-every-client-globally-quotas-and-expiry-are-not-affected-triggers-an-xray-restart-if-any-counter-actually-moved
- content: >-
Delete every client whose traffic quota is exhausted (used >= total,
when reset is disabled) or whose expiry has passed. Returns the
deleted count and triggers an Xray restart when any client was on a
running inbound.
id: >-
delete-every-client-whose-traffic-quota-is-exhausted-used--total-when-reset-is-disabled-or-whose-expiry-has-passed-returns-the-deleted-count-and-triggers-an-xray-restart-when-any-client-was-on-a-running-inbound
- content: >-
Delete every client that is not attached to any inbound, along with
its traffic record, IP log, and external links. Useful for clearing
clients left unattached after their inbounds were removed. Returns the
deleted count. Cannot be undone.
id: >-
delete-every-client-that-is-not-attached-to-any-inbound-along-with-its-traffic-record-ip-log-and-external-links-useful-for-clearing-clients-left-unattached-after-their-inbounds-were-removed-returns-the-deleted-count-cannot-be-undone
- content: >-
Return every client as a {client, inboundIds} array — the same shape
/bulkCreate and /import accept — so the payload round-trips straight
back through /import. Clients with no inbound attachment are included
with an empty inboundIds list. The UI shows this in a CodeMirror
viewer (copy / download); programmatic callers get the array in obj.
id: >-
return-every-client-as-a-client-inboundids-array--the-same-shape-bulkcreate-and-import-accept--so-the-payload-round-trips-straight-back-through-import-clients-with-no-inbound-attachment-are-included-with-an-empty-inboundids-list-the-ui-shows-this-in-a-codemirror-viewer-copy--download-programmatic-callers-get-the-array-in-obj
- content: >-
Import clients from a JSON body { "data": "<json>" }, where data is a
string-encoded array produced by /export ([{client, inboundIds}]).
Items with inboundIds are created and attached to those inbounds;
items with an empty inboundIds list are restored as unattached client
records. Existing emails are never overwritten — they are returned in
skipped. Triggers a single Xray restart at the end if any target
inbound was running.
id: >-
import-clients-from-a-json-body--data-json--where-data-is-a-string-encoded-array-produced-by-export-client-inboundids-items-with-inboundids-are-created-and-attached-to-those-inbounds-items-with-an-empty-inboundids-list-are-restored-as-unattached-client-records-existing-emails-are-never-overwritten--they-are-returned-in-skipped-triggers-a-single-xray-restart-at-the-end-if-any-target-inbound-was-running
- content: >-
Shift expiry and/or traffic quota for many clients in one call.
addDays/addBytes may be negative. Clients with unlimited expiry
(expiryTime=0) or unlimited traffic (totalGB=0) are skipped for the
corresponding field — bulk extend never converts unlimited to limited.
The optional flow directive sets the XTLS flow on every client: "none"
clears it, "xtls-rprx-vision"/"xtls-rprx-vision-udp443" set it where
the inbound supports it (omit or "" to leave it unchanged). Returns
the adjusted count and per-email skip reasons.
id: >-
shift-expiry-andor-traffic-quota-for-many-clients-in-one-call-adddaysaddbytes-may-be-negative-clients-with-unlimited-expiry-expirytime0-or-unlimited-traffic-totalgb0-are-skipped-for-the-corresponding-field--bulk-extend-never-converts-unlimited-to-limited-the-optional-flow-directive-sets-the-xtls-flow-on-every-client-none-clears-it-xtls-rprx-visionxtls-rprx-vision-udp443-set-it-where-the-inbound-supports-it-omit-or--to-leave-it-unchanged-returns-the-adjusted-count-and-per-email-skip-reasons
- content: >-
Enable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to add each user. Note that enabling
a client whose quota is exhausted or whose expiry has passed only
flips the flag — the traffic loop will disable it again on the next
tick. Returns the changed count and per-email skip reasons.
id: >-
enable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-add-each-user-note-that-enabling-a-client-whose-quota-is-exhausted-or-whose-expiry-has-passed-only-flips-the-flag--the-traffic-loop-will-disable-it-again-on-the-next-tick-returns-the-changed-count-and-per-email-skip-reasons
- content: >-
Disable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to remove each user. Returns the
changed count and per-email skip reasons.
id: >-
disable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-remove-each-user-returns-the-changed-count-and-per-email-skip-reasons
- content: >-
Delete many clients in one call. The server processes the list
sequentially so each delete sees the committed state of the previous
one — avoids the race the per-email fan-out had on the panel side.
Pass keepTraffic=true to retain the xray_client_traffic rows after
deletion.
id: >-
delete-many-clients-in-one-call-the-server-processes-the-list-sequentially-so-each-delete-sees-the-committed-state-of-the-previous-one--avoids-the-race-the-per-email-fan-out-had-on-the-panel-side-pass-keeptraffictrue-to-retain-the-xray_client_traffic-rows-after-deletion
- content: >-
Create many clients in one call. Body is a JSON array of {client,
inboundIds} payloads — the same shape /add accepts. Items are
processed sequentially; per-email skip reasons are returned for items
that fail (e.g., duplicate email). Triggers a single Xray restart at
the end if any inbound was running.
id: >-
create-many-clients-in-one-call-body-is-a-json-array-of-client-inboundids-payloads--the-same-shape-add-accepts-items-are-processed-sequentially-per-email-skip-reasons-are-returned-for-items-that-fail-eg-duplicate-email-triggers-a-single-xray-restart-at-the-end-if-any-inbound-was-running
- content: >-
Add many clients to a group in one call. Updates clients.group_name
and patches the matching client entry inside every owning inbound's
settings JSON in a single transaction. If the group name does not yet
exist (in client_groups or as a derived label), it is auto-created as
a persistent group. To clear the group label, use /groups/bulkRemove
instead.
id: >-
add-many-clients-to-a-group-in-one-call-updates-clientsgroup_name-and-patches-the-matching-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-if-the-group-name-does-not-yet-exist-in-client_groups-or-as-a-derived-label-it-is-auto-created-as-a-persistent-group-to-clear-the-group-label-use-groupsbulkremove-instead
- content: >-
Clear the group label on many clients in one call. Inverse of
/groups/bulkAdd. Clients themselves are kept — only the group label is
cleared from clients.group_name and from each owning inbound's
settings JSON. Groups become empty if all their members are removed.
id: >-
clear-the-group-label-on-many-clients-in-one-call-inverse-of-groupsbulkadd-clients-themselves-are-kept--only-the-group-label-is-cleared-from-clientsgroup_name-and-from-each-owning-inbounds-settings-json-groups-become-empty-if-all-their-members-are-removed
- content: >-
Attach many existing clients to many inbounds in one call. Each client
keeps its identity (email/UUID/password/subId) and a shared traffic
row; all clients are added to a target inbound in a single
AddInboundClient call. Clients already present on a target are
reported under skipped. Returns per-email attached/skipped/errors
lists and triggers a single Xray restart if any target inbound was
running.
id: >-
attach-many-existing-clients-to-many-inbounds-in-one-call-each-client-keeps-its-identity-emailuuidpasswordsubid-and-a-shared-traffic-row-all-clients-are-added-to-a-target-inbound-in-a-single-addinboundclient-call-clients-already-present-on-a-target-are-reported-under-skipped-returns-per-email-attachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- content: >-
Mirror of bulkAttach: detach many existing clients from many inbounds
in one call. For each email, intersects the client's current inbounds
with the requested set and detaches from those only; (email, inbound)
pairs where the client is not currently attached are silently no-ops.
Emails not attached to any of the requested inbounds are reported
under skipped. Client records are kept even if they become orphaned —
use bulkDel for full removal. Returns per-email
detached/skipped/errors lists and triggers a single Xray restart if
any target inbound was running.
id: >-
mirror-of-bulkattach-detach-many-existing-clients-from-many-inbounds-in-one-call-for-each-email-intersects-the-clients-current-inbounds-with-the-requested-set-and-detaches-from-those-only-email-inbound-pairs-where-the-client-is-not-currently-attached-are-silently-no-ops-emails-not-attached-to-any-of-the-requested-inbounds-are-reported-under-skipped-client-records-are-kept-even-if-they-become-orphaned--use-bulkdel-for-full-removal-returns-per-email-detachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- content: >-
Zero up/down counters for many clients in one call. Loops the
single-reset path so each client is re-enabled across its attached
inbounds and pushed to Xray/remote nodes. Returns the count of
successfully reset clients.
id: >-
zero-updown-counters-for-many-clients-in-one-call-loops-the-single-reset-path-so-each-client-is-re-enabled-across-its-attached-inbounds-and-pushed-to-xrayremote-nodes-returns-the-count-of-successfully-reset-clients
- content: >-
List all client groups with their member counts. Merges persisted
groups (rows in client_groups, including empty placeholders) with the
distinct group_name values currently set on clients. Sorted
alphabetically (case-insensitive).
id: >-
list-all-client-groups-with-their-member-counts-merges-persisted-groups-rows-in-client_groups-including-empty-placeholders-with-the-distinct-group_name-values-currently-set-on-clients-sorted-alphabetically-case-insensitive
- content: >-
Return just the email list of clients that currently belong to the
given group. Useful for fanning a single bulk action over an entire
group without round-tripping the full client list.
id: >-
return-just-the-email-list-of-clients-that-currently-belong-to-the-given-group-useful-for-fanning-a-single-bulk-action-over-an-entire-group-without-round-tripping-the-full-client-list
- content: >-
Create a new empty (placeholder) group. The group becomes selectable
in client forms and the filter drawer even before any client is added
to it. Errors if a group with the same name already exists.
id: >-
create-a-new-empty-placeholder-group-the-group-becomes-selectable-in-client-forms-and-the-filter-drawer-even-before-any-client-is-added-to-it-errors-if-a-group-with-the-same-name-already-exists
- content: >-
Rename a group. The new name is applied to the client_groups row AND
propagated to every matching client (both clients.group_name and the
client entry inside every owning inbound's settings JSON) in a single
transaction. Returns the number of clients whose label was updated.
id: >-
rename-a-group-the-new-name-is-applied-to-the-client_groups-row-and-propagated-to-every-matching-client-both-clientsgroup_name-and-the-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-returns-the-number-of-clients-whose-label-was-updated
- content: >-
Remove a group. Deletes the client_groups row and clears the group
label from every matching client (both clients.group_name and the
inbound settings JSON). The clients themselves are NOT deleted — use
/bulkDel after filtering by group for that. Returns the count of
clients whose label was cleared.
id: >-
remove-a-group-deletes-the-client_groups-row-and-clears-the-group-label-from-every-matching-client-both-clientsgroup_name-and-the-inbound-settings-json-the-clients-themselves-are-not-deleted--use-bulkdel-after-filtering-by-group-for-that-returns-the-count-of-clients-whose-label-was-cleared
- content: >-
Zero out a single clients up/down counters. Re-enables the client
across every attached inbound and pushes the change to Xray (or the
remote node) so depleted users can connect again immediately.
id: >-
zero-out-a-single-clients-updown-counters-re-enables-the-client-across-every-attached-inbound-and-pushes-the-change-to-xray-or-the-remote-node-so-depleted-users-can-connect-again-immediately
- content: >-
Manually adjust a clients upload + download counters. Useful for
migrations from external accounting systems.
id: >-
manually-adjust-a-clients-upload--download-counters-useful-for-migrations-from-external-accounting-systems
- content: >-
List source IPs that have connected with the given clients
credentials. Returns an array of "ip (timestamp)" strings.
id: >-
list-source-ips-that-have-connected-with-the-given-clients-credentials-returns-an-array-of-ip-timestamp-strings
- content: Reset the recorded IP list for a client.
id: reset-the-recorded-ip-list-for-a-client
- content: >-
List the emails of currently connected clients (last seen within the
heartbeat window), deduped across every node.
id: >-
list-the-emails-of-currently-connected-clients-last-seen-within-the-heartbeat-window-deduped-across-every-node
- content: >-
Online client emails grouped by the panelGuid of the node that
physically hosts each client. The local panel uses its own GUID; each
node (at any depth in a chain) uses its GUID. Lets the inbounds page
attribute online status to the real node instead of the intermediate
one it syncs through.
id: >-
online-client-emails-grouped-by-the-panelguid-of-the-node-that-physically-hosts-each-client-the-local-panel-uses-its-own-guid-each-node-at-any-depth-in-a-chain-uses-its-guid-lets-the-inbounds-page-attribute-online-status-to-the-real-node-instead-of-the-intermediate-one-it-syncs-through
- content: >-
Per-client source IPs grouped by the panelGuid of the node that
observed them. Lets the central panel attribute and enforce per-client
IP limits using the real visitor IPs each node sees, instead of the
address of the intermediate panel it syncs through.
id: >-
per-client-source-ips-grouped-by-the-panelguid-of-the-node-that-observed-them-lets-the-central-panel-attribute-and-enforce-per-client-ip-limits-using-the-real-visitor-ips-each-node-sees-instead-of-the-address-of-the-intermediate-panel-it-syncs-through
- content: >-
Inbound tags that carried traffic within the heartbeat window, grouped
by the hosting node's panelGuid. Pairs with onlinesByGuid so the
inbounds page only marks a multi-inbound client online on the inbounds
it actually used. Nodes that do not report per-inbound activity are
absent.
id: >-
inbound-tags-that-carried-traffic-within-the-heartbeat-window-grouped-by-the-hosting-nodes-panelguid-pairs-with-onlinesbyguid-so-the-inbounds-page-only-marks-a-multi-inbound-client-online-on-the-inbounds-it-actually-used-nodes-that-do-not-report-per-inbound-activity-are-absent
- content: Map of client email → last-seen unix timestamp.
id: map-of-client-email--last-seen-unix-timestamp
- content: Traffic counters for a client identified by email.
id: traffic-counters-for-a-client-identified-by-email
- content: >-
Return every protocol URL (vless://, vmess://, trojan://, ss://,
hysteria://, hy2://) for clients matching the subscription ID. Same
result set as /sub/<subId>, but as a JSON array — no base64. When an
inbound has streamSettings.externalProxy set, one URL is emitted per
external proxy. Empty array when the subId has no enabled clients.
id: >-
return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-subsubid-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
- content: >-
Return every URL for one client across all attached inbounds — the
same strings the Copy URL button copies in the panel UI. Supported
protocols: vmess, vless, trojan, shadowsocks, hysteria. If
streamSettings.externalProxy is set, returns one URL per external
proxy. Protocols without a URL form (socks, http, mixed, wireguard,
dokodemo, tunnel) contribute nothing.
id: >-
return-every-url-for-one-client-across-all-attached-inbounds--the-same-strings-the-copy-url-button-copies-in-the-panel-ui-supported-protocols-vmess-vless-trojan-shadowsocks-hysteria-if-streamsettingsexternalproxy-is-set-returns-one-url-per-external-proxy-protocols-without-a-url-form-socks-http-mixed-wireguard-dokodemo-tunnel-contribute-nothing
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/clients/list","method":"get"},{"path":"/panel/api/clients/list/paged","method":"get"},{"path":"/panel/api/clients/get/{email}","method":"get"},{"path":"/panel/api/clients/add","method":"post"},{"path":"/panel/api/clients/update/{email}","method":"post"},{"path":"/panel/api/clients/del/{email}","method":"post"},{"path":"/panel/api/clients/{email}/attach","method":"post"},{"path":"/panel/api/clients/{email}/detach","method":"post"},{"path":"/panel/api/clients/{email}/externalLinks","method":"post"},{"path":"/panel/api/clients/resetAllTraffics","method":"post"},{"path":"/panel/api/clients/delDepleted","method":"post"},{"path":"/panel/api/clients/delOrphans","method":"post"},{"path":"/panel/api/clients/export","method":"get"},{"path":"/panel/api/clients/import","method":"post"},{"path":"/panel/api/clients/bulkAdjust","method":"post"},{"path":"/panel/api/clients/bulkEnable","method":"post"},{"path":"/panel/api/clients/bulkDisable","method":"post"},{"path":"/panel/api/clients/bulkDel","method":"post"},{"path":"/panel/api/clients/bulkCreate","method":"post"},{"path":"/panel/api/clients/groups/bulkAdd","method":"post"},{"path":"/panel/api/clients/groups/bulkRemove","method":"post"},{"path":"/panel/api/clients/bulkAttach","method":"post"},{"path":"/panel/api/clients/bulkDetach","method":"post"},{"path":"/panel/api/clients/bulkResetTraffic","method":"post"},{"path":"/panel/api/clients/groups","method":"get"},{"path":"/panel/api/clients/groups/{name}/emails","method":"get"},{"path":"/panel/api/clients/groups/create","method":"post"},{"path":"/panel/api/clients/groups/rename","method":"post"},{"path":"/panel/api/clients/groups/delete","method":"post"},{"path":"/panel/api/clients/resetTraffic/{email}","method":"post"},{"path":"/panel/api/clients/updateTraffic/{email}","method":"post"},{"path":"/panel/api/clients/ips/{email}","method":"post"},{"path":"/panel/api/clients/clearIps/{email}","method":"post"},{"path":"/panel/api/clients/onlines","method":"post"},{"path":"/panel/api/clients/onlinesByGuid","method":"post"},{"path":"/panel/api/clients/clientIpsByGuid","method":"post"},{"path":"/panel/api/clients/activeInbounds","method":"post"},{"path":"/panel/api/clients/lastOnline","method":"post"},{"path":"/panel/api/clients/traffic/{email}","method":"get"},{"path":"/panel/api/clients/subLinks/{subId}","method":"get"},{"path":"/panel/api/clients/links/{email}","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,108 @@
---
title: Hosts
description: >-
Per-inbound override endpoints. Each enabled host renders one extra
subscription link/proxy with its own address/port/TLS, superseding the legacy
externalProxy array. All endpoints under /panel/api/hosts.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every host across all inbounds, grouped by inbound then ordered by
sort order.
url: >-
#list-every-host-across-all-inbounds-grouped-by-inbound-then-ordered-by-sort-order
- depth: 2
title: Fetch a single host by ID.
url: '#fetch-a-single-host-by-id'
- depth: 2
title: Fetch one inbound's hosts, ordered by sort order then id.
url: '#fetch-one-inbounds-hosts-ordered-by-sort-order-then-id'
- depth: 2
title: Distinct, sorted set of tags used across all hosts.
url: '#distinct-sorted-set-of-tags-used-across-all-hosts'
- depth: 2
title: >-
Create a host on an inbound. inboundId and remark are required; security
defaults to "same" (inherit the inbound).
url: >-
#create-a-host-on-an-inbound-inboundid-and-remark-are-required-security-defaults-to-same-inherit-the-inbound
- depth: 2
title: >-
Replace a hosts content. The inbound and sort order are immutable here
(use /reorder for ordering).
url: >-
#replace-a-hosts-content-the-inbound-and-sort-order-are-immutable-here-use-reorder-for-ordering
- depth: 2
title: Delete a host.
url: '#delete-a-host'
- depth: 2
title: >-
Enable or disable a single host (disabled hosts are skipped in
subscriptions).
url: >-
#enable-or-disable-a-single-host-disabled-hosts-are-skipped-in-subscriptions
- depth: 2
title: Set host sort order by the position of each id in the array.
url: '#set-host-sort-order-by-the-position-of-each-id-in-the-array'
- depth: 2
title: Enable or disable many hosts in one call.
url: '#enable-or-disable-many-hosts-in-one-call'
- depth: 2
title: Delete many hosts in one call.
url: '#delete-many-hosts-in-one-call'
structuredData:
headings:
- content: >-
List every host across all inbounds, grouped by inbound then ordered
by sort order.
id: >-
list-every-host-across-all-inbounds-grouped-by-inbound-then-ordered-by-sort-order
- content: Fetch a single host by ID.
id: fetch-a-single-host-by-id
- content: Fetch one inbound's hosts, ordered by sort order then id.
id: fetch-one-inbounds-hosts-ordered-by-sort-order-then-id
- content: Distinct, sorted set of tags used across all hosts.
id: distinct-sorted-set-of-tags-used-across-all-hosts
- content: >-
Create a host on an inbound. inboundId and remark are required;
security defaults to "same" (inherit the inbound).
id: >-
create-a-host-on-an-inbound-inboundid-and-remark-are-required-security-defaults-to-same-inherit-the-inbound
- content: >-
Replace a hosts content. The inbound and sort order are immutable
here (use /reorder for ordering).
id: >-
replace-a-hosts-content-the-inbound-and-sort-order-are-immutable-here-use-reorder-for-ordering
- content: Delete a host.
id: delete-a-host
- content: >-
Enable or disable a single host (disabled hosts are skipped in
subscriptions).
id: >-
enable-or-disable-a-single-host-disabled-hosts-are-skipped-in-subscriptions
- content: Set host sort order by the position of each id in the array.
id: set-host-sort-order-by-the-position-of-each-id-in-the-array
- content: Enable or disable many hosts in one call.
id: enable-or-disable-many-hosts-in-one-call
- content: Delete many hosts in one call.
id: delete-many-hosts-in-one-call
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/hosts/list","method":"get"},{"path":"/panel/api/hosts/get/{id}","method":"get"},{"path":"/panel/api/hosts/byInbound/{inboundId}","method":"get"},{"path":"/panel/api/hosts/tags","method":"get"},{"path":"/panel/api/hosts/add","method":"post"},{"path":"/panel/api/hosts/update/{id}","method":"post"},{"path":"/panel/api/hosts/del/{id}","method":"post"},{"path":"/panel/api/hosts/setEnable/{id}","method":"post"},{"path":"/panel/api/hosts/reorder","method":"post"},{"path":"/panel/api/hosts/bulk/setEnable","method":"post"},{"path":"/panel/api/hosts/bulk/del","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,242 @@
---
title: Inbounds
description: >-
Manage inbound configurations and their clients. All endpoints live under
/panel/api/inbounds and require a logged-in session or Bearer token.
Link-generating endpoints honour forwarded headers only when the request comes
from a configured trusted proxy.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every inbound owned by the authenticated user, including each
inbounds clientStats traffic counters. settings, streamSettings, and
sniffing are returned as nested JSON objects (no escaped strings);
legacy callers that send them back as JSON-encoded strings are still
accepted on write.
url: >-
#list-every-inbound-owned-by-the-authenticated-user-including-each-inbounds-clientstats-traffic-counters-settings-streamsettings-and-sniffing-are-returned-as-nested-json-objects-no-escaped-strings-legacy-callers-that-send-them-back-as-json-encoded-strings-are-still-accepted-on-write
- depth: 2
title: >-
Same shape as /list but with settings.clients[] stripped down to {email,
enable, comment} and ClientStats not enriched with UUID/SubId. Use this
for list pages; fetch /get/:id when you need the full per-client payload
(uuid, password, flow, ...).
url: >-
#same-shape-as-list-but-with-settingsclients-stripped-down-to-email-enable-comment-and-clientstats-not-enriched-with-uuidsubid-use-this-for-list-pages-fetch-getid-when-you-need-the-full-per-client-payload-uuid-password-flow-
- depth: 2
title: >-
Lightweight picker projection of the authenticated users inbounds.
Returns id, remark, tag, protocol, port, a server-computed
tlsFlowCapable flag (true for VLESS on TCP with tls or reality, or on
XHTTP with VLESS encryption / vlessenc enabled), and ssMethod (the
Shadowsocks cipher, empty for non-Shadowsocks inbounds — used by the
client UI to generate a valid Shadowsocks 2022 PSK). Use this for
dropdowns and attach pickers — it skips settings, streamSettings, and
clientStats so the payload stays small even on panels with thousands of
clients.
url: >-
#lightweight-picker-projection-of-the-authenticated-users-inbounds-returns-id-remark-tag-protocol-port-a-server-computed-tlsflowcapable-flag-true-for-vless-on-tcp-with-tls-or-reality-or-on-xhttp-with-vless-encryption--vlessenc-enabled-and-ssmethod-the-shadowsocks-cipher-empty-for-non-shadowsocks-inbounds--used-by-the-client-ui-to-generate-a-valid-shadowsocks-2022-psk-use-this-for-dropdowns-and-attach-pickers--it-skips-settings-streamsettings-and-clientstats-so-the-payload-stays-small-even-on-panels-with-thousands-of-clients
- depth: 2
title: Fetch a single inbound by numeric ID.
url: '#fetch-a-single-inbound-by-numeric-id'
- depth: 2
title: >-
Create a new inbound. Send the full inbound payload (protocol, port,
settings, streamSettings, sniffing, remark, expiryTime, total, enable).
settings, streamSettings, and sniffing may be sent as nested JSON
objects (preferred) or as JSON-encoded strings (legacy).
url: >-
#create-a-new-inbound-send-the-full-inbound-payload-protocol-port-settings-streamsettings-sniffing-remark-expirytime-total-enable-settings-streamsettings-and-sniffing-may-be-sent-as-nested-json-objects-preferred-or-as-json-encoded-strings-legacy
- depth: 2
title: Delete an inbound by ID. Also removes its associated client stats rows.
url: '#delete-an-inbound-by-id-also-removes-its-associated-client-stats-rows'
- depth: 2
title: >-
Delete many inbounds in one call. Processes the list sequentially;
failures are reported per id and the rest still proceed. Restarts xray
at most once.
url: >-
#delete-many-inbounds-in-one-call-processes-the-list-sequentially-failures-are-reported-per-id-and-the-rest-still-proceed-restarts-xray-at-most-once
- depth: 2
title: >-
Replace an inbounds configuration. Body shape mirrors /add. Heavy on
inbounds with thousands of clients — prefer /setEnable for enable-only
flips.
url: >-
#replace-an-inbounds-configuration-body-shape-mirrors-add-heavy-on-inbounds-with-thousands-of-clients--prefer-setenable-for-enable-only-flips
- depth: 2
title: >-
Toggle only the enable flag without serialising the whole settings JSON.
Recommended for UI switches on large inbounds.
url: >-
#toggle-only-the-enable-flag-without-serialising-the-whole-settings-json-recommended-for-ui-switches-on-large-inbounds
- depth: 2
title: >-
Zero out upload + download counters for a single inbound. Does not touch
per-client counters.
url: >-
#zero-out-upload--download-counters-for-a-single-inbound-does-not-touch-per-client-counters
- depth: 2
title: >-
Remove every client attached to a single inbound while keeping the
inbound itself. Collects emails from settings.clients[] and feeds them
into the optimized bulk-delete path (runtime user removal + traffic-row
cleanup + SyncInbound). Destructive and cannot be undone.
url: >-
#remove-every-client-attached-to-a-single-inbound-while-keeping-the-inbound-itself-collects-emails-from-settingsclients-and-feeds-them-into-the-optimized-bulk-delete-path-runtime-user-removal--traffic-row-cleanup--syncinbound-destructive-and-cannot-be-undone
- depth: 2
title: >-
Reset upload + download counters on every inbound. Destructive —
accounting history is lost.
url: >-
#reset-upload--download-counters-on-every-inbound-destructive--accounting-history-is-lost
- depth: 2
title: >-
Bulk-import an inbound from a JSON blob (e.g. one exported via the UI).
The body uses form encoding with a single "data" field.
url: >-
#bulk-import-an-inbound-from-a-json-blob-eg-one-exported-via-the-ui-the-body-uses-form-encoding-with-a-single-data-field
- depth: 2
title: >-
Receive a master panel's aggregated per-client usage, keyed by the
master's GUID. Stored in a side table used only for the UI display
overlay and local quota enforcement — never folded into the local
counters that masters poll, so delta accounting stays intact. Called
panel-to-panel by the node traffic sync job.
url: >-
#receive-a-master-panels-aggregated-per-client-usage-keyed-by-the-masters-guid-stored-in-a-side-table-used-only-for-the-ui-display-overlay-and-local-quota-enforcement--never-folded-into-the-local-counters-that-masters-poll-so-delta-accounting-stays-intact-called-panel-to-panel-by-the-node-traffic-sync-job
- depth: 2
title: >-
List the fallback rules attached to a master VLESS/Trojan TCP-TLS
inbound. Each rule links one child inbound (the dest) to optional
SNI/ALPN/path/dest/xver match criteria. When dest is empty the child
inbound's listen+port is used.
url: >-
#list-the-fallback-rules-attached-to-a-master-vlesstrojan-tcp-tls-inbound-each-rule-links-one-child-inbound-the-dest-to-optional-snialpnpathdestxver-match-criteria-when-dest-is-empty-the-child-inbounds-listenport-is-used
- depth: 2
title: >-
Replace the entire fallback list for a master inbound. Body is JSON.
Triggers an Xray restart.
url: >-
#replace-the-entire-fallback-list-for-a-master-inbound-body-is-json-triggers-an-xray-restart
structuredData:
headings:
- content: >-
List every inbound owned by the authenticated user, including each
inbounds clientStats traffic counters. settings, streamSettings, and
sniffing are returned as nested JSON objects (no escaped strings);
legacy callers that send them back as JSON-encoded strings are still
accepted on write.
id: >-
list-every-inbound-owned-by-the-authenticated-user-including-each-inbounds-clientstats-traffic-counters-settings-streamsettings-and-sniffing-are-returned-as-nested-json-objects-no-escaped-strings-legacy-callers-that-send-them-back-as-json-encoded-strings-are-still-accepted-on-write
- content: >-
Same shape as /list but with settings.clients[] stripped down to
{email, enable, comment} and ClientStats not enriched with UUID/SubId.
Use this for list pages; fetch /get/:id when you need the full
per-client payload (uuid, password, flow, ...).
id: >-
same-shape-as-list-but-with-settingsclients-stripped-down-to-email-enable-comment-and-clientstats-not-enriched-with-uuidsubid-use-this-for-list-pages-fetch-getid-when-you-need-the-full-per-client-payload-uuid-password-flow-
- content: >-
Lightweight picker projection of the authenticated users inbounds.
Returns id, remark, tag, protocol, port, a server-computed
tlsFlowCapable flag (true for VLESS on TCP with tls or reality, or on
XHTTP with VLESS encryption / vlessenc enabled), and ssMethod (the
Shadowsocks cipher, empty for non-Shadowsocks inbounds — used by the
client UI to generate a valid Shadowsocks 2022 PSK). Use this for
dropdowns and attach pickers — it skips settings, streamSettings, and
clientStats so the payload stays small even on panels with thousands
of clients.
id: >-
lightweight-picker-projection-of-the-authenticated-users-inbounds-returns-id-remark-tag-protocol-port-a-server-computed-tlsflowcapable-flag-true-for-vless-on-tcp-with-tls-or-reality-or-on-xhttp-with-vless-encryption--vlessenc-enabled-and-ssmethod-the-shadowsocks-cipher-empty-for-non-shadowsocks-inbounds--used-by-the-client-ui-to-generate-a-valid-shadowsocks-2022-psk-use-this-for-dropdowns-and-attach-pickers--it-skips-settings-streamsettings-and-clientstats-so-the-payload-stays-small-even-on-panels-with-thousands-of-clients
- content: Fetch a single inbound by numeric ID.
id: fetch-a-single-inbound-by-numeric-id
- content: >-
Create a new inbound. Send the full inbound payload (protocol, port,
settings, streamSettings, sniffing, remark, expiryTime, total,
enable). settings, streamSettings, and sniffing may be sent as nested
JSON objects (preferred) or as JSON-encoded strings (legacy).
id: >-
create-a-new-inbound-send-the-full-inbound-payload-protocol-port-settings-streamsettings-sniffing-remark-expirytime-total-enable-settings-streamsettings-and-sniffing-may-be-sent-as-nested-json-objects-preferred-or-as-json-encoded-strings-legacy
- content: >-
Delete an inbound by ID. Also removes its associated client stats
rows.
id: delete-an-inbound-by-id-also-removes-its-associated-client-stats-rows
- content: >-
Delete many inbounds in one call. Processes the list sequentially;
failures are reported per id and the rest still proceed. Restarts xray
at most once.
id: >-
delete-many-inbounds-in-one-call-processes-the-list-sequentially-failures-are-reported-per-id-and-the-rest-still-proceed-restarts-xray-at-most-once
- content: >-
Replace an inbounds configuration. Body shape mirrors /add. Heavy on
inbounds with thousands of clients — prefer /setEnable for enable-only
flips.
id: >-
replace-an-inbounds-configuration-body-shape-mirrors-add-heavy-on-inbounds-with-thousands-of-clients--prefer-setenable-for-enable-only-flips
- content: >-
Toggle only the enable flag without serialising the whole settings
JSON. Recommended for UI switches on large inbounds.
id: >-
toggle-only-the-enable-flag-without-serialising-the-whole-settings-json-recommended-for-ui-switches-on-large-inbounds
- content: >-
Zero out upload + download counters for a single inbound. Does not
touch per-client counters.
id: >-
zero-out-upload--download-counters-for-a-single-inbound-does-not-touch-per-client-counters
- content: >-
Remove every client attached to a single inbound while keeping the
inbound itself. Collects emails from settings.clients[] and feeds them
into the optimized bulk-delete path (runtime user removal +
traffic-row cleanup + SyncInbound). Destructive and cannot be undone.
id: >-
remove-every-client-attached-to-a-single-inbound-while-keeping-the-inbound-itself-collects-emails-from-settingsclients-and-feeds-them-into-the-optimized-bulk-delete-path-runtime-user-removal--traffic-row-cleanup--syncinbound-destructive-and-cannot-be-undone
- content: >-
Reset upload + download counters on every inbound. Destructive —
accounting history is lost.
id: >-
reset-upload--download-counters-on-every-inbound-destructive--accounting-history-is-lost
- content: >-
Bulk-import an inbound from a JSON blob (e.g. one exported via the
UI). The body uses form encoding with a single "data" field.
id: >-
bulk-import-an-inbound-from-a-json-blob-eg-one-exported-via-the-ui-the-body-uses-form-encoding-with-a-single-data-field
- content: >-
Receive a master panel's aggregated per-client usage, keyed by the
master's GUID. Stored in a side table used only for the UI display
overlay and local quota enforcement — never folded into the local
counters that masters poll, so delta accounting stays intact. Called
panel-to-panel by the node traffic sync job.
id: >-
receive-a-master-panels-aggregated-per-client-usage-keyed-by-the-masters-guid-stored-in-a-side-table-used-only-for-the-ui-display-overlay-and-local-quota-enforcement--never-folded-into-the-local-counters-that-masters-poll-so-delta-accounting-stays-intact-called-panel-to-panel-by-the-node-traffic-sync-job
- content: >-
List the fallback rules attached to a master VLESS/Trojan TCP-TLS
inbound. Each rule links one child inbound (the dest) to optional
SNI/ALPN/path/dest/xver match criteria. When dest is empty the child
inbound's listen+port is used.
id: >-
list-the-fallback-rules-attached-to-a-master-vlesstrojan-tcp-tls-inbound-each-rule-links-one-child-inbound-the-dest-to-optional-snialpnpathdestxver-match-criteria-when-dest-is-empty-the-child-inbounds-listenport-is-used
- content: >-
Replace the entire fallback list for a master inbound. Body is JSON.
Triggers an Xray restart.
id: >-
replace-the-entire-fallback-list-for-a-master-inbound-body-is-json-triggers-an-xray-restart
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/inbounds/list","method":"get"},{"path":"/panel/api/inbounds/list/slim","method":"get"},{"path":"/panel/api/inbounds/options","method":"get"},{"path":"/panel/api/inbounds/get/{id}","method":"get"},{"path":"/panel/api/inbounds/add","method":"post"},{"path":"/panel/api/inbounds/del/{id}","method":"post"},{"path":"/panel/api/inbounds/bulkDel","method":"post"},{"path":"/panel/api/inbounds/update/{id}","method":"post"},{"path":"/panel/api/inbounds/setEnable/{id}","method":"post"},{"path":"/panel/api/inbounds/{id}/resetTraffic","method":"post"},{"path":"/panel/api/inbounds/{id}/delAllClients","method":"post"},{"path":"/panel/api/inbounds/resetAllTraffics","method":"post"},{"path":"/panel/api/inbounds/import","method":"post"},{"path":"/panel/api/inbounds/pushClientTraffics","method":"post"},{"path":"/panel/api/inbounds/{id}/fallbacks","method":"get"},{"path":"/panel/api/inbounds/{id}/fallbacks","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,40 @@
---
title: API Reference
description: The 3x-ui panel REST API — authentication, inbounds, clients, server stats, and more, generated from the OpenAPI spec.
icon: Webhook
---
The 3x-ui panel exposes a REST API for automation. These pages are generated from
the panel's OpenAPI specification, so they always match the documented schema.
## Authentication
Requests authenticate with either a **session cookie** (from `POST /login`) or a
**Bearer token**:
```text
Authorization: Bearer <token>
```
Create API tokens in the panel; they are full-admin credentials, so store them
securely. See [API Tokens](/docs/reference/api/api-tokens).
Build an authenticated request for any endpoint below:
<ApiRequestBuilder />
## Browse by area
<Cards>
<Card title="Authentication" href="/docs/reference/api/authentication" />
<Card title="Inbounds" href="/docs/reference/api/inbounds" />
<Card title="Clients" href="/docs/reference/api/clients" />
<Card title="Server" href="/docs/reference/api/server" />
<Card title="Settings" href="/docs/reference/api/settings" />
<Card title="Xray Settings" href="/docs/reference/api/xray-settings" />
</Cards>
<Callout type="info">
This reference is regenerated from `public/openapi.json` with `pnpm gen:api`.
Don't edit the generated tag pages by hand.
</Callout>
@@ -0,0 +1,19 @@
{
"title": "API Reference",
"icon": "Webhook",
"pages": [
"index",
"authentication",
"api-tokens",
"inbounds",
"clients",
"server",
"settings",
"xray-settings",
"subscription-server",
"hosts",
"nodes",
"backup",
"websocket"
]
}
@@ -0,0 +1,183 @@
---
title: Nodes
description: >-
Manage remote 3x-ui panels acting as nodes for a central panel. All endpoints
under /panel/api/nodes.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every configured node with its connection details, health, and last
heartbeat patch.
url: >-
#list-every-configured-node-with-its-connection-details-health-and-last-heartbeat-patch
- depth: 2
title: >-
This panel's node-auth CA certificate (public, PEM) to paste into a
node's mTLS trust setting. Lazily mints the CA and the master client
cert on first call. Pair with setting tlsVerifyMode=mtls on the node.
url: >-
#this-panels-node-auth-ca-certificate-public-pem-to-paste-into-a-nodes-mtls-trust-setting-lazily-mints-the-ca-and-the-master-client-cert-on-first-call-pair-with-setting-tlsverifymodemtls-on-the-node
- depth: 2
title: >-
Set the CA certificate this panel trusts for incoming node-API client
certificates (this panel acting as a node). Paste the managing panel's
CA (from nodes/mtls/ca). An empty caCert disables it. A non-empty value
must be a PEM certificate. Applied on the next panel restart.
url: >-
#set-the-ca-certificate-this-panel-trusts-for-incoming-node-api-client-certificates-this-panel-acting-as-a-node-paste-the-managing-panels-ca-from-nodesmtlsca-an-empty-cacert-disables-it-a-non-empty-value-must-be-a-pem-certificate-applied-on-the-next-panel-restart
- depth: 2
title: Fetch a single node by ID.
url: '#fetch-a-single-node-by-id'
- depth: 2
title: >-
Fetch a node's own web TLS certificate/key file paths (proxied to the
node). Used by the inbound form's "Set Cert from Panel" so a
node-assigned inbound gets paths that exist on the node, not the central
panel.
url: >-
#fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel
- depth: 2
title: >-
Register a new remote node. Provide its URL, apiToken, and optional
remark / allowPrivateAddress flag.
url: >-
#register-a-new-remote-node-provide-its-url-apitoken-and-optional-remark--allowprivateaddress-flag
- depth: 2
title: Replace a nodes connection details. Same body shape as /add.
url: '#replace-a-nodes-connection-details-same-body-shape-as-add'
- depth: 2
title: Delete a node. Inbounds bound to it are not auto-migrated.
url: '#delete-a-node-inbounds-bound-to-it-are-not-auto-migrated'
- depth: 2
title: Pause or resume traffic sync with this node.
url: '#pause-or-resume-traffic-sync-with-this-node'
- depth: 2
title: >-
Probe a node without saving it. Uses the body as connection details and
returns the same heartbeat snapshot a registered node would have.
url: >-
#probe-a-node-without-saving-it-uses-the-body-as-connection-details-and-returns-the-same-heartbeat-snapshot-a-registered-node-would-have
- depth: 2
title: >-
Connect to the node over HTTPS without verifying its certificate and
return the leaf certificate's SHA-256 (base64). Used by the Add/Edit
Node dialog to fetch and pin a self-signed certificate. Uses the same
body as /test.
url: >-
#connect-to-the-node-over-https-without-verifying-its-certificate-and-return-the-leaf-certificates-sha-256-base64-used-by-the-addedit-node-dialog-to-fetch-and-pin-a-self-signed-certificate-uses-the-same-body-as-test
- depth: 2
title: >-
Use unsaved node connection details to list the remote inbounds
available for selective import.
url: >-
#use-unsaved-node-connection-details-to-list-the-remote-inbounds-available-for-selective-import
- depth: 2
title: Probe an existing node, updating its cached health state.
url: '#probe-an-existing-node-updating-its-cached-health-state'
- depth: 2
title: >-
Trigger the official panel self-updater on each given node (downloads
the latest release and restarts). Only enabled, online nodes are
updated; offline/disabled ones are reported as skipped. Set "dev": true
to move the nodes to the rolling per-commit dev channel instead of the
latest stable release. Returns a per-node result list.
url: >-
#trigger-the-official-panel-self-updater-on-each-given-node-downloads-the-latest-release-and-restarts-only-enabled-online-nodes-are-updated-offlinedisabled-ones-are-reported-as-skipped-set-dev-true-to-move-the-nodes-to-the-rolling-per-commit-dev-channel-instead-of-the-latest-stable-release-returns-a-per-node-result-list
- depth: 2
title: >-
Aggregated metric history for a node — same shape as /server/history,
scoped to one node.
url: >-
#aggregated-metric-history-for-a-node--same-shape-as-serverhistory-scoped-to-one-node
structuredData:
headings:
- content: >-
List every configured node with its connection details, health, and
last heartbeat patch.
id: >-
list-every-configured-node-with-its-connection-details-health-and-last-heartbeat-patch
- content: >-
This panel's node-auth CA certificate (public, PEM) to paste into a
node's mTLS trust setting. Lazily mints the CA and the master client
cert on first call. Pair with setting tlsVerifyMode=mtls on the node.
id: >-
this-panels-node-auth-ca-certificate-public-pem-to-paste-into-a-nodes-mtls-trust-setting-lazily-mints-the-ca-and-the-master-client-cert-on-first-call-pair-with-setting-tlsverifymodemtls-on-the-node
- content: >-
Set the CA certificate this panel trusts for incoming node-API client
certificates (this panel acting as a node). Paste the managing panel's
CA (from nodes/mtls/ca). An empty caCert disables it. A non-empty
value must be a PEM certificate. Applied on the next panel restart.
id: >-
set-the-ca-certificate-this-panel-trusts-for-incoming-node-api-client-certificates-this-panel-acting-as-a-node-paste-the-managing-panels-ca-from-nodesmtlsca-an-empty-cacert-disables-it-a-non-empty-value-must-be-a-pem-certificate-applied-on-the-next-panel-restart
- content: Fetch a single node by ID.
id: fetch-a-single-node-by-id
- content: >-
Fetch a node's own web TLS certificate/key file paths (proxied to the
node). Used by the inbound form's "Set Cert from Panel" so a
node-assigned inbound gets paths that exist on the node, not the
central panel.
id: >-
fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel
- content: >-
Register a new remote node. Provide its URL, apiToken, and optional
remark / allowPrivateAddress flag.
id: >-
register-a-new-remote-node-provide-its-url-apitoken-and-optional-remark--allowprivateaddress-flag
- content: Replace a nodes connection details. Same body shape as /add.
id: replace-a-nodes-connection-details-same-body-shape-as-add
- content: Delete a node. Inbounds bound to it are not auto-migrated.
id: delete-a-node-inbounds-bound-to-it-are-not-auto-migrated
- content: Pause or resume traffic sync with this node.
id: pause-or-resume-traffic-sync-with-this-node
- content: >-
Probe a node without saving it. Uses the body as connection details
and returns the same heartbeat snapshot a registered node would have.
id: >-
probe-a-node-without-saving-it-uses-the-body-as-connection-details-and-returns-the-same-heartbeat-snapshot-a-registered-node-would-have
- content: >-
Connect to the node over HTTPS without verifying its certificate and
return the leaf certificate's SHA-256 (base64). Used by the Add/Edit
Node dialog to fetch and pin a self-signed certificate. Uses the same
body as /test.
id: >-
connect-to-the-node-over-https-without-verifying-its-certificate-and-return-the-leaf-certificates-sha-256-base64-used-by-the-addedit-node-dialog-to-fetch-and-pin-a-self-signed-certificate-uses-the-same-body-as-test
- content: >-
Use unsaved node connection details to list the remote inbounds
available for selective import.
id: >-
use-unsaved-node-connection-details-to-list-the-remote-inbounds-available-for-selective-import
- content: Probe an existing node, updating its cached health state.
id: probe-an-existing-node-updating-its-cached-health-state
- content: >-
Trigger the official panel self-updater on each given node (downloads
the latest release and restarts). Only enabled, online nodes are
updated; offline/disabled ones are reported as skipped. Set "dev":
true to move the nodes to the rolling per-commit dev channel instead
of the latest stable release. Returns a per-node result list.
id: >-
trigger-the-official-panel-self-updater-on-each-given-node-downloads-the-latest-release-and-restarts-only-enabled-online-nodes-are-updated-offlinedisabled-ones-are-reported-as-skipped-set-dev-true-to-move-the-nodes-to-the-rolling-per-commit-dev-channel-instead-of-the-latest-stable-release-returns-a-per-node-result-list
- content: >-
Aggregated metric history for a node — same shape as /server/history,
scoped to one node.
id: >-
aggregated-metric-history-for-a-node--same-shape-as-serverhistory-scoped-to-one-node
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/nodes/list","method":"get"},{"path":"/panel/api/nodes/mtls/ca","method":"post"},{"path":"/panel/api/nodes/mtls/trustCA","method":"post"},{"path":"/panel/api/nodes/get/{id}","method":"get"},{"path":"/panel/api/nodes/webCert/{id}","method":"get"},{"path":"/panel/api/nodes/add","method":"post"},{"path":"/panel/api/nodes/update/{id}","method":"post"},{"path":"/panel/api/nodes/del/{id}","method":"post"},{"path":"/panel/api/nodes/setEnable/{id}","method":"post"},{"path":"/panel/api/nodes/test","method":"post"},{"path":"/panel/api/nodes/certFingerprint","method":"post"},{"path":"/panel/api/nodes/inbounds","method":"post"},{"path":"/panel/api/nodes/probe/{id}","method":"post"},{"path":"/panel/api/nodes/updatePanel","method":"post"},{"path":"/panel/api/nodes/history/{id}/{metric}/{bucket}","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,381 @@
---
title: Server
description: >-
System status, log retrieval, certificate generators, Xray binary management,
and backup/restore. All under /panel/api/server.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Real-time machine snapshot: CPU, memory, swap, disk, network IO, load
averages, open connections, Xray state. Cached and refreshed every 2
seconds in the background.
url: >-
#real-time-machine-snapshot-cpu-memory-swap-disk-network-io-load-averages-open-connections-xray-state-cached-and-refreshed-every-2-seconds-in-the-background
- depth: 2
title: >-
Reports whether per-client IP limits can be enforced on this host. The
panel uses it to gate the "IP Limit" field, since enforcement depends on
Fail2ban being installed.
url: >-
#reports-whether-per-client-ip-limits-can-be-enforced-on-this-host-the-panel-uses-it-to-gate-the-ip-limit-field-since-enforcement-depends-on-fail2ban-being-installed
- depth: 2
title: >-
Legacy: aggregated CPU history. Use /history/cpu/:bucket instead — same
data with a uniform {t, v} shape.
url: >-
#legacy-aggregated-cpu-history-use-historycpubucket-instead--same-data-with-a-uniform-t-v-shape
- depth: 2
title: >-
Aggregated time-series for one metric. Returns an array of {t, v}
samples covering the last ~6 hours.
url: >-
#aggregated-time-series-for-one-metric-returns-an-array-of-t-v-samples-covering-the-last-6-hours
- depth: 2
title: >-
Xray runtime metrics state — whether the xray config has a `metrics`
block, which expvar keys are flowing, and the current snapshot values
for each. Returns an empty state when metrics are not configured.
url: >-
#xray-runtime-metrics-state--whether-the-xray-config-has-a-metrics-block-which-expvar-keys-are-flowing-and-the-current-snapshot-values-for-each-returns-an-empty-state-when-metrics-are-not-configured
- depth: 2
title: >-
Time-series history for one Xray runtime metric over the last ~6 hours.
Same {t, v} shape as /history/:metric/:bucket.
url: >-
#time-series-history-for-one-xray-runtime-metric-over-the-last-6-hours-same-t-v-shape-as-historymetricbucket
- depth: 2
title: >-
Latest snapshot from the Xray observatory — per-outbound latency, health
status, and last-probe time. Only populated when the Xray config has an
observatory configured.
url: >-
#latest-snapshot-from-the-xray-observatory--per-outbound-latency-health-status-and-last-probe-time-only-populated-when-the-xray-config-has-an-observatory-configured
- depth: 2
title: >-
Time-series of observatory probe results for one outbound tag. Same {t,
v} shape as the other history endpoints.
url: >-
#time-series-of-observatory-probe-results-for-one-outbound-tag-same-t-v-shape-as-the-other-history-endpoints
- depth: 2
title: List Xray binary versions available for install on this host.
url: '#list-xray-binary-versions-available-for-install-on-this-host'
- depth: 2
title: Check whether a newer 3x-ui release is available on GitHub.
url: '#check-whether-a-newer-3x-ui-release-is-available-on-github'
- depth: 2
title: Return the assembled Xray config thats currently running on this host.
url: '#return-the-assembled-xray-config-thats-currently-running-on-this-host'
- depth: 2
title: >-
Stream the SQLite database file as an attachment. Use as a manual
backup.
url: '#stream-the-sqlite-database-file-as-an-attachment-use-as-a-manual-backup'
- depth: 2
title: >-
Stream a cross-engine migration file as an attachment: a .dump (SQL
text) on SQLite, or a .db SQLite database built from the live data on
PostgreSQL.
url: >-
#stream-a-cross-engine-migration-file-as-an-attachment-a-dump-sql-text-on-sqlite-or-a-db-sqlite-database-built-from-the-live-data-on-postgresql
- depth: 2
title: Generate a fresh UUID v4. Convenience helper for client IDs.
url: '#generate-a-fresh-uuid-v4-convenience-helper-for-client-ids'
- depth: 2
title: >-
Return this panel's own web TLS certificate and key file paths. The
central panel calls it on a node (via the node API token) so "Set Cert
from Panel" fills a node-assigned inbound with paths that exist on the
node.
url: >-
#return-this-panels-own-web-tls-certificate-and-key-file-paths-the-central-panel-calls-it-on-a-node-via-the-node-api-token-so-set-cert-from-panel-fills-a-node-assigned-inbound-with-paths-that-exist-on-the-node
- depth: 2
title: >-
Read-only summaries (guid, parentGuid, name, address, status, versions)
of the nodes this panel manages. A parent panel calls it on a node (via
the node API token) to surface transitive sub-nodes in a chained
topology. Counts are computed by the parent, not returned here.
url: >-
#read-only-summaries-guid-parentguid-name-address-status-versions-of-the-nodes-this-panel-manages-a-parent-panel-calls-it-on-a-node-via-the-node-api-token-to-surface-transitive-sub-nodes-in-a-chained-topology-counts-are-computed-by-the-parent-not-returned-here
- depth: 2
title: Generate a new X25519 keypair for Reality.
url: '#generate-a-new-x25519-keypair-for-reality'
- depth: 2
title: >-
Generate a new ML-DSA-65 keypair (post-quantum signature). Returns
{privateKey, publicKey, seed}.
url: >-
#generate-a-new-ml-dsa-65-keypair-post-quantum-signature-returns-privatekey-publickey-seed
- depth: 2
title: >-
Generate a new ML-KEM-768 keypair (post-quantum KEM). Returns
{clientKey, serverKey}.
url: >-
#generate-a-new-ml-kem-768-keypair-post-quantum-kem-returns-clientkey-serverkey
- depth: 2
title: >-
Generate VLESS encryption auth options. Returns an auths array each with
id, label, encryption, and decryption fields.
url: >-
#generate-vless-encryption-auth-options-returns-an-auths-array-each-with-id-label-encryption-and-decryption-fields
- depth: 2
title: Stop the Xray binary. All proxies go offline immediately.
url: '#stop-the-xray-binary-all-proxies-go-offline-immediately'
- depth: 2
title: >-
Reload Xray with the current config. Typically required after structural
inbound or routing changes.
url: >-
#reload-xray-with-the-current-config-typically-required-after-structural-inbound-or-routing-changes
- depth: 2
title: >-
Download and install the specified Xray version. Pass "latest" for the
newest release.
url: >-
#download-and-install-the-specified-xray-version-pass-latest-for-the-newest-release
- depth: 2
title: >-
Self-update the panel to the latest version. The server restarts on
success.
url: >-
#self-update-the-panel-to-the-latest-version-the-server-restarts-on-success
- depth: 2
title: >-
Toggle the panel update channel between stable and the rolling
per-commit dev release. Only effective on dev builds.
url: >-
#toggle-the-panel-update-channel-between-stable-and-the-rolling-per-commit-dev-release-only-effective-on-dev-builds
- depth: 2
title: >-
Refresh the default GeoIP / GeoSite data files. Body can include a
fileName, or use the /:fileName variant.
url: >-
#refresh-the-default-geoip--geosite-data-files-body-can-include-a-filename-or-use-the-filename-variant
- depth: 2
title: Refresh a single Geo file by filename (e.g. geoip.dat, geosite.dat).
url: '#refresh-a-single-geo-file-by-filename-eg-geoipdat-geositedat'
- depth: 2
title: Return the last N lines of the panels own log.
url: '#return-the-last-n-lines-of-the-panels-own-log'
- depth: 2
title: Return the last N lines of the Xray process log.
url: '#return-the-last-n-lines-of-the-xray-process-log'
- depth: 2
title: >-
Restore the panel DB from an uploaded SQLite file (multipart form, field
name "db"). The panel restarts after restore. Destructive.
url: >-
#restore-the-panel-db-from-an-uploaded-sqlite-file-multipart-form-field-name-db-the-panel-restarts-after-restore-destructive
- depth: 2
title: >-
Generate a new ECH (Encrypted Client Hello) keypair and config list for
the given SNI.
url: >-
#generate-a-new-ech-encrypted-client-hello-keypair-and-config-list-for-the-given-sni
- depth: 2
title: >-
Compute the hex SHA-256 of a certificate (DER) for pinning
(pinnedPeerCertSha256). Provide either a server file path or inline
PEM/DER content.
url: >-
#compute-the-hex-sha-256-of-a-certificate-der-for-pinning-pinnedpeercertsha256-provide-either-a-server-file-path-or-inline-pemder-content
- depth: 2
title: >-
Run `xray tls ping` against a remote server and return its live
leaf-certificate SHA-256 hash(es) for pinning (pinnedPeerCertSha256).
url: >-
#run-xray-tls-ping-against-a-remote-server-and-return-its-live-leaf-certificate-sha-256-hashes-for-pinning-pinnedpeercertsha256
- depth: 2
title: >-
Fetch the fully aggregated inbound_client_ips database table. Used by
nodes to sync recently active IPs across the cluster.
url: >-
#fetch-the-fully-aggregated-inbound_client_ips-database-table-used-by-nodes-to-sync-recently-active-ips-across-the-cluster
- depth: 2
title: >-
Submit a list of recently active IP timestamps. The panel merges them
with the existing database to maintain a unified global IP-limit view.
url: >-
#submit-a-list-of-recently-active-ip-timestamps-the-panel-merges-them-with-the-existing-database-to-maintain-a-unified-global-ip-limit-view
structuredData:
headings:
- content: >-
Real-time machine snapshot: CPU, memory, swap, disk, network IO, load
averages, open connections, Xray state. Cached and refreshed every 2
seconds in the background.
id: >-
real-time-machine-snapshot-cpu-memory-swap-disk-network-io-load-averages-open-connections-xray-state-cached-and-refreshed-every-2-seconds-in-the-background
- content: >-
Reports whether per-client IP limits can be enforced on this host. The
panel uses it to gate the "IP Limit" field, since enforcement depends
on Fail2ban being installed.
id: >-
reports-whether-per-client-ip-limits-can-be-enforced-on-this-host-the-panel-uses-it-to-gate-the-ip-limit-field-since-enforcement-depends-on-fail2ban-being-installed
- content: >-
Legacy: aggregated CPU history. Use /history/cpu/:bucket instead —
same data with a uniform {t, v} shape.
id: >-
legacy-aggregated-cpu-history-use-historycpubucket-instead--same-data-with-a-uniform-t-v-shape
- content: >-
Aggregated time-series for one metric. Returns an array of {t, v}
samples covering the last ~6 hours.
id: >-
aggregated-time-series-for-one-metric-returns-an-array-of-t-v-samples-covering-the-last-6-hours
- content: >-
Xray runtime metrics state — whether the xray config has a `metrics`
block, which expvar keys are flowing, and the current snapshot values
for each. Returns an empty state when metrics are not configured.
id: >-
xray-runtime-metrics-state--whether-the-xray-config-has-a-metrics-block-which-expvar-keys-are-flowing-and-the-current-snapshot-values-for-each-returns-an-empty-state-when-metrics-are-not-configured
- content: >-
Time-series history for one Xray runtime metric over the last ~6
hours. Same {t, v} shape as /history/:metric/:bucket.
id: >-
time-series-history-for-one-xray-runtime-metric-over-the-last-6-hours-same-t-v-shape-as-historymetricbucket
- content: >-
Latest snapshot from the Xray observatory — per-outbound latency,
health status, and last-probe time. Only populated when the Xray
config has an observatory configured.
id: >-
latest-snapshot-from-the-xray-observatory--per-outbound-latency-health-status-and-last-probe-time-only-populated-when-the-xray-config-has-an-observatory-configured
- content: >-
Time-series of observatory probe results for one outbound tag. Same
{t, v} shape as the other history endpoints.
id: >-
time-series-of-observatory-probe-results-for-one-outbound-tag-same-t-v-shape-as-the-other-history-endpoints
- content: List Xray binary versions available for install on this host.
id: list-xray-binary-versions-available-for-install-on-this-host
- content: Check whether a newer 3x-ui release is available on GitHub.
id: check-whether-a-newer-3x-ui-release-is-available-on-github
- content: >-
Return the assembled Xray config thats currently running on this
host.
id: return-the-assembled-xray-config-thats-currently-running-on-this-host
- content: >-
Stream the SQLite database file as an attachment. Use as a manual
backup.
id: >-
stream-the-sqlite-database-file-as-an-attachment-use-as-a-manual-backup
- content: >-
Stream a cross-engine migration file as an attachment: a .dump (SQL
text) on SQLite, or a .db SQLite database built from the live data on
PostgreSQL.
id: >-
stream-a-cross-engine-migration-file-as-an-attachment-a-dump-sql-text-on-sqlite-or-a-db-sqlite-database-built-from-the-live-data-on-postgresql
- content: Generate a fresh UUID v4. Convenience helper for client IDs.
id: generate-a-fresh-uuid-v4-convenience-helper-for-client-ids
- content: >-
Return this panel's own web TLS certificate and key file paths. The
central panel calls it on a node (via the node API token) so "Set Cert
from Panel" fills a node-assigned inbound with paths that exist on the
node.
id: >-
return-this-panels-own-web-tls-certificate-and-key-file-paths-the-central-panel-calls-it-on-a-node-via-the-node-api-token-so-set-cert-from-panel-fills-a-node-assigned-inbound-with-paths-that-exist-on-the-node
- content: >-
Read-only summaries (guid, parentGuid, name, address, status,
versions) of the nodes this panel manages. A parent panel calls it on
a node (via the node API token) to surface transitive sub-nodes in a
chained topology. Counts are computed by the parent, not returned
here.
id: >-
read-only-summaries-guid-parentguid-name-address-status-versions-of-the-nodes-this-panel-manages-a-parent-panel-calls-it-on-a-node-via-the-node-api-token-to-surface-transitive-sub-nodes-in-a-chained-topology-counts-are-computed-by-the-parent-not-returned-here
- content: Generate a new X25519 keypair for Reality.
id: generate-a-new-x25519-keypair-for-reality
- content: >-
Generate a new ML-DSA-65 keypair (post-quantum signature). Returns
{privateKey, publicKey, seed}.
id: >-
generate-a-new-ml-dsa-65-keypair-post-quantum-signature-returns-privatekey-publickey-seed
- content: >-
Generate a new ML-KEM-768 keypair (post-quantum KEM). Returns
{clientKey, serverKey}.
id: >-
generate-a-new-ml-kem-768-keypair-post-quantum-kem-returns-clientkey-serverkey
- content: >-
Generate VLESS encryption auth options. Returns an auths array each
with id, label, encryption, and decryption fields.
id: >-
generate-vless-encryption-auth-options-returns-an-auths-array-each-with-id-label-encryption-and-decryption-fields
- content: Stop the Xray binary. All proxies go offline immediately.
id: stop-the-xray-binary-all-proxies-go-offline-immediately
- content: >-
Reload Xray with the current config. Typically required after
structural inbound or routing changes.
id: >-
reload-xray-with-the-current-config-typically-required-after-structural-inbound-or-routing-changes
- content: >-
Download and install the specified Xray version. Pass "latest" for the
newest release.
id: >-
download-and-install-the-specified-xray-version-pass-latest-for-the-newest-release
- content: >-
Self-update the panel to the latest version. The server restarts on
success.
id: >-
self-update-the-panel-to-the-latest-version-the-server-restarts-on-success
- content: >-
Toggle the panel update channel between stable and the rolling
per-commit dev release. Only effective on dev builds.
id: >-
toggle-the-panel-update-channel-between-stable-and-the-rolling-per-commit-dev-release-only-effective-on-dev-builds
- content: >-
Refresh the default GeoIP / GeoSite data files. Body can include a
fileName, or use the /:fileName variant.
id: >-
refresh-the-default-geoip--geosite-data-files-body-can-include-a-filename-or-use-the-filename-variant
- content: Refresh a single Geo file by filename (e.g. geoip.dat, geosite.dat).
id: refresh-a-single-geo-file-by-filename-eg-geoipdat-geositedat
- content: Return the last N lines of the panels own log.
id: return-the-last-n-lines-of-the-panels-own-log
- content: Return the last N lines of the Xray process log.
id: return-the-last-n-lines-of-the-xray-process-log
- content: >-
Restore the panel DB from an uploaded SQLite file (multipart form,
field name "db"). The panel restarts after restore. Destructive.
id: >-
restore-the-panel-db-from-an-uploaded-sqlite-file-multipart-form-field-name-db-the-panel-restarts-after-restore-destructive
- content: >-
Generate a new ECH (Encrypted Client Hello) keypair and config list
for the given SNI.
id: >-
generate-a-new-ech-encrypted-client-hello-keypair-and-config-list-for-the-given-sni
- content: >-
Compute the hex SHA-256 of a certificate (DER) for pinning
(pinnedPeerCertSha256). Provide either a server file path or inline
PEM/DER content.
id: >-
compute-the-hex-sha-256-of-a-certificate-der-for-pinning-pinnedpeercertsha256-provide-either-a-server-file-path-or-inline-pemder-content
- content: >-
Run `xray tls ping` against a remote server and return its live
leaf-certificate SHA-256 hash(es) for pinning (pinnedPeerCertSha256).
id: >-
run-xray-tls-ping-against-a-remote-server-and-return-its-live-leaf-certificate-sha-256-hashes-for-pinning-pinnedpeercertsha256
- content: >-
Fetch the fully aggregated inbound_client_ips database table. Used by
nodes to sync recently active IPs across the cluster.
id: >-
fetch-the-fully-aggregated-inbound_client_ips-database-table-used-by-nodes-to-sync-recently-active-ips-across-the-cluster
- content: >-
Submit a list of recently active IP timestamps. The panel merges them
with the existing database to maintain a unified global IP-limit view.
id: >-
submit-a-list-of-recently-active-ip-timestamps-the-panel-merges-them-with-the-existing-database-to-maintain-a-unified-global-ip-limit-view
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/server/status","method":"get"},{"path":"/panel/api/server/fail2banStatus","method":"get"},{"path":"/panel/api/server/cpuHistory/{bucket}","method":"get"},{"path":"/panel/api/server/history/{metric}/{bucket}","method":"get"},{"path":"/panel/api/server/xrayMetricsState","method":"get"},{"path":"/panel/api/server/xrayMetricsHistory/{metric}/{bucket}","method":"get"},{"path":"/panel/api/server/xrayObservatory","method":"get"},{"path":"/panel/api/server/xrayObservatoryHistory/{tag}/{bucket}","method":"get"},{"path":"/panel/api/server/getXrayVersion","method":"get"},{"path":"/panel/api/server/getPanelUpdateInfo","method":"get"},{"path":"/panel/api/server/getConfigJson","method":"get"},{"path":"/panel/api/server/getDb","method":"get"},{"path":"/panel/api/server/getMigration","method":"get"},{"path":"/panel/api/server/getNewUUID","method":"get"},{"path":"/panel/api/server/getWebCertFiles","method":"get"},{"path":"/panel/api/server/descendants","method":"get"},{"path":"/panel/api/server/getNewX25519Cert","method":"get"},{"path":"/panel/api/server/getNewmldsa65","method":"get"},{"path":"/panel/api/server/getNewmlkem768","method":"get"},{"path":"/panel/api/server/getNewVlessEnc","method":"get"},{"path":"/panel/api/server/stopXrayService","method":"post"},{"path":"/panel/api/server/restartXrayService","method":"post"},{"path":"/panel/api/server/installXray/{version}","method":"post"},{"path":"/panel/api/server/updatePanel","method":"post"},{"path":"/panel/api/server/setUpdateChannel","method":"post"},{"path":"/panel/api/server/updateGeofile","method":"post"},{"path":"/panel/api/server/updateGeofile/{fileName}","method":"post"},{"path":"/panel/api/server/logs/{count}","method":"post"},{"path":"/panel/api/server/xraylogs/{count}","method":"post"},{"path":"/panel/api/server/importDB","method":"post"},{"path":"/panel/api/server/getNewEchCert","method":"post"},{"path":"/panel/api/server/getCertHash","method":"post"},{"path":"/panel/api/server/getRemoteCertHash","method":"post"},{"path":"/panel/api/server/clientIps","method":"get"},{"path":"/panel/api/server/clientIps","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,122 @@
---
title: Settings
description: >-
Panel configuration and user credentials. All endpoints live under
/panel/api/setting and require a logged-in session or Bearer token.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Return every panel setting: web server, Telegram bot, subscription,
security, LDAP. The full JSON blob that the Settings page edits.
url: >-
#return-every-panel-setting-web-server-telegram-bot-subscription-security-ldap-the-full-json-blob-that-the-settings-page-edits
- depth: 2
title: >-
Return the computed default settings based on the request host. Useful
to preview what a fresh install would use.
url: >-
#return-the-computed-default-settings-based-on-the-request-host-useful-to-preview-what-a-fresh-install-would-use
- depth: 2
title: >-
Persist every setting at once. The body mirrors the shape returned by
/all. Invalid values (bad ports, missing cert pairs, etc.) are rejected
before write.
url: >-
#persist-every-setting-at-once-the-body-mirrors-the-shape-returned-by-all-invalid-values-bad-ports-missing-cert-pairs-etc-are-rejected-before-write
- depth: 2
title: >-
Change the panel admin username and password. Requires the current
credentials for verification. The session is refreshed with the new
values on success.
url: >-
#change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success
- depth: 2
title: >-
Restart the entire 3x-ui process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10 seconds
later.
url: >-
#restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
- depth: 2
title: >-
Test SMTP connection with stage-by-stage reporting (connect, auth,
send). Returns structured result with stage and message.
url: >-
#test-smtp-connection-with-stage-by-stage-reporting-connect-auth-send-returns-structured-result-with-stage-and-message
- depth: 2
title: >-
Test Telegram bot connection by sending a test message to the configured
chat.
url: >-
#test-telegram-bot-connection-by-sending-a-test-message-to-the-configured-chat
- depth: 2
title: >-
Return the built-in default Xray JSON config template that ships with
this panel version.
url: >-
#return-the-built-in-default-xray-json-config-template-that-ships-with-this-panel-version
structuredData:
headings:
- content: >-
Return every panel setting: web server, Telegram bot, subscription,
security, LDAP. The full JSON blob that the Settings page edits.
id: >-
return-every-panel-setting-web-server-telegram-bot-subscription-security-ldap-the-full-json-blob-that-the-settings-page-edits
- content: >-
Return the computed default settings based on the request host. Useful
to preview what a fresh install would use.
id: >-
return-the-computed-default-settings-based-on-the-request-host-useful-to-preview-what-a-fresh-install-would-use
- content: >-
Persist every setting at once. The body mirrors the shape returned by
/all. Invalid values (bad ports, missing cert pairs, etc.) are
rejected before write.
id: >-
persist-every-setting-at-once-the-body-mirrors-the-shape-returned-by-all-invalid-values-bad-ports-missing-cert-pairs-etc-are-rejected-before-write
- content: >-
Change the panel admin username and password. Requires the current
credentials for verification. The session is refreshed with the new
values on success.
id: >-
change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success
- content: >-
Restart the entire 3x-ui process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10
seconds later.
id: >-
restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
- content: >-
Test SMTP connection with stage-by-stage reporting (connect, auth,
send). Returns structured result with stage and message.
id: >-
test-smtp-connection-with-stage-by-stage-reporting-connect-auth-send-returns-structured-result-with-stage-and-message
- content: >-
Test Telegram bot connection by sending a test message to the
configured chat.
id: >-
test-telegram-bot-connection-by-sending-a-test-message-to-the-configured-chat
- content: >-
Return the built-in default Xray JSON config template that ships with
this panel version.
id: >-
return-the-built-in-default-xray-json-config-template-that-ships-with-this-panel-version
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/setting/all","method":"post"},{"path":"/panel/api/setting/defaultSettings","method":"post"},{"path":"/panel/api/setting/update","method":"post"},{"path":"/panel/api/setting/updateUser","method":"post"},{"path":"/panel/api/setting/restartPanel","method":"post"},{"path":"/panel/api/setting/testSmtp","method":"post"},{"path":"/panel/api/setting/testTgBot","method":"post"},{"path":"/panel/api/setting/getDefaultJsonConfig","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,72 @@
---
title: Subscription Server
description: >-
A separate HTTP/HTTPS server that serves proxy subscription links (standard,
JSON, and Clash) to clients. The server listens on its own port (default
10882) and is configured in Settings → Subscription. Paths are configurable;
defaults are shown below. All subscription endpoints set response headers for
client apps to read traffic/expiry info.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Return base64-encoded subscription links for all enabled clients
matching the subscription ID. When the request has an Accept: text/html
header or ?html=1, renders a styled info page instead. Default path:
/sub/:subid.
url: >-
#return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-default-path-subsubid
- depth: 2
title: >-
Return subscription as a JSON array of proxy configs (one per enabled
client). Only when JSON subscription is enabled in settings. Default
path: /json/:subid.
url: >-
#return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-default-path-jsonsubid
- depth: 2
title: >-
Return subscription as a Clash/Mihomo-compatible YAML config, including
configured global Clash routing rules. Only when Clash subscription is
enabled in settings. Default path: /clash/:subid.
url: >-
#return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-default-path-clashsubid
structuredData:
headings:
- content: >-
Return base64-encoded subscription links for all enabled clients
matching the subscription ID. When the request has an Accept:
text/html header or ?html=1, renders a styled info page instead.
Default path: /sub/:subid.
id: >-
return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-default-path-subsubid
- content: >-
Return subscription as a JSON array of proxy configs (one per enabled
client). Only when JSON subscription is enabled in settings. Default
path: /json/:subid.
id: >-
return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-default-path-jsonsubid
- content: >-
Return subscription as a Clash/Mihomo-compatible YAML config,
including configured global Clash routing rules. Only when Clash
subscription is enabled in settings. Default path: /clash/:subid.
id: >-
return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-default-path-clashsubid
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/{subPath}{subid}","method":"get"},{"path":"/{jsonPath}{subid}","method":"get"},{"path":"/{clashPath}{subid}","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,46 @@
---
title: WebSocket
description: >-
Real-time status updates via WebSocket. Connect once at
<code>ws://<panel>/ws</code> to receive a stream of JSON messages without
polling. Requires an authenticated session cookie (Bearer token auth is not
supported). Each message has a <code>type</code> field that identifies the
payload shape.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Upgrade an HTTP connection to a WebSocket. Requires an authenticated
session cookie (Bearer token auth is not supported here). Returns 101
Switching Protocols on success. The server then pushes JSON messages
described below.
url: >-
#upgrade-an-http-connection-to-a-websocket-requires-an-authenticated-session-cookie-bearer-token-auth-is-not-supported-here-returns-101-switching-protocols-on-success-the-server-then-pushes-json-messages-described-below
structuredData:
headings:
- content: >-
Upgrade an HTTP connection to a WebSocket. Requires an authenticated
session cookie (Bearer token auth is not supported here). Returns 101
Switching Protocols on success. The server then pushes JSON messages
described below.
id: >-
upgrade-an-http-connection-to-a-websocket-requires-an-authenticated-session-cookie-bearer-token-auth-is-not-supported-here-returns-101-switching-protocols-on-success-the-server-then-pushes-json-messages-described-below
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/ws","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,257 @@
---
title: Xray Settings
description: >-
Xray configuration template, outbound management, Warp/Nord integration, and
config testing. All endpoints under /panel/api/xray.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Return the Xray config template (JSON string), available inbound tags,
client reverse tags, and the configured outbound test URL in one
response.
url: >-
#return-the-xray-config-template-json-string-available-inbound-tags-client-reverse-tags-and-the-configured-outbound-test-url-in-one-response
- depth: 2
title: >-
Return the built-in default Xray config shipped with the panel
(identical to /panel/api/setting/getDefaultJsonConfig).
url: >-
#return-the-built-in-default-xray-config-shipped-with-the-panel-identical-to-panelapisettinggetdefaultjsonconfig
- depth: 2
title: >-
Return traffic statistics for every outbound. Each outbound shows
up/down/total counters.
url: >-
#return-traffic-statistics-for-every-outbound-each-outbound-shows-updowntotal-counters
- depth: 2
title: >-
Return the most recent Xray process stdout/stderr output. Useful to
check for startup errors or runtime warnings.
url: >-
#return-the-most-recent-xray-process-stdoutstderr-output-useful-to-check-for-startup-errors-or-runtime-warnings
- depth: 2
title: >-
Save the Xray JSON config template and optionally the outbound test URL.
Both are sent as form fields.
url: >-
#save-the-xray-json-config-template-and-optionally-the-outbound-test-url-both-are-sent-as-form-fields
- depth: 2
title: >-
Manage Cloudflare Warp integration. The action parameter selects the
operation.
url: >-
#manage-cloudflare-warp-integration-the-action-parameter-selects-the-operation
- depth: 2
title: Manage NordVPN integration. The action parameter selects the operation.
url: '#manage-nordvpn-integration-the-action-parameter-selects-the-operation'
- depth: 2
title: Reset traffic counters for a specific outbound by tag.
url: '#reset-traffic-counters-for-a-specific-outbound-by-tag'
- depth: 2
title: >-
Test an outbound configuration. Sends the outbound JSON (required),
optionally all outbounds (to resolve sockopt.dialerProxy dependencies),
and a mode flag.
url: >-
#test-an-outbound-configuration-sends-the-outbound-json-required-optionally-all-outbounds-to-resolve-sockoptdialerproxy-dependencies-and-a-mode-flag
- depth: 2
title: >-
Test a batch of outbounds (max 50) through one shared temp xray
instance. Returns an array of results in input order, each with the
outbound tag, delay, HTTP status and a connect/TLS/TTFB timing
breakdown.
url: >-
#test-a-batch-of-outbounds-max-50-through-one-shared-temp-xray-instance-returns-an-array-of-results-in-input-order-each-with-the-outbound-tag-delay-http-status-and-a-connecttlsttfb-timing-breakdown
- depth: 2
title: >-
Live state of routing balancers in the running core
(RoutingService.GetBalancerInfo): current override and the targets the
strategy prefers. Returns a map keyed by balancer tag.
url: >-
#live-state-of-routing-balancers-in-the-running-core-routingservicegetbalancerinfo-current-override-and-the-targets-the-strategy-prefers-returns-a-map-keyed-by-balancer-tag
- depth: 2
title: >-
Force a balancer in the running core to always pick one outbound
(RoutingService.OverrideBalancerTarget). Applied live without a restart;
cleared automatically when Xray restarts.
url: >-
#force-a-balancer-in-the-running-core-to-always-pick-one-outbound-routingserviceoverridebalancertarget-applied-live-without-a-restart-cleared-automatically-when-xray-restarts
- depth: 2
title: >-
Ask the running core which outbound its router would pick for a
synthetic connection (RoutingService.TestRoute). No traffic is sent.
url: >-
#ask-the-running-core-which-outbound-its-router-would-pick-for-a-synthetic-connection-routingservicetestroute-no-traffic-is-sent
- depth: 2
title: >-
List all outbound subscriptions (remote URLs that supply additional
outbounds), newest first.
url: >-
#list-all-outbound-subscriptions-remote-urls-that-supply-additional-outbounds-newest-first
- depth: 2
title: >-
Create an outbound subscription. The URL is fetched, parsed into
outbounds with stable tags, and merged additively into the running Xray
config.
url: >-
#create-an-outbound-subscription-the-url-is-fetched-parsed-into-outbounds-with-stable-tags-and-merged-additively-into-the-running-xray-config
- depth: 2
title: >-
Update an existing outbound subscription by id. Accepts the same form
fields as create.
url: >-
#update-an-existing-outbound-subscription-by-id-accepts-the-same-form-fields-as-create
- depth: 2
title: Delete an outbound subscription by id.
url: '#delete-an-outbound-subscription-by-id'
- depth: 2
title: >-
Delete an outbound subscription by id (POST alias of DELETE for
axios-friendly clients).
url: >-
#delete-an-outbound-subscription-by-id-post-alias-of-delete-for-axios-friendly-clients
- depth: 2
title: >-
Force an immediate re-fetch of the subscription and return the parsed
outbounds. Signals Xray to reload.
url: >-
#force-an-immediate-re-fetch-of-the-subscription-and-return-the-parsed-outbounds-signals-xray-to-reload
- depth: 2
title: >-
Reorder a subscription one step up or down in priority (controls its
position in the merged outbounds).
url: >-
#reorder-a-subscription-one-step-up-or-down-in-priority-controls-its-position-in-the-merged-outbounds
- depth: 2
title: >-
Preview a subscription URL: fetch and parse it into outbounds without
persisting anything.
url: >-
#preview-a-subscription-url-fetch-and-parse-it-into-outbounds-without-persisting-anything
structuredData:
headings:
- content: >-
Return the Xray config template (JSON string), available inbound tags,
client reverse tags, and the configured outbound test URL in one
response.
id: >-
return-the-xray-config-template-json-string-available-inbound-tags-client-reverse-tags-and-the-configured-outbound-test-url-in-one-response
- content: >-
Return the built-in default Xray config shipped with the panel
(identical to /panel/api/setting/getDefaultJsonConfig).
id: >-
return-the-built-in-default-xray-config-shipped-with-the-panel-identical-to-panelapisettinggetdefaultjsonconfig
- content: >-
Return traffic statistics for every outbound. Each outbound shows
up/down/total counters.
id: >-
return-traffic-statistics-for-every-outbound-each-outbound-shows-updowntotal-counters
- content: >-
Return the most recent Xray process stdout/stderr output. Useful to
check for startup errors or runtime warnings.
id: >-
return-the-most-recent-xray-process-stdoutstderr-output-useful-to-check-for-startup-errors-or-runtime-warnings
- content: >-
Save the Xray JSON config template and optionally the outbound test
URL. Both are sent as form fields.
id: >-
save-the-xray-json-config-template-and-optionally-the-outbound-test-url-both-are-sent-as-form-fields
- content: >-
Manage Cloudflare Warp integration. The action parameter selects the
operation.
id: >-
manage-cloudflare-warp-integration-the-action-parameter-selects-the-operation
- content: >-
Manage NordVPN integration. The action parameter selects the
operation.
id: manage-nordvpn-integration-the-action-parameter-selects-the-operation
- content: Reset traffic counters for a specific outbound by tag.
id: reset-traffic-counters-for-a-specific-outbound-by-tag
- content: >-
Test an outbound configuration. Sends the outbound JSON (required),
optionally all outbounds (to resolve sockopt.dialerProxy
dependencies), and a mode flag.
id: >-
test-an-outbound-configuration-sends-the-outbound-json-required-optionally-all-outbounds-to-resolve-sockoptdialerproxy-dependencies-and-a-mode-flag
- content: >-
Test a batch of outbounds (max 50) through one shared temp xray
instance. Returns an array of results in input order, each with the
outbound tag, delay, HTTP status and a connect/TLS/TTFB timing
breakdown.
id: >-
test-a-batch-of-outbounds-max-50-through-one-shared-temp-xray-instance-returns-an-array-of-results-in-input-order-each-with-the-outbound-tag-delay-http-status-and-a-connecttlsttfb-timing-breakdown
- content: >-
Live state of routing balancers in the running core
(RoutingService.GetBalancerInfo): current override and the targets the
strategy prefers. Returns a map keyed by balancer tag.
id: >-
live-state-of-routing-balancers-in-the-running-core-routingservicegetbalancerinfo-current-override-and-the-targets-the-strategy-prefers-returns-a-map-keyed-by-balancer-tag
- content: >-
Force a balancer in the running core to always pick one outbound
(RoutingService.OverrideBalancerTarget). Applied live without a
restart; cleared automatically when Xray restarts.
id: >-
force-a-balancer-in-the-running-core-to-always-pick-one-outbound-routingserviceoverridebalancertarget-applied-live-without-a-restart-cleared-automatically-when-xray-restarts
- content: >-
Ask the running core which outbound its router would pick for a
synthetic connection (RoutingService.TestRoute). No traffic is sent.
id: >-
ask-the-running-core-which-outbound-its-router-would-pick-for-a-synthetic-connection-routingservicetestroute-no-traffic-is-sent
- content: >-
List all outbound subscriptions (remote URLs that supply additional
outbounds), newest first.
id: >-
list-all-outbound-subscriptions-remote-urls-that-supply-additional-outbounds-newest-first
- content: >-
Create an outbound subscription. The URL is fetched, parsed into
outbounds with stable tags, and merged additively into the running
Xray config.
id: >-
create-an-outbound-subscription-the-url-is-fetched-parsed-into-outbounds-with-stable-tags-and-merged-additively-into-the-running-xray-config
- content: >-
Update an existing outbound subscription by id. Accepts the same form
fields as create.
id: >-
update-an-existing-outbound-subscription-by-id-accepts-the-same-form-fields-as-create
- content: Delete an outbound subscription by id.
id: delete-an-outbound-subscription-by-id
- content: >-
Delete an outbound subscription by id (POST alias of DELETE for
axios-friendly clients).
id: >-
delete-an-outbound-subscription-by-id-post-alias-of-delete-for-axios-friendly-clients
- content: >-
Force an immediate re-fetch of the subscription and return the parsed
outbounds. Signals Xray to reload.
id: >-
force-an-immediate-re-fetch-of-the-subscription-and-return-the-parsed-outbounds-signals-xray-to-reload
- content: >-
Reorder a subscription one step up or down in priority (controls its
position in the merged outbounds).
id: >-
reorder-a-subscription-one-step-up-or-down-in-priority-controls-its-position-in-the-merged-outbounds
- content: >-
Preview a subscription URL: fetch and parse it into outbounds without
persisting anything.
id: >-
preview-a-subscription-url-fetch-and-parse-it-into-outbounds-without-persisting-anything
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/xray/","method":"post"},{"path":"/panel/api/xray/getDefaultJsonConfig","method":"get"},{"path":"/panel/api/xray/getOutboundsTraffic","method":"get"},{"path":"/panel/api/xray/getXrayResult","method":"get"},{"path":"/panel/api/xray/update","method":"post"},{"path":"/panel/api/xray/warp/{action}","method":"post"},{"path":"/panel/api/xray/nord/{action}","method":"post"},{"path":"/panel/api/xray/resetOutboundsTraffic","method":"post"},{"path":"/panel/api/xray/testOutbound","method":"post"},{"path":"/panel/api/xray/testOutbounds","method":"post"},{"path":"/panel/api/xray/balancerStatus","method":"post"},{"path":"/panel/api/xray/balancerOverride","method":"post"},{"path":"/panel/api/xray/routeTest","method":"post"},{"path":"/panel/api/xray/outbound-subs","method":"get"},{"path":"/panel/api/xray/outbound-subs","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}","method":"delete"},{"path":"/panel/api/xray/outbound-subs/{id}/del","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}/refresh","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}/move","method":"post"},{"path":"/panel/api/xray/outbound-subs/parse","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,64 @@
---
title: Database
description: 3x-ui storage backends — SQLite (default) and PostgreSQL — the database path, connection pool, and SQLite-to-PostgreSQL migration.
icon: Database
---
3x-ui stores everything — inbounds, clients, settings — in a database. You choose
the backend at install time; both are first-class.
## SQLite (default)
A single file at `/etc/x-ui/x-ui.db`. Zero setup, ideal for small and medium
deployments. The folder is configurable with
[`XUI_DB_FOLDER`](/docs/reference/env-vars#database) (on Windows it defaults next
to the binary).
## PostgreSQL
Recommended for high client counts or multi-node setups. The installer can
install PostgreSQL locally for you, or accept a DSN to an existing server. At
runtime the backend is selected via environment variables, which the installer
writes to `/etc/default/x-ui`:
```bash title="/etc/default/x-ui"
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
Tune the connection pool with `XUI_DB_MAX_OPEN_CONNS` and
`XUI_DB_MAX_IDLE_CONNS`.
### Docker
`docker compose up -d` keeps using SQLite. To run with the bundled PostgreSQL
service, uncomment the two `XUI_DB_*` lines in `docker-compose.yml` and start
with the profile:
```bash
docker compose --profile postgres up -d
```
## Migrate SQLite → PostgreSQL
Move an existing SQLite install to PostgreSQL with the built-in command:
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
```
Then set `XUI_DB_TYPE` and `XUI_DB_DSN` in `/etc/default/x-ui` and restart:
```bash
systemctl restart x-ui
```
<Callout type="info">
The source SQLite file is left untouched — remove it manually only after you've
verified the new backend works.
</Callout>
## Backups
Whichever backend you use, back it up regularly — see
[Backup & restore](/docs/operations/backup-restore).
@@ -0,0 +1,84 @@
---
title: Environment Variables
description: Complete reference for 3x-ui's XUI_* environment variables — database, panel, logging, memory, and the tunnel health monitor.
icon: Variable
---
3x-ui reads its runtime configuration from `XUI_*` environment variables. On a
script install the installer writes them to the service environment file
(`/etc/default/x-ui`, or `/etc/conf.d/x-ui` / `/etc/sysconfig/x-ui` depending on
the distro); for Docker you set them in `docker-compose.yml` or `docker run -e`.
Defaults are sensible — set only what you need to change, then restart:
`systemctl restart x-ui`.
## Database
| Variable | Default | Description |
| ------------------------ | ----------- | -------------------------------------------------------------------- |
| `XUI_DB_TYPE` | `sqlite` | Backend: `sqlite`, or `postgres` (also accepts `postgresql` / `pg`). |
| `XUI_DB_FOLDER` | `/etc/x-ui` | Folder for the SQLite database file (`x-ui.db`). |
| `XUI_DB_DSN` | — | PostgreSQL connection string (used when `XUI_DB_TYPE=postgres`). |
| `XUI_DB_MAX_OPEN_CONNS` | — | Max open connections in the PostgreSQL pool. |
| `XUI_DB_MAX_IDLE_CONNS` | — | Max idle connections in the PostgreSQL pool. |
The default SQLite database path is `/etc/x-ui/x-ui.db`. See
[Database](/docs/reference/database) for the SQLite ↔ PostgreSQL details.
## Panel
| Variable | Default | Description |
| ------------------------ | ------- | ------------------------------------------------------------------------ |
| `XUI_PORT` | — | Override the panel port (165535). Takes precedence over the stored setting. |
| `XUI_INIT_WEB_BASE_PATH` | `/` | Initial web base path on **first** launch (e.g. `/panel`). |
| `XUI_ENABLE_FAIL2BAN` | `true` | Enable Fail2ban-based IP-limit enforcement. |
| `XUI_SKIP_HSTS` | `false` | Skip the HSTS header — set `true` when TLS is terminated by a reverse proxy. |
## Logging & binaries
| Variable | Default | Description |
| ---------------- | ---------------- | ----------------------------------------------------------- |
| `XUI_LOG_LEVEL` | `info` | `debug`, `info`, `notice`, `warning`, or `error`. |
| `XUI_DEBUG` | `false` | Debug mode (forces log level to `debug`). |
| `XUI_LOG_FOLDER` | `/var/log/x-ui` | Log output directory. |
| `XUI_BIN_FOLDER` | `bin` | Folder for the Xray-core binary and geosite/geoip files. |
## Memory & profiling
The panel keeps memory low via `GOGC` and periodic releases. These are advanced
knobs — leave them unset unless you're tuning a constrained host.
| Variable | Default | Description |
| ----------------------------- | ------- | ----------------------------------------------------------------- |
| `XUI_GOGC` | — | Go GC target percentage; lower = less RAM, slightly more CPU. |
| `XUI_MEMORY_RELEASE_INTERVAL` | — | Minutes between `FreeOSMemory` calls; `0` disables. |
| `XUI_MEMORY_LIMIT` | — | Go soft memory limit in **MiB**. |
| `GOMEMLIMIT` | — | Go-syntax soft limit (e.g. `400MiB`); takes precedence over above.|
| `XUI_PPROF` | `false` | Expose pprof profiling on `127.0.0.1:6060`. |
## Xray
| Variable | Default | Description |
| ------------------------ | ------- | --------------------- |
| `XRAY_VMESS_AEAD_FORCED` | `false` | Force VMess AEAD. |
## Tunnel health monitor
Optional watchdog: it probes a URL (optionally **through** a local Xray inbound)
and restarts Xray after repeated failures. A restart drops all connected
clients, so enable it deliberately.
| Variable | Default | Description |
| ----------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
| `XUI_TUNNEL_HEALTH_MONITOR` | `false` | Enable the monitor. |
| `XUI_TUNNEL_HEALTH_PROXY` | — | Proxy to send the probe through, e.g. `socks5://127.0.0.1:1080`. Empty = only checks host connectivity. |
| `XUI_TUNNEL_HEALTH_URL` | `https://www.cloudflare.com/cdn-cgi/trace` | URL to probe. |
| `XUI_TUNNEL_HEALTH_INTERVAL` | `30s` | Interval between probes. |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | Per-probe timeout. |
| `XUI_TUNNEL_HEALTH_FAILURES` | `3` | Consecutive failures before a restart. |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | Minimum delay between restarts. |
## Unattended install
| Variable | Description |
| -------------------- | -------------------------------------------------------------------------------------------- |
| `XUI_NONINTERACTIVE` | Set to `1` (or run with no TTY) to install with zero prompts; generated credentials are written to `/etc/x-ui/install-result.env`. See [Installation](/docs/guide/installation#unattended--cloud-init). |
+5
View File
@@ -0,0 +1,5 @@
{
"title": "Reference",
"icon": "BookMarked",
"pages": ["env-vars", "database", "ports-firewall", "api"]
}
@@ -0,0 +1,36 @@
---
title: Ports & Firewall
description: The ports 3x-ui uses by default and ready-made ufw / nftables rules to open them.
icon: Network
---
Open only the ports you actually use. Below are the common ones and a generator
for `ufw` and `nftables` rules.
## Common ports
| Port (default) | Purpose |
| -------------- | ----------------------------------------- |
| `22` | SSH (keep this open!). |
| `2053` | Panel (configurable). |
| `2096` | Subscription server (if separate). |
| `443` | A common inbound port (TLS / REALITY). |
| `80` / `443` | Reverse proxy (if you run one). |
Your actual inbound ports depend on the inbounds you create.
## Generate firewall rules
<FirewallRulesGenerator />
<Callout type="warn">
Always keep SSH allowed before enabling a default-deny policy, and test from a
second session so you don't lock yourself out.
</Callout>
## Related
<Cards>
<Card title="Security" href="/docs/operations/security" description="Fail2ban, IP limits, and hardening." />
<Card title="Environment variables" href="/docs/reference/env-vars" description="XUI_PORT and friends." />
</Cards>
+67
View File
@@ -0,0 +1,67 @@
---
title: کلاینت‌ها
description: مدیریت کلاینت‌های 3x-ui — اعتبارنامه‌ها، محدودیت ترافیک و انقضا، محدودیت IP، گروه‌ها، اقدامات گروهی، لینک‌های خارجی و وضعیت آنلاین.
icon: Users
---
یک **کلاینت** یک کاربر منفرد است که با یک **ایمیل** یکتا شناسایی می‌شود. در پنل
فعلی، کلاینت‌ها رکوردهای درجه‌یک هستند که می‌توانند هم‌زمان به **چندین ورودی**
متصل شوند و حساب‌داری ترافیک به‌صورت جداگانه برای هر کلاینت انجام می‌شود.
## فیلدهای کلاینت
| فیلد | اعمال بر | معنی |
| -------------- | --------------------- | ------------------------------------------------------------------ |
| **Email** | همه | شناسه‌ی یکتا که برای حساب‌داری و جست‌وجوها استفاده می‌شود. |
| **ID (UUID)** | VLESS, VMess | اعتبارنامه‌ی کلاینت. |
| **Password** | Trojan, Shadowsocks | اعتبارنامه‌ی کلاینت. |
| **Auth** | Hysteria2 | اعتبارنامه‌ی کلاینت. |
| **Flow** | VLESS | جریان XTLS، برای مثال `xtls-rprx-vision`. |
| **Limit IP** | همه | بیشینه‌ی تعداد IPهای مبدأ هم‌زمان (با Fail2ban اعمال می‌شود). |
| **Total (GB)** | همه | سهمیه‌ی ترافیک؛ هنگام اتمام، کلاینت غیرفعال می‌شود. |
| **Expiry** | همه | تاریخی که پس از آن کلاینت از کار می‌افتد. |
| **Reset** | همه | دوره‌ی تمدید خودکار به **روز** (سهمیه را از نو می‌چرخاند). |
| **Telegram ID**| همه | کلاینت را به یک کاربر Telegram برای سلف‌سرویس/اعلان‌ها پیوند می‌دهد.|
| **Sub ID** | همه | شناسه‌ی اشتراک که لینک‌های این کلاینت را گروه‌بندی می‌کند. |
| **Group** | همه | گروه اختیاری کلاینت برای سازمان‌دهی و فیلترکردن گروهی. |
| **Comment** | همه | یادداشت متنی آزاد. |
<Callout type="info">
رسیدن به محدودیت **ترافیک** یا **انقضا** کلاینت را غیرفعال می‌کند؛ پنل می‌تواند
هنگام غیرفعال‌شدن خودکار کلاینت‌ها، Xray را به‌صورت خودکار راه‌اندازی مجدد کند
(`restartXrayOnClientDisable`، به‌صورت پیش‌فرض فعال).
</Callout>
## محدودیت‌ها و کنترل IP
- سقف‌های **ترافیک / انقضا** هنگام رسیدن، کلاینت را غیرفعال می‌کنند؛ یک دوره‌ی
**Reset** سهمیه را به‌صورت خودکار تمدید می‌کند.
- **Limit IP** تعداد IPهای مبدأ هم‌زمان را محدود می‌کند. اعمال آن به Fail2ban متکی
است — به [امنیت](/docs/operations/security) مراجعه کنید. می‌توانید IPهای اخیر یک
کلاینت را مشاهده کرده و آن‌ها را از بخش اقدامات کلاینت پاک کنید.
- **وضعیت آنلاین** و زمان‌های **آخرین‌بار آنلاین** برای هر کلاینت (و در پیکربندی‌های
چندنودی برای هر نود) ثبت می‌شوند.
## لینک‌های اشتراک‌گذاری و لینک‌های خارجی
هر کلاینت برای ورودی‌هایش لینک‌های اشتراک‌گذاری و یک کد QR دارد، به‌علاوه‌ی یک
[اشتراک](/docs/config/subscription) ترکیبی. همچنین می‌توانید **لینک‌های خارجی** به
یک کلاینت متصل کنید — لینک‌های اضافی `vless://`، `vmess://`، `trojan://`، `ss://`،
`hysteria2://` یا `wireguard://`، یا یک URL اشتراک از راه دور — تا در کنار
لینک‌های تولیدشده توسط پنل، در اشتراک کلاینت نمایش داده شوند.
برای بررسی دقیق محتویات یک لینک، آن را در
[بازرس لینک اشتراک‌گذاری](/docs/config/share-links) جای‌گذاری کنید.
## اقدامات گروهی
برای مدیریت هم‌زمان تعداد زیادی کلاینت، پنل از اقدامات گروهی **ساخت، فعال‌سازی،
غیرفعال‌سازی، حذف، اتصال/قطع اتصال** (به ورودی‌ها)، **بازنشانی ترافیک** و
**تنظیم** (افزودن روز / افزودن بایت / تعیین flow) پشتیبانی می‌کند. اقدامات
نگه‌داری همچنین به شما امکان می‌دهند کلاینت‌های **تمام‌شده** (سهمیه/انقضای پایان‌یافته)
و کلاینت‌های **یتیم** (متصل‌نشده به هیچ ورودی) را حذف کنید.
<Callout type="warn">
لینک اشتراک‌گذاری یک کلاینت حاوی اعتبارنامه‌ی آن است. با لینک‌ها و کدهای QR مانند
رمز عبور رفتار کنید و در صورت نشت یکی از آن‌ها، اعتبارنامه را تعویض کنید.
</Callout>
+97
View File
@@ -0,0 +1,97 @@
---
title: ورودی‌ها و پروتکل‌ها
description: ساخت ورودی‌ها در 3x-ui — پروتکل‌ها، انتقال‌ها، بازنشانی و انقضای ترافیک، و fallbackهایی که چند پروتکل را روی یک پورت سرویس می‌دهند.
icon: ArrowDownToLine
---
یک **ورودی (inbound)** شنونده‌ای است که اتصال‌های کلاینت را روی یک پورت با
پروتکل و انتقال مشخصی می‌پذیرد. بیشتر کارهای روزمره شما ساخت و مدیریت ورودی‌ها و
کلاینت‌های درون آن‌هاست.
## ساخت یک ورودی
<Steps>
<Step>
### افزودن یک ورودی
به **Inbounds → Add** بروید، یک توضیح (remark) برای آن بگذارید، یک **پروتکل**
انتخاب کنید، و یک **پورت** و آدرس شنود انتخاب کنید.
</Step>
<Step>
### انتخاب انتقال و امنیت
انتقال (TCP، WebSocket، gRPC، HTTPUpgrade، XHTTP، …) و لایه امنیتی (هیچ‌کدام،
TLS یا REALITY) را انتخاب کنید. به [انتقال‌ها](/docs/config/transports) و
[REALITY](/docs/config/reality) مراجعه کنید.
</Step>
<Step>
### افزودن کلاینت‌ها
یک یا چند کلاینت اضافه کنید که هر کدام اعتبارنامه، محدودیت‌ها و لینک اشتراک
خودش را دارد. به [کلاینت‌ها](/docs/config/clients) مراجعه کنید.
</Step>
<Step>
### تنظیم محدودیت ترافیک، انقضا و بازنشانی
به‌صورت اختیاری می‌توانید کل ترافیک را محدود کنید و یک تاریخ انقضا برای ورودی
تعیین کنید، و یک زمان‌بندی **بازنشانی ترافیک** دوره‌ای انتخاب کنید: `never`
(پیش‌فرض)، `hourly`، `daily`، `weekly` یا `monthly`.
</Step>
</Steps>
## پروتکل‌های پشتیبانی‌شده
ویرایشگر ورودی این پروتکل‌ها را می‌پذیرد:
| پروتکل | توضیحات |
| ---------------------- | ------------------------------------------------------------------------ |
| **VLESS** | سبک؛ پایه‌ی REALITY + XTLS-Vision. توصیه‌شده. |
| **VMess** | قدیمی‌تر اما با پشتیبانی بسیار گسترده در کلاینت‌ها. |
| **Trojan** | مبتنی بر TLS؛ از XTLS و fallback پشتیبانی می‌کند. |
| **Shadowsocks** | شامل رمزهای Shadowsocks-2022 (`2022-blake3-*`). |
| **WireGuard** | تونل مدرن. |
| **Hysteria2** | با عنوان `hysteria` انتخاب می‌شود؛ پنل لینک‌های `hysteria2://` تولید می‌کند. |
| **HTTP** | پراکسی HTTP. |
| **Mixed (SOCKS/HTTP)** | یک شنونده ترکیبی SOCKS + HTTP. |
| **Dokodemo-door / Tunnel** | فورواردینگ پورت / هدایت ترافیک. |
| **MTProto** | پراکسی MTProto تلگرام که توسط یک فرایند همراه `mtg` سرویس می‌شود (نه Xray). |
<Callout type="info">
Hysteria2 در سطح داخلی یک پروتکل جداگانه نیست — همان پروتکل `hysteria` است که
نسخه انتقال آن روی ۲ تنظیم شده، و پنل برای آن لینک‌های اشتراک `hysteria2://`
تولید می‌کند.
</Callout>
## Fallbackها — چند پروتکل روی یک پورت
Fallbackها به یک پورت TLS واحد (مثلاً `443`) اجازه می‌دهند بیش از یک پروتکل را
سرویس دهد — برای مثال VLESS **و** Trojan — با هدایت دست‌دادن‌های (handshake)
ناهماهنگ به یک ورودی فرزند. در 3x-ui، fallbackها در پنل مدیریت می‌شوند (لیست
**Fallbacks** یک ورودی اصلی) به‌جای آنکه به‌صورت دستی در JSON نوشته شوند.
Fallbackها تنها زمانی در دسترس‌اند که ورودی اصلی این‌گونه باشد:
- **VLESS** یا **Trojan**،
- روی انتقال خام **TCP**،
- با امنیت **TLS** یا **REALITY**.
هر قاعده fallback یک ورودی فرزند را هدف قرار می‌دهد و می‌تواند بر اساس `path`،
`alpn` و `dest` تطبیق یابد. لینک‌های اشتراک کلاینت برای یک فرزند fallback
به‌صورت خودکار بازنویسی می‌شوند تا آدرس، پورت و TLS ورودی اصلی را اعلام کنند.
## مطمئن نیستید کدام را انتخاب کنید؟
از این جادوگر استفاده کنید تا بر اساس اهداف و کلاینت‌هایتان یک پیشنهاد دریافت کنید:
<ProtocolWizard />
<Callout type="info">
برای مقاومت در برابر سانسور با کلاینت‌های مدرن، **VLESS + REALITY +
XTLS-Vision** معمولاً بهترین انتخاب است — به
[REALITY](/docs/config/reality) ادامه دهید.
</Callout>
+14
View File
@@ -0,0 +1,14 @@
{
"title": "پیکربندی",
"icon": "Settings",
"pages": [
"panel",
"ssl-certificates",
"inbounds",
"reality",
"transports",
"clients",
"subscription",
"share-links"
]
}
+77
View File
@@ -0,0 +1,77 @@
---
title: تنظیمات پنل
description: تمام تنظیمات پنل 3x-ui — وب‌سرور، TLS، نمایش، امنیت و اعلان‌ها — همراه با مقادیر پیش‌فرض برگرفته از سورس.
icon: SlidersHorizontal
---
**تنظیمات پنل** نحوه‌ی ارائه و ایمن‌سازی خودِ پنل را کنترل می‌کند (جدا از ورودی‌ها
و کلاینت‌های شما). تنظیمات به‌صورت جفت‌های کلید/مقدار ذخیره می‌شوند؛ مقادیر
پیش‌فرض زیر مستقیماً از سورس پنل گرفته شده‌اند. اطلاعات محرمانه (توکن‌ها، گذرواژه‌ها)
فقط با نشانگرِ «تنظیم‌شده / تنظیم‌نشده» نمایش داده می‌شوند و هرگز به‌صورت کامل به
مرورگر بازگردانده نمی‌شوند.
## وب‌سرور
| Setting | Default | Meaning |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | پورت پنل (۱ تا ۶۵۵۳۵). متغیر محیطی `XUI_PORT` در زمان اجرا آن را بازنویسی می‌کند. |
| `webListen` | _(همه‌ی واسط‌ها)_ | پنل را به یک IP مشخص مقید کنید. |
| `webBasePath` | `/` | مسیر URLی که پنل زیر آن ارائه می‌شود (همیشه به شکل `/…/` نرمال‌سازی می‌شود). |
| `webCertFile` / `webKeyFile` | _(هیچ‌کدام)_ | گواهی + کلید TLS. وقتی هر دو تنظیم شوند، پنل با **HTTPS** ارائه می‌شود. |
| `sessionMaxAge` | `360` | طول عمر نشست بر حسب **دقیقه** (پیش‌فرض ۶ ساعت). |
| `trustedProxyCIDRs` | `127.0.0.1/32,::1/128` | IPها/CIDRهایی که هدرهای فورواردشده‌شان (IP واقعی کلاینت) مورد اعتماد است. |
| `panelOutbound` | _(هیچ‌کدام)_ | مسیریابی خروجیِ خود پنل (بررسی به‌روزرسانی‌ها، Telegram، واکشی geo/sub) از طریق یک خروجی Xray با نام مشخص. |
پس از تغییر پورت یا مسیر پایه، آدرس پنل به‌صورت
`http(s)://<server>:<port><web-base-path>` درمی‌آید. می‌توانید مسیر پایه را در
نخستین اجرا با [`XUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars) از پیش تعیین کنید.
### TLS
ارائه‌ی پنل روی HTTPS از اطلاعات احراز هویت شما در حین انتقال محافظت می‌کند. یا
`webCertFile` + `webKeyFile` را تنظیم کنید — [منوی SSL در `x-ui`](/docs/config/ssl-certificates)
می‌تواند یک گواهی Let's Encrypt برای شما تهیه کند — یا TLS را روی یک
[پروکسی معکوس](/docs/operations/reverse-proxy) خاتمه دهید.
<Callout type="warn">
هرگز پنل را روی اینترنت عمومی با HTTP ساده در دسترس قرار ندهید. از TLS، یک پورت
غیرپیش‌فرض، و یک مسیر پایه‌ی وب تصادفیِ بلند استفاده کنید.
</Callout>
## نمایش
| Setting | Default | Meaning |
| ---------------- | ------------------------------------------------ | ------------------------------------------------------------- |
| `pageSize` | `25` | تعداد ردیف در هر صفحه از فهرست‌ها (`0` صفحه‌بندی را غیرفعال می‌کند). |
| `expireDiff` | `0` | تعداد روز پیش از انقضا برای شروع هشدار. |
| `trafficDiff` | `0` | درصد باقی‌مانده از سهمیه که در آن هشدار آغاز می‌شود. |
| `remarkTemplate` | `{{INBOUND}}-{{EMAIL}}\|📊{{TRAFFIC_LEFT}}\|⏳{{DAYS_LEFT}}D` | الگوی پیش‌فرض یادداشت کلاینت (نگاه کنید به [لینک‌های اشتراک‌گذاری](/docs/config/share-links#remark-template-variables)). |
| `timeLocation` | `Local` | منطقه‌ی زمانی برای آمار و انقضا. |
| `datepicker` | `gregorian` | تقویم برای ورودی‌های تاریخ (میلادی یا جلالی/شمسی). |
## امنیت و احراز هویت
اطلاعات احراز هویت، احراز هویت دومرحله‌ای، محدودکننده‌ی حملات جستجوی فراگیر،
نشست‌ها و LDAP در [نخستین ورود](/docs/guide/first-login) و
[امنیت](/docs/operations/security) پوشش داده شده‌اند. به‌طور خلاصه:
- گذرواژه‌ها به‌صورت هش‌های **bcrypt** ذخیره می‌شوند؛ تغییر آن‌ها همه‌ی نشست‌ها را از سیستم خارج می‌کند.
- **۲FA (TOTP)** می‌تواند در زمان ورود الزامی شود.
- یک سازوکار جایگزین **LDAP** می‌تواند زمانی که بررسی گذرواژه‌ی محلی ناموفق باشد، کاربران را احراز هویت کند.
- دسترسی API از **توکن‌های API** استفاده می‌کند که زیر تنظیمات پنل مدیریت می‌شوند (نگاه کنید به
[مرجع API](/docs/reference/api/api-tokens)).
## اعلان‌ها و اشتراک
این موارد گروه‌های تنظیمات و صفحه‌های مخصوص خود را دارند:
<Cards>
<Card title="ربات Telegram" href="/docs/operations/telegram-bot" description="توکن، شناسه‌های چت، هشدارها و گزارش‌ها." />
<Card title="اشتراک" href="/docs/config/subscription" description="سرور اشتراک، قالب‌ها و مسیرها." />
<Card title="امنیت" href="/docs/operations/security" description="۲FA، محدودیت‌های IP و سخت‌سازی." />
</Cards>
<Callout type="info">
اعلان‌های ایمیل (SMTP) نیز قابل پیکربندی‌اند (میزبان، پورت، رمزنگاری،
گیرندگان) با همان انواع رویدادهای ربات Telegram.
</Callout>
+135
View File
@@ -0,0 +1,135 @@
---
title: REALITY
description: راه‌اندازی یک ورودی VLESS + REALITY همراه با XTLS-Vision در 3x-ui — کلیدها، short IDها، SNI، اثرانگشت‌ها و اشتباهات رایج.
icon: ShieldCheck
---
**REALITY** یک لایه‌ی امنیتی انتقال در Xray است که پروکسی شما را به‌شکل ترافیک
عادی به یک وب‌سایت واقعی و پرطرفدار جلوه می‌دهد. برخلاف TLS کلاسیک، سرور شما به
**هیچ گواهی اختصاصی** نیاز ندارد — دست‌دهی (handshake) TLS سایت مقصد (`dest`) را
قرض می‌گیرد. در ترکیب با جریان **XTLS-Vision**، سریع است و در برابر بازرسی عمیق
بسته‌ها (DPI) مقاومت می‌کند.
REALITY همراه با **VLESS** (و Trojan) به‌کار می‌رود. جریان توصیه‌شده
`xtls-rprx-vision` است.
## تنظیمات کلیدی
وقتی **REALITY** را به‌عنوان حالت امنیتی روی یک ورودی VLESS انتخاب می‌کنید، 3x-ui
این فیلدها را نمایش می‌دهد:
| فیلد | چیست |
| ------------------------ | ------------------------------------------------------------------ |
| **Dest (target)** | یک سایت TLS واقعی برای جعل هویت، برای مثال `www.microsoft.com:443`. |
| **SNI / Server Names** | نام میزبانی که کلاینت‌ها ارسال می‌کنند؛ باید با گواهی مقصد بخواند. |
| **Public / Private key** | یک جفت‌کلید **x25519**. کلید خصوصی روی سرور باقی می‌ماند. |
| **Short IDs** | رشته‌های Hex برای احراز هویت کلاینت‌ها (می‌توانید چندتا داشته باشید).|
| **Flow** | روی `xtls-rprx-vision` تنظیم شود. |
| **Fingerprint (uTLS)** | اثرانگشت TLS کلاینت برای تقلید، برای مثال `chrome`. |
کلید خصوصی با ابزار `x25519` از Xray تولید می‌شود (پنل می‌تواند این جفت‌کلید را
برای شما بسازد):
```bash title="generate an x25519 keypair"
xray x25519
```
## راه‌اندازی در پنل
<Steps>
<Step>
### ساخت یک ورودی VLESS
یک ورودی جدید اضافه کنید، پروتکل **VLESS** را انتخاب کنید و **Security** را روی
**reality** تنظیم کنید.
</Step>
<Step>
### انتخاب مقصد (dest) و SNI
سایتی معتبر که از TLS 1.3 و HTTP/2 پشتیبانی می‌کند و هم از سرور و هم از کلاینت‌های
شما در دسترس است انتخاب کنید (برای مثال `www.microsoft.com:443`). نام سرورها / SNI
را طوری تنظیم کنید که با گواهی آن سایت بخواند.
</Step>
<Step>
### تولید کلیدها و short IDها
جفت‌کلید x25519 و یک یا چند short ID تولید کنید. **کلید خصوصی** را محرمانه نگه
دارید؛ کلاینت‌ها فقط **کلید عمومی** را دریافت می‌کنند.
</Step>
<Step>
### تنظیم جریان و اثرانگشت
از جریان `xtls-rprx-vision` و یک اثرانگشت رایج uTLS مانند `chrome` استفاده کنید.
</Step>
<Step>
### افزودن کلاینت و اشتراک‌گذاری لینک
یک کلاینت بسازید، سپس از لینک اشتراک‌گذاری یا کد QR آن در یک برنامه‌ی سازگار
(v2rayNG، Hiddify، Mihomo و دیگران) استفاده کنید.
</Step>
</Steps>
## پیکربندی چه شکلی است
روی سرور، `streamSettings` یک ورودی REALITY تقریباً به این شکل است:
```json title="server inbound (excerpt)"
{
"network": "tcp",
"security": "reality",
"realitySettings": {
"dest": "www.microsoft.com:443",
"serverNames": ["www.microsoft.com"],
"privateKey": "<x25519 private key>",
"shortIds": ["<hex short id>"],
"fingerprint": "chrome"
}
}
```
لینک اشتراک‌گذاری متناظر کلاینت، پارامترهای **عمومی** را حمل می‌کند:
```text title="vless:// (excerpt)"
vless://<uuid>@<server>:443?security=reality&pbk=<public-key>&sid=<short-id>&sni=www.microsoft.com&fp=chrome&spx=%2F&flow=xtls-rprx-vision#my-reality
```
- `pbk` — کلید **عمومی** REALITY
- `sid` — short ID (با یکی از موارد روی سرور می‌خواند)
- `sni` — نام سرور (با گواهی مقصد می‌خواند)
- `fp` — اثرانگشت کلاینت
- `spx` — مسیر spiderX
- `flow` — `xtls-rprx-vision`
## اشتباهات رایج
<Callout type="warn">
- **مقصد نامناسب.** مقدار `dest` باید یک سایت واقعی باشد که از **TLS 1.3** و
**HTTP/2** پشتیبانی می‌کند، در دسترس است و در منطقه‌ی شما مسدود نیست. سایتی را
انتخاب کنید که مالک آن نیستید و ترافیک زیادی دارد.
- **عدم تطابق SNI.** مقدار SNI / نام سرورها باید با گواهی واقعی مقصد بخواند، وگرنه
دست‌دهی، استتار را لو می‌دهد.
- **نشت کلید خصوصی.** فقط و فقط **کلید عمومی** را میان کلاینت‌ها توزیع کنید.
- **جریان نادرست.** REALITY + XTLS-Vision به `flow = xtls-rprx-vision` هم در ورودیِ
مدخل کلاینت و هم در لینک اشتراک‌گذاری نیاز دارد.
</Callout>
## تولید یک پیکربندی
از تولیدکننده‌ی زیر برای ساخت یک جفت‌کلید تازه‌ی X25519، UUID و short ID استفاده
کنید، سپس JSON ورودی سرور و لینک اشتراک‌گذاری کلاینت را کپی کنید. همه‌چیز **در
مرورگر شما** محاسبه می‌شود — هیچ کلید یا لینکی به جایی ارسال نمی‌شود.
<RealityConfigGenerator />
<Callout type="info">
**کلید خصوصی** فقط به سرور شما تعلق دارد. لینک تولیدشده‌ی `vless://` (که حاوی
**کلید عمومی** است) را با کلاینت‌ها به اشتراک بگذارید.
</Callout>
@@ -0,0 +1,81 @@
---
title: لینک‌های اشتراک‌گذاری
description: قالب‌های لینک اشتراک‌گذاری 3x-ui (vless، vmess، trojan، ss، hysteria2، mtproto)، متغیرهای قالب توضیحات، و بازرس لینک درون‌مرورگری.
icon: Link
---
3x-ui برای هر کلاینت یک **لینک اشتراک‌گذاری** (و کد QR) تولید می‌کند. برنامه‌های کلاینت
مانند v2rayNG، Hiddify و Mihomo این لینک‌ها را برای پیکربندی خودشان وارد می‌کنند.
## قالب‌های لینک
| Scheme | ساختار |
| -------------- | --------------------------------------------------------------- |
| `vless://` | `vless://<uuid>@<host>:<port>?<params>#<remark>` |
| `vmess://` | `vmess://<base64-json>` (یک شیء JSON کدشده با base64) |
| `trojan://` | `trojan://<password>@<host>:<port>?<params>#<remark>` |
| `ss://` | `ss://<userinfo>@<host>:<port>?<params>#<remark>` (SIP002؛ Shadowsocks-2022 از userinfo کدگذاری‌شده با درصد استفاده می‌کند) |
| `hysteria2://` | `hysteria2://<auth>@<host>:<port>?<params>#<remark>` |
| `tg://proxy` | `tg://proxy?server=…&port=…&secret=…` (MTProto) |
پارامترهای کوئری تنظیمات انتقال و امنیت را حمل می‌کنند — `security`،
`sni`، `fp`، `pbk`، `sid`، `spx`، `flow`، `type`، `path`، `host`، `alpn` و
بیشتر.
## بازرسی یک لینک
هر لینک اشتراک‌گذاری را بچسبانید تا تک‌تک فیلدها رمزگشایی شوند. تجزیه **به‌طور کامل در
مرورگر شما** انجام می‌شود — لینک هرگز روی شبکه ارسال نمی‌شود.
<ShareLinkInspector />
<Callout type="warn">
لینک‌های اشتراک‌گذاری همه‌ی آنچه را برای اتصال به‌عنوان یک کلاینت لازم است در بر دارند، از جمله
اعتبارنامه‌ی کلاینت. با آن‌ها مانند رمز عبور رفتار کنید.
</Callout>
## متغیرهای قالب توضیحات
متنی که در هر لینک پس از `#` می‌آید (**توضیحات** یا remark) از یک قالب تولید می‌شود
که شما در تنظیمات پنل کنترل می‌کنید (`remarkTemplate`). مقدار پیش‌فرض این است:
```text
{{INBOUND}}-{{EMAIL}}|📊{{TRAFFIC_LEFT}}|⏳{{DAYS_LEFT}}D
```
توکن‌ها از نحو `{{UPPER_CASE}}` استفاده می‌کنند. قالب بر اساس `|` به بخش‌هایی تقسیم می‌شود؛
بخشی که تنها مقدارش نشانگر نامحدود `∞` باشد (برای `TRAFFIC_LEFT`،
`TRAFFIC_TOTAL`، `DAYS_LEFT` یا `TIME_LEFT`) حذف می‌شود، تا کلاینت‌های نامحدود
تزئینات خالی نشان ندهند.
### توکن‌های در دسترس
| توکن | مقدار |
| ----- | ----- |
| `{{EMAIL}}` / `{{USERNAME}}` | ایمیل کلاینت (شناسه) |
| `{{INBOUND}}` | توضیحات اینباند |
| `{{HOST}}` | توضیحات ردیف هاست (هاست‌های مدیریت‌شده) |
| `{{ID}}` / `{{SHORT_ID}}` | UUID کلاینت / ۸ کاراکتر نخست آن |
| `{{TELEGRAM_ID}}` · `{{SUB_ID}}` · `{{COMMENT}}` | شناسه Telegram، شناسه اشتراک، توضیح |
| `{{STATUS}}` / `{{STATUS_EMOJI}}` | `active`/`expired`/`depleted`/`disabled` (یا ✅⏳🚫) |
| `{{DAYS_LEFT}}` / `{{TIME_LEFT}}` | روزهای باقی‌مانده، یا `Xd Xh Xm` (`∞` در صورت نامحدود بودن) |
| `{{EXPIRE_DATE}}` / `{{JALALI_EXPIRE_DATE}}` / `{{EXPIRE_UNIX}}` | تاریخ انقضا به‌صورت میلادی / شمسی / ثانیه‌های Unix |
| `{{CREATED_UNIX}}` | زمان ایجاد (ثانیه‌های Unix) |
| `{{TRAFFIC_USED}}` / `{{TRAFFIC_LEFT}}` / `{{TRAFFIC_TOTAL}}` | مصرف خوانا برای انسان (`∞` در صورت نامحدود بودن) |
| `{{TRAFFIC_USED_BYTES}}` / `{{TRAFFIC_LEFT_BYTES}}` / `{{TRAFFIC_TOTAL_BYTES}}` | همان، بر حسب بایت |
| `{{UP}}` / `{{DOWN}}` | آپلود / دانلود (خوانا برای انسان) |
| `{{RESET_DAYS}}` · `{{USAGE_PERCENTAGE}}` | دوره بازنشانی (روز) · درصد مصرف‌شده |
| `{{PROTOCOL}}` / `{{TRANSPORT}}` / `{{SECURITY}}` | مثلاً `VLESS` / `ws` / `REALITY` |
<Callout type="info">
توکن‌های مصرف (ترافیک، روزها، وضعیت) در **بدنه**ی اشتراک ظاهر می‌شوند اما
از نمای نمایش/QR حذف می‌گردند، تا یک QR اشتراک‌گذاری‌شده سهمیه‌ی باقی‌مانده‌ی یک کلاینت
را افشا نکند. توکن‌های تاریخ از تنظیم `datepicker` پیروی می‌کنند (میلادی یا شمسی).
</Callout>
## مرتبط
<Cards>
<Card title="REALITY" href="/docs/config/reality" description="یک پیکربندی و لینک VLESS + REALITY بسازید." />
<Card title="اشتراک" href="/docs/config/subscription" description="همه‌ی لینک‌های یک کلاینت را از یک URL ارائه دهید." />
</Cards>
@@ -0,0 +1,179 @@
---
title: گواهی‌های SSL
description: دریافت و تمدید گواهی‌های TLS برای پنل و ورودی‌های 3x-ui — با منوی ACME در x-ui (دامنه یا IP خام)، گواهی wildcard از طریق Cloudflare DNS-01، یا Certbot دستی.
icon: ShieldCheck
---
یک گواهی TLS به شما امکان می‌دهد **پنل** را روی HTTPS سرویس‌دهی کنید (تا ترافیک ورود و
API شما رمزگذاری شود) و TLS را روی **ورودی‌ها** خاتمه دهید (VLESS-TLS، Trojan،
Shadowsocks-TLS و موارد مشابه). سه راه برای به‌دست‌آوردن گواهی وجود دارد:
- **منوی `x-ui`** — کلاینت داخلی [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment).
آسان‌ترین گزینه برای یک دامنه‌ی واحد یا یک IP خام.
- **Cloudflare DNS-01** — این هم از همان منو؛ برای گواهی‌های **wildcard** یا
زمانی که پورت 80 مسدود است / سرور پشت پراکسی Cloudflare قرار دارد لازم است.
- **Certbot دستی** — اگر ترجیح می‌دهید `acme.sh`/Certbot را خودتان مدیریت کنید.
<Callout type="info">
اگر پنل را پشت Nginx یا Caddy قرار می‌دهید، بگذارید پراکسی به‌جای شما گواهی را
مدیریت کند — به [پراکسی معکوس](/docs/operations/reverse-proxy) مراجعه کنید.
ورودی‌های [REALITY](/docs/config/reality) **هیچ** گواهی‌ای نیاز ندارند؛ آن‌ها
TLS یک سایت واقعی را قرض می‌گیرند. این صفحه برای پنل و برای ورودی‌های کلاسیک TLS است.
</Callout>
## منوی SSL در `x-ui` (Let's Encrypt)
`x-ui` را اجرا کنید و **`20` — SSL Certificate Management** را انتخاب کنید. این گزینه
[acme.sh](https://github.com/acmesh-official/acme.sh) را به کار می‌گیرد و موارد زیر را ارائه می‌دهد:
| گزینه | کاری که انجام می‌دهد |
| ------------------------------ | ------------------------------------------------------------------- |
| Get SSL (Domain) | صدور گواهی برای یک دامنه از طریق اعتبارسنجی HTTP. |
| Get SSL for IP Address | صدور یک گواهی کوتاه‌مدت (۶ روزه، با تمدید خودکار) برای یک **IP خام**. |
| Revoke | باطل‌کردن یک گواهی موجود. |
| Force Renew | تمدید همین حالا، پیش از انقضا. |
| Show Existing Domains | فهرست‌کردن گواهی‌هایی که از پیش روی سرور هستند. |
| Set Cert paths for the panel | اشاره‌دادن TLS پنل به یک گواهی صادرشده (فیلدها را برای شما تنظیم می‌کند). |
### صدور گواهی برای یک دامنه
<Steps>
<Step>
### دامنه را به سرور اشاره دهید
یک رکورد `A` (و/یا `AAAA`) برای دامنه‌ی خود بسازید که به IP عمومی این سرور
اشاره کند. تا زمانی که DNS منتشر (propagate) نشده باشد، اعتبارسنجی ناموفق خواهد بود.
</Step>
<Step>
### پورت 80 را آزاد کنید
اعتبارسنجی HTTP نیاز دارد که **پورت 80** از اینترنت در دسترس باشد و از پیش در حال
استفاده نباشد. هر چیزی را که به آن متصل است برای این مدت متوقف کنید و آن را از
[فایروال](/docs/reference/ports-firewall) عبور دهید.
</Step>
<Step>
### صادرکننده را اجرا کنید
`x-ui` ← `20` ← **Get SSL (Domain)**، سپس دامنه را وارد کنید. acme.sh گواهی را
درخواست می‌کند و آن را زیر `/root/cert/<domain>/` به‌صورت `fullchain.pem`
(زنجیره‌ی گواهی) و `privkey.pem` (کلید خصوصی) ذخیره می‌کند.
</Step>
<Step>
### آن را به پنل متصل کنید
گزینه‌ی **Set Cert paths for the panel** را انتخاب کنید تا `webCertFile` و
`webKeyFile` پر شوند و پنل راه‌اندازی مجدد شود، یا آن‌ها را خودتان در
[تنظیمات پنل](/docs/config/panel#tls) تنظیم کنید. به‌محض تنظیم‌شدن هر دو، پنل HTTPS را
سرویس‌دهی می‌کند.
</Step>
</Steps>
### صدور گواهی برای یک IP خام
دامنه‌ای ندارید؟ گزینه‌ی **Get SSL for IP Address** را انتخاب کنید تا یک گواهی
کوتاه‌مدت (با اعتبار حدود ۶ روز، که به‌صورت خودکار تمدید می‌شود) متصل به IP سرور
به‌دست آورید. برای دسترسی به پنل روی HTTPS پیش از آنکه دامنه‌ای راه‌اندازی کنید مفید است.
## Cloudflare (گواهی wildcard با DNS-01)
اعتبارسنجی DNS به‌جای پاسخ‌دادن روی پورت 80، با ساختن یک رکورد TXT ثابت می‌کند که شما
دامنه را در اختیار دارید — بنابراین **پشت پراکسی Cloudflare**، روی سرورهایی که
پورت 80 در آن‌ها مسدود است، و برای گواهی‌های **wildcard** (`*.example.com`) کار می‌کند.
DNS دامنه‌ی شما باید توسط Cloudflare مدیریت شود و به یکی از این موارد نیاز دارید:
- یک **توکن API محدودشده** با مجوز `Zone:DNS:Edit` (توصیه‌شده)، یا
- **ایمیل حساب + Global API Key**.
<Steps>
<Step>
### یک توکن API محدودشده بسازید
در داشبورد Cloudflare به **My Profile → API Tokens →
[Create Token](https://dash.cloudflare.com/profile/api-tokens)** بروید، قالب
**Edit zone DNS** را انتخاب کنید، آن را به zone‌ای که برایش گواهی صادر می‌کنید محدود
کنید و آن را بسازید. توکن را کپی کنید — فقط یک‌بار نمایش داده می‌شود.
</Step>
<Step>
### صادرکننده‌ی Cloudflare را اجرا کنید
`x-ui` ← **`21` — Cloudflare SSL Certificate**. هنگام پرسش، **`t`** را برای یک
توکن API (پیش‌فرض) یا **`g`** را برای Global API Key انتخاب کنید، سپس دامنه‌ی خود را
وارد کنید (و برای Global API Key، ایمیل حساب و کلید خود را). acme.sh رکورد TXT را
می‌سازد، اعتبارسنجی می‌کند و آن را پاک‌سازی می‌کند.
</Step>
<Step>
### پنل را به آن اشاره دهید
مانند جریان دامنه، از **Set Cert paths for the panel** (منوی `20`) استفاده کنید یا
`webCertFile` / `webKeyFile` را در [تنظیمات پنل](/docs/config/panel#tls) تنظیم کنید.
</Step>
</Steps>
<Callout type="info">
یک توکن محدودشده را به Global API Key ترجیح دهید — آن فقط اجازه‌ی ویرایش DNS را روی
zoneای که انتخاب می‌کنید می‌دهد، بنابراین نشت آن نمی‌تواند به بقیه‌ی حساب Cloudflare شما دست بزند.
</Callout>
## دستی (Certbot)
اگر ترجیح می‌دهید از منو استفاده نکنید، یک گواهی را با افزونه‌ی standalone مربوط به
Certbot صادر کنید (این هم نیاز دارد که پورت 80 آزاد باشد و دامنه به سرور اشاره کند):
```bash
apt-get install certbot -y
certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com
certbot renew --dry-run
```
Certbot گواهی را در `/etc/letsencrypt/live/yourdomain.com/` می‌نویسد
(`fullchain.pem` و `privkey.pem`). پنل را در [تنظیمات پنل](/docs/config/panel#tls) به آن
دو فایل اشاره دهید و تمدید را راه‌اندازی کنید — `certbot renew` به‌صورت پیش‌فرض روی یک
تایمر systemd اجرا می‌شود.
## استفاده از گواهی
- **پنل** — `webCertFile` (زنجیره‌ی کامل) و `webKeyFile` (کلید خصوصی) را در
[تنظیمات پنل](/docs/config/panel#tls) تنظیم کنید. برای آنکه پنل به HTTPS سوئیچ کند،
هر دو باید تنظیم شوند. گزینه‌ی منوی **`11` — View Current Settings** مسیرهای
درحال‌استفاده‌ی فعلی را چاپ می‌کند.
- **ورودی‌ها** — وقتی TLS را روی یک ورودی فعال می‌کنید، در تنظیمات TLS همان ورودی به
همان فایل‌های گواهی و کلید ارجاع دهید (یا محتوای آن‌ها را جای‌گذاری کنید). به
[ورودی‌ها](/docs/config/inbounds) و [ترابری‌ها](/docs/config/transports) مراجعه کنید.
<Callout type="warn">
گواهی‌ها منقضی می‌شوند (Let's Encrypt: ۹۰ روز؛ گواهی‌های IP: حدود ۶ روز). هم منو و هم
Certbot به‌صورت خودکار تمدید می‌کنند، اما پنل همچنان **فایل‌ها** را در مسیرهای ثابت‌شان
می‌خواند — بنابراین **در همان محل** تمدید کنید نه با جابه‌جاکردن فایل‌ها، و پنل در
راه‌اندازی مجدد بعدی‌اش گواهی جدید را برمی‌دارد. **Force Renew** (منوی `20`) یک تمدید
را به‌صورت درخواستی فعال می‌کند.
</Callout>
## گام‌های بعدی
<Cards>
<Card
title="تنظیمات پنل"
href="/docs/config/panel#tls"
description="webCertFile / webKeyFile و بقیه‌ی تنظیمات وب‌سرور."
/>
<Card
title="پراکسی معکوس"
href="/docs/operations/reverse-proxy"
description="به‌جای آن، بگذارید Nginx یا Caddy کار خاتمه‌دادن TLS را برایتان انجام دهد."
/>
<Card
title="REALITY"
href="/docs/config/reality"
description="TLS مخفیانه برای ورودی‌ها — بدون نیاز به گواهی."
/>
</Cards>
@@ -0,0 +1,86 @@
---
title: Subscription
description: راه‌اندازی سرور اشتراک 3x-ui — قالب‌های base64/JSON/Clash، پورت‌ها و مسیرها، TLS، هدرهای پاسخ و قالب‌های سفارشی.
icon: Rss
---
یک **اشتراک** (subscription) یک URL واحد است که همه‌ی پیکربندی‌های یک کلاینت را
برمی‌گرداند. برنامه‌های کلاینت آن را به‌صورت دوره‌ای تازه‌سازی می‌کنند، بنابراین وقتی
یک ورودی را تغییر می‌دهید، کلاینت‌ها این تغییر را به‌صورت خودکار دریافت می‌کنند. سرور
اشتراک به‌عنوان یک سرور **جداگانه** از پنل اجرا می‌شود.
## فعال‌سازی و پیکربندی
سرور اشتراک به‌صورت **پیش‌فرض روشن** است (`subEnable`). آن را در تنظیمات اشتراک
پنل پیکربندی کنید:
| Setting | Default | Meaning |
| ------------- | ------- | --------------------------------------------------------------- |
| `subPort` | `2096` | پورت گوش‌دادن (جدا از پنل). |
| `subListen` | _(همه)_ | آدرس اتصال (bind). |
| `subPath` | `/sub/` | مسیر پایه برای URLهای خام اشتراک. |
| `subDomain` | _(هیچ)_ | میزبان عمومی؛ اگر تنظیم شود، سرور فقط به همان Host پاسخ می‌دهد. |
| `subCertFile` / `subKeyFile` | _(هیچ)_ | گواهی و کلید TLS — هنگام تنظیم، سرور **HTTPS** ارائه می‌دهد. |
| `subEncrypt` | `true` | بدنه‌ی خام اشتراک را با base64 رمزگذاری می‌کند. |
| `subUpdates` | `12` | بازه‌ی پیشنهادی تازه‌سازی (ساعت) که به کلاینت‌ها ارسال می‌شود. |
یک URL اشتراک به این شکل است:
```text
https://<sub-host>:<sub-port>/sub/<sub-id>
```
که در آن `<sub-id>` همان **Sub ID** کلاینت است.
همان Sub ID در چند قالب روی مسیرهای مختلف ارائه می‌شود — فهرست **Base64** در
`subPath` و پیکربندی **JSON** (Xray-json) در مسیر JSON. URLها را بسازید و هر دو
بدنه را اینجا پیش‌نمایش کنید:
<SubscriptionBuilder />
## قالب‌های خروجی
**قالب بر اساس مسیر انتخاب می‌شود** و هرکدام کلید فعال‌سازی مخصوص خود را دارند:
| Format | Path | Enabled by | Output |
| --------------------- | --------- | ---------------- | --------------------------------------------------- |
| **لینک‌های خام** | `/sub/` | همیشه (اگر روشن باشد) | فهرستی از لینک‌های `vless://`، `vmess://`، … (هنگام فعال‌بودن `subEncrypt` با base64 رمزگذاری می‌شود). |
| **JSON** | `/json/` | `subJsonEnable` | پیکربندی(های) کامل کلاینت Xray. |
| **Clash / Mihomo** | `/clash/` | `subClashEnable` | پروفایل YAML. |
فقط ورودی‌های فعالی که از **VLESS، VMess، Trojan، Shadowsocks یا Hysteria2**
استفاده می‌کنند در یک اشتراک ظاهر می‌شوند و بر اساس شاخص sub-sort آن‌ها مرتب می‌شوند.
درخواست `/sub/` همراه با هدر `Accept: text/html` (یا `?html=1`) به‌جای بدنه‌ی خام،
یک صفحه‌ی اطلاعات خوانا برای انسان برمی‌گرداند.
### Base64 vs JSON
بدنه‌ی **Base64** صرفاً همان لینک‌های اشتراک‌گذاری است که با خط جدید به هم پیوسته و
با standard-base64 رمزگذاری شده‌اند (با `subEncrypt` قابل تغییر است). بدنه‌ی **JSON**
هر کلاینت را در یک پیکربندی کامل کلاینت Xray می‌پیچد — یک اسکلت ثابت (ورودی‌های محلی
mixed/HTTP، DNS، مسیریابی، policy) به‌علاوه‌ی یک outbound از نوع `proxy` که به ورودی
اشاره می‌کند. 3x-ui **برای یک کلاینت یک شیء پیکربندی واحد و برای چند کلاینت یک آرایه**
تولید می‌کند، از فرم تخت `settings` در outbound استفاده می‌کند
(`address`/`port`/`id`، `level: 8`) و `sockopt` را از `streamSettings` حذف می‌کند.
## هدرهای پاسخ
اشتراک‌ها هدرهای استانداردی برمی‌گردانند که برنامه‌های سازگار آن‌ها را می‌خوانند:
- **`Subscription-Userinfo`** — `upload`، `download`، `total` (بایت؛ `total=0`
یعنی نامحدود) و `expire` (ثانیه‌های Unix).
- **`Profile-Update-Interval`** — بازه‌ی تازه‌سازی برحسب ساعت (`subUpdates`).
- **`Profile-Title`**، **`Support-Url`**، **`Profile-Web-Page-Url`**،
**`Announce`** — برندینگ اختیاری که برخی کلاینت‌ها نمایش می‌دهند.
## قالب‌های سفارشی صفحه
برای برندینگ صفحه‌ی HTML اشتراک، `subThemeDir` را به یک پوشه‌ی حاوی قالب سفارشیِ
صفحه‌ی اطلاعات اشاره دهید. توضیح (remark) هر کلاینت روی هر لینک کاملاً قابل
قالب‌بندی است — به [لینک‌های اشتراک‌گذاری ← متغیرهای remark](/docs/config/share-links#remark-template-variables) مراجعه کنید.
<Callout type="info">
سرور اشتراک را پشت TLS قرار دهید (با تنظیم `subCertFile`/`subKeyFile`، یا یک
[پروکسی معکوس](/docs/operations/reverse-proxy)) تا محتوای اشتراک در حین انتقال
افشا نشود.
</Callout>
+201
View File
@@ -0,0 +1,201 @@
---
title: انتقال‌ها و امنیت
description: هر انتقالی که 3x-ui ارائه می‌دهد — TCP، mKCP، WebSocket، gRPC، HTTPUpgrade، XHTTP، Hysteria — به‌همراه تنظیماتشان، و نیز مبهم‌سازی FinalMask، sockopt، TLS/REALITY، XTLS-Vision و رمزنگاری VLESS.
icon: Network
---
یک **انتقال** تعیین می‌کند که بسته‌ها چگونه میان کلاینت و سرور حمل شوند، یک
لایه **امنیتی** تعیین می‌کند که چگونه رمزنگاری و استتار شوند، و **FinalMask**
می‌تواند آنچه باقی مانده را مبهم کند. پنل تنها ترکیب‌های معتبر را ارائه می‌دهد؛ این
صفحه تنظیمات هر انتقال و قواعدی را که پنل اعمال می‌کند فهرست می‌کند.
## انتقال‌ها
انتقال (مقدار `network` مربوط به inbound) را در فرم inbound/outbound انتخاب کنید. هر
شبکه کلید تنظیمات خود را روی سیم می‌نویسد (`tcpSettings`، `kcpSettings`، …).
| انتقال | کلید تنظیمات | چه زمانی از آن استفاده کنید |
| --------------- | --------------------- | ---------------------------------------------------------------------- |
| **TCP (Raw)** | `tcpSettings` | کمترین سربار. پایه‌ای برای REALITY + XTLS-Vision و fallback‌ها؛ استتار اختیاری هدر HTTP/1.1. |
| **mKCP** | `kcpSettings` | پروتکل قابل‌اعتماد روی **UDP** — پهنای باند را با تأخیر کمتر روی لینک‌های پُرافت معاوضه می‌کند. هیچ TLS/REALITY حمل نمی‌کند. |
| **WebSocket** | `wsSettings` | از طریق CDN‌ها و پراکسی‌های معکوس HTTP کار می‌کند؛ بسیار سازگار است. |
| **gRPC** | `grpcSettings` | مبتنی بر HTTP/2؛ مالتی‌پلکس خوبی دارد و به‌خوبی از طریق Nginx پراکسی می‌شود. |
| **HTTPUpgrade** | `httpupgradeSettings` | `Upgrade` مربوط به HTTP/1.1 و سازگار با CDN؛ سبک‌تر از WebSocket کامل. |
| **XHTTP** | `xhttpSettings` | انتقال HTTP مدرن با مالتی‌پلکس جریانی؛ سازگار با CDN و توانمند برای REALITY. |
| **Hysteria** | `hysteriaSettings` | انتقال مبتنی بر QUIC — تنها برای پروتکل **Hysteria2**. |
<Callout type="info">
inbound‌های **WireGuard** و **Tunnel** (dokodemo-door) هیچ انتخابگر انتقالی
نمایش نمی‌دهند — جریان آن‌ها تنها security/sockopt را حمل می‌کند. پنل‌های قدیمی‌تر
یک انتقال خام **HTTP/2 (`http`)** نیز نمایش می‌دادند؛ این انتقال جای خود را به
**XHTTP** داده و دیگر قابل انتخاب نیست.
</Callout>
### TCP (Raw) — `tcpSettings`
| فیلد | پیش‌فرض | معنی |
| ------------------------------ | ------- | ----------------------------------------------------------------------- |
| `acceptProxyProtocol` | `false` | پذیرش پروتکل PROXY از یک پراکسی بالادست تا IP واقعی کلاینت حفظ شود. |
| `header.type` | `none` | `none`، یا `http` برای استتار HTTP/1.1. |
| `header.request` / `response` | — | هنگام `type: http`: متد، مسیر، نسخه و یک نگاشت هدر که یک تبادل HTTP معمولی را تقلید می‌کنند. |
### mKCP — `kcpSettings`
| فیلد | پیش‌فرض | معنی |
| ------------------ | ----------- | ---------------------------------------------------------------- |
| `mtu` | `1350` | بیشینه واحد انتقال، بر حسب بایت (576–1460). |
| `tti` | `20` | بازه زمانی انتقال، بر حسب میلی‌ثانیه (10–100). کمتر = پاسخگوتر، سربار بیشتر. |
| `uplinkCapacity` | `5` | بودجه پهنای باند آپلود، بر حسب **MB/s**. |
| `downlinkCapacity` | `20` | بودجه پهنای باند دانلود، بر حسب **MB/s**. |
| `cwndMultiplier` | `1` | ضریب پنجره ازدحام؛ برای فشار بیشتر روی لینک‌های خوب آن را بالا ببرید. |
| `maxSendingWindow` | `2097152` | کران بالای بسته‌های در حال پرواز. |
<Callout type="info">
mKCP نمی‌تواند TLS یا REALITY حمل کند. برای استتار آن، یک ماسک UDP از نوع
**FinalMask** اضافه کنید — ماسک `mkcp-legacy` همان مبهم‌سازی کلاسیک هدر را
بازتولید می‌کند که Xray قدیمی‌تر در `kcpSettings.header`/`seed` ذخیره می‌کرد
(آن فیلدها دیگر اینجا وجود ندارند).
</Callout>
### WebSocket — `wsSettings`
| فیلد | پیش‌فرض | معنی |
| --------------------- | ------- | ---------------------------------------------------------------- |
| `path` | `/` | مسیر درخواست — وقتی چند سرویس یک میزبان را به اشتراک می‌گذارند، بر اساس آن مسیریابی کنید. |
| `host` | _(none)_| بازنویسی هدر `Host` (پشت یک CDN مفید است). |
| `headers` | `{}` | هدرهای درخواست اضافی. |
| `heartbeatPeriod` | `0` | ثانیه‌های بین پینگ‌های keepalive؛ `0` آن‌ها را غیرفعال می‌کند. |
| `acceptProxyProtocol` | `false` | پذیرش پروتکل PROXY از یک بالادست. |
### gRPC — `grpcSettings`
| فیلد | پیش‌فرض | معنی |
| ------------- | ------- | --------------------------------------------------------- |
| `serviceName` | _(none)_| مسیر سرویس gRPC؛ مانند یک مسیر مخفی عمل می‌کند. |
| `authority` | _(none)_| بازنویسی شبه‌هدر `:authority`. |
| `multiMode` | `false` | مالتی‌پلکس چند جریان روی یک اتصال. |
### HTTPUpgrade — `httpupgradeSettings`
| فیلد | پیش‌فرض | معنی |
| --------------------- | ------- | --------------------------------------------- |
| `path` | `/` | مسیر درخواست. |
| `host` | _(none)_| بازنویسی هدر `Host`. |
| `headers` | `{}` | هدرهای درخواست اضافی. |
| `acceptProxyProtocol` | `false` | پذیرش پروتکل PROXY از یک بالادست. |
HTTPUpgrade یک `Upgrade` تک‌مرحله‌ای HTTP/1.1 بدون قاب‌بندی WebSocket است — هیچ
فیلد heartbeat ندارد.
### XHTTP — `xhttpSettings`
XHTTP (SplitHTTP) مجموعه فیلد بزرگی دارد؛ پنل پیش‌فرض‌های معقولی را پر می‌کند.
آن‌هایی که معمولاً سراغشان می‌روید:
| فیلد | پیش‌فرض | معنی |
| ---------------------- | ----------- | ---------------------------------------------------------------------- |
| `path` | `/` | مسیر درخواست. |
| `host` | _(none)_ | بازنویسی هدر `Host`. |
| `mode` | `auto` | `auto`، `packet-up`، `stream-up` یا `stream-one`. `packet-up` بیشترین سازگاری با CDN را دارد؛ `stream-*` تأخیر کمتری دارند. |
| `xPaddingBytes` | `100-1000` | بازه padding تصادفی که اندازه بسته‌ها را محو می‌کند. |
| `scMaxBufferedPosts` | `30` | بافر سمت سرور برای POST‌های آپلودشده. |
| `scStreamUpServerSecs` | `20-80` | پنجره stream-up سمت سرور (بازه با خط تیره). |
| `xmux` (`enableXmux`) | _(off)_ | مالتی‌پلکس اتصال — `maxConcurrency` `16-32`، `maxConnections` `6`، … برای همزمانی بالا روشن کنید. |
فیلدهای Session-ID (`sessionIDPlacement`، `sessionIDKey`، `sessionIDTable`،
`sessionIDLength`) و کلیدهای `scMin/MaxEachPostBytes` پیشرفته‌اند؛ آن‌ها را خالی
بگذارید مگر آنکه با یک بالادست مشخص هماهنگ می‌شوید.
### Hysteria — `hysteriaSettings`
تنها زمانی معتبر است که پروتکل **Hysteria2** باشد.
| فیلد | پیش‌فرض | معنی |
| ---------------- | ------- | ----------------------------------------------------------------------- |
| `version` | `2` | نسخه پروتکل Hysteria. |
| `auth` | _(none)_| رشته احراز هویت مشترک. |
| `udpIdleTimeout` | `60` | ثانیه (2–600) پیش از حذف نشست‌های بی‌کار UDP. |
| `masquerade` | — | استتار به‌عنوان یک سرور HTTP/3: `type` با مقدار `proxy`/`file`/`string` و `url`/`dir`/`content`، به‌علاوه `headers` و `statusCode`. |
## FinalMask — مبهم‌سازی لایه پایانی
**FinalMask** ترافیک را **پس از** لایه‌های انتقال و امنیت می‌پیچد، بنابراین می‌تواند
انتقال‌هایی را که TLS حمل نمی‌کنند (مانند mKCP) استتار کند یا پوسته‌ای دوم روی TLS
بیفزاید. ماسک‌ها برای هر جهت پیکربندی می‌شوند:
- **ماسک‌های TCP** — `fragment`، `sudoku`، `header-custom`.
- **ماسک‌های UDP** — `salamander`، `mkcp-legacy`، `header-custom`، `xdns`، `xicmp`،
`noise`، `sudoku`، `realm`. (`mkcp-legacy` همان مبهم‌سازی قدیمی هدر mKCP را
بازتولید می‌کند.)
- **پارامترهای QUIC** — کنترل ازدحام (`reno`، `bbr`، `brutal`، `force-brutal`)،
نرخ‌های آپلود/دانلود Brutal، `udpHop` (چرخاندن پورت QUIC در یک بازه برای دور زدن
مسدودسازی پورت)، و تنظیم پنجره دریافت.
FinalMask جایگزین مبهم‌سازی `header`/`seed` به‌ازای هر انتقال می‌شود که بیلدهای
قدیمی‌تر Xray نمایش می‌دادند.
## sockopt — گزینه‌های سطح پایین سوکت
`sockopt` در کنار هر انتقالی سوار می‌شود و سوکت زیرین را تنظیم می‌کند. مفیدترین
فیلدها:
| فیلد | پیش‌فرض | معنی |
| --------------------- | ------- | ---------------------------------------------------------------- |
| `tcpFastOpen` | `false` | فعال‌سازی TCP Fast Open. |
| `tcpcongestion` | `bbr` | کنترل ازدحام: `bbr`، `cubic` یا `reno`. |
| `tproxy` | `off` | حالت پراکسی شفاف: `off`، `redirect` یا `tproxy`. |
| `domainStrategy` | `AsIs` | نحوه تفکیک نشانی‌ها (`UseIP`، `ForceIPv4`، …). |
| `dialerProxy` | _(none)_| زنجیر کردن شماره‌گیری این outbound از طریق یک تگ outbound دیگر. |
| `interface` | _(none)_| اتصال به یک رابط شبکه مشخص. |
| `mark` | `0` | SO_MARK برای مسیریابی سیاستی (`0` = تنظیم‌نشده). |
فیلدهای عددی که روی `0` رها شوند روی سیم حذف می‌شوند تا Xray پیش‌فرض‌های سیستم‌عامل
را حفظ کند. ورودی‌های پیشرفته (`happyEyeballs`، `customSockopt[]`، تایمرهای
keepalive) برای موارد خاص در دسترس‌اند.
## امنیت
لایه امنیتی یکی از **`none`**، **`tls`** یا **`reality`** است، با این
قواعد واجد شرایط بودن:
| امنیت | انتقال‌های واجد شرایط | پروتکل‌های واجد شرایط |
| ----------- | -------------------------------------------- | --------------------------------------------------- |
| **TLS** | `tcp`، `ws`، `grpc`، `httpupgrade`، `xhttp` | VLESS، VMess، Trojan، Shadowsocks (Hysteria2 همیشه TLS است) |
| **REALITY** | `tcp`، `grpc`، `xhttp` | VLESS، Trojan |
mKCP و Hysteria لایه TLS/REALITY جداگانه‌ای نمی‌گیرند — mKCP به‌صورت متن ساده اجرا
می‌شود (با FinalMask استتارش کنید)، و Hysteria به‌طور ذاتی QUIC/TLS است. REALITY
سرور شما را به‌عنوان یک سایت واقعی TLS استتار می‌کند و به هیچ گواهی نیازی ندارد — به
[REALITY](/docs/config/reality) مراجعه کنید.
## جریان XTLS-Vision
جریان `xtls-rprx-vision` سریع و مقاوم در برابر DPI است. این جریان برای
**VLESS** در یکی از این دو حالت در دسترس است:
- انتقال، **TCP** خام با امنیت **TLS** یا **REALITY** باشد (XTLS-Vision
کلاسیک)، یا
- انتقال، **XHTTP** با رمزنگاری VLESS فعال باشد (به ادامه مراجعه کنید).
جریان را روی **کلاینت** VLESS تنظیم کنید، نه روی inbound. با Vision کلاسیک روی
TCP، پنل می‌تواند پس از آنکه یک کلاینت از جریان استفاده کرد، یک **Vision seed** نیز
ارائه دهد.
## رمزنگاری VLESS (ML-KEM)
‏VLESS از **رمزنگاری** پساکوانتومی (ML-KEM / `mlkem768x25519`) پشتیبانی می‌کند که در
`decryption` مربوط به inbound (سمت سرور) و `encryption` کلاینت‌ها (برای تولید
لینک) ذخیره می‌شود. وقتی فعال باشد، جریان Vision را روی XHTTP باز می‌کند. کلیدها
را از تنظیمات VLESS در پنل تولید کنید.
## رمزهای Shadowsocks
inbound‌های Shadowsocks هم از رمزهای کلاسیک و هم از **Shadowsocks-2022**
پشتیبانی می‌کنند (نام روش‌هایی که با `2022-blake3-` آغاز می‌شوند). بیشتر رمزها چندکاربره هستند؛
`2022-blake3-chacha20-poly1305` تک‌کاربره است.
<Callout type="info">
انتقال‌ها و امنیت باید در هر دو سر یکسان باشند. لینک اشتراک کلاینت آن‌ها را
کدگذاری می‌کند (`type=ws`، `security=reality`، `flow=xtls-rprx-vision`، …) —
هر لینکی را با [بازرس لینک اشتراک](/docs/config/share-links) رمزگشایی کنید.
</Callout>
+126
View File
@@ -0,0 +1,126 @@
---
title: نخستین ورود
description: مشخصات ورود تولیدشدهٔ 3x-ui را بیابید، به پنل دسترسی پیدا کنید، احراز هویت دومرحله‌ای را فعال کنید و پیش از در معرض قرار دادن هر چیزی، پنل را ایمن‌سازی کنید.
icon: KeyRound
---
پس از نصب، نخستین کار شما این است که وارد پنل شوید و **آن را ایمن کنید**، پیش از
آنکه چیز دیگری را در معرض دسترس قرار دهید.
## دسترسی به پنل
پنل در این نشانی ارائه می‌شود:
```text
http://<your-server-ip>:<port>/<web-base-path>
```
پورت پیش‌فرض **2053** و مسیر پایهٔ پیش‌فرض `/` است — اما نصب با اسکریپت، نام
کاربری، رمز عبور، **پورت** و مسیر پایهٔ وب را **به‌صورت تصادفی تولید می‌کند**،
پس مقادیر واقعی خود را بررسی کنید.
### یافتن مشخصات ورود
نصب با اسکریپت پس از پایان، خلاصه‌ای از مشخصات ورود را چاپ می‌کند و آن را در یک
فایل ویژهٔ root نیز می‌نویسد:
```bash title="/etc/x-ui/install-result.env (mode 600)"
XUI_USERNAME=...
XUI_PASSWORD=...
XUI_PANEL_PORT=...
XUI_WEB_BASE_PATH=...
XUI_ACCESS_URL=...
XUI_API_TOKEN=...
XUI_DB_TYPE=sqlite
```
اگر آن‌ها را از دست دادید، از ابزارهای مدیریتی استفاده کنید:
```bash
x-ui # menu → 11 (View Current Settings)
x-ui settings # or the one-shot form
```
برای **Docker**، مشخصات ورود تولیدشده را از لاگ‌های کانتینر بخوانید، یا دستور
`docker exec -it <container> x-ui setting -show` را اجرا کنید.
<Callout type="warn">
اگر پنل شما هنوز از مقادیر پیش‌فرض `admin` / `admin` استفاده می‌کند (پنل در این
حالت هشدار می‌دهد)، بی‌درنگ آن را تغییر دهید — پیش از ساختن هر inbound.
</Callout>
## تغییر مشخصات ورود، پورت و مسیر
یک پورت غیرپیش‌فرض و یک **مسیر پایهٔ وب** طولانی و تصادفی، یافتن پنل را بسیار
دشوارتر می‌کند. آن‌ها را از بخش **Panel Settings** در رابط کاربری، یا از منوی
`x-ui` تغییر دهید:
- **7 — Reset Username & Password** (با امکان غیرفعال‌سازی همزمان 2FA)
- **8 — Reset Web Base Path** (آن را تصادفی می‌کند)
- **10 — Change Port**
تغییر نام کاربری یا رمز عبور **همهٔ نشست‌های موجود را از سیستم خارج می‌کند** و
اگر احراز هویت دومرحله‌ای فعال بود، آن را غیرفعال می‌سازد.
## احراز هویت دومرحله‌ای (2FA)
‏3x-ui از احراز هویت دومرحله‌ای TOTP پشتیبانی می‌کند (سازگار با Google
Authenticator، Aegis و غیره). آن را در بخش **Panel Settings** فعال کنید — پس از
فعال‌سازی، صفحهٔ ورود علاوه بر رمز عبور، یک کد ۶ رقمی نیز درخواست می‌کند و
فعال کردن آن همه را وادار به ورود مجدد می‌کند. می‌توانید آن را از مرحلهٔ **Reset
Username & Password** در منو یا با دستور `x-ui setting -resetTwoFactor` غیرفعال
کنید.
## محافظت داخلی از ورود
- **محدودکنندهٔ حملهٔ جستجوی فراگیر:** پس از **۵** ورود ناموفق از یک IP/نام
کاربری یکسان در بازهٔ ۵ دقیقه، آن ترکیب برای **۱۵ دقیقه** مسدود می‌شود.
- **خطاهای عمومی:** صفحهٔ ورود هم برای مشخصات نادرست و هم برای کدهای 2FA نادرست،
پیام «wrong username or password» را نمایش می‌دهد، پس هیچ چیزی فاش نمی‌کند.
- **نشست‌ها** به مدت `sessionMaxAge` دقیقه (پیش‌فرض **۳۶۰** = ۶ ساعت) معتبرند و
هنگام تغییر مشخصات ورود باطل می‌شوند.
- **LDAP** را می‌توان به‌عنوان روش جایگزین احراز هویت در Panel Settings فعال کرد.
## چک‌لیست ضروری ایمن‌سازی
<Steps>
<Step>
### مشخصات ورود قوی و یکتا تعیین کنید
نام کاربری و رمز عبور تولیدشده (یا `admin/admin`) را با مقادیر قوی جایگزین کنید.
</Step>
<Step>
### از پورت غیرپیش‌فرض و مسیر پایهٔ تصادفی استفاده کنید
پنل را از `2053` جابه‌جا کنید و آن را زیر یک مسیر تصادفی و طولانی ارائه دهید.
</Step>
<Step>
### احراز هویت دومرحله‌ای را فعال کنید
‏2FA را فعال کنید تا یک رمز عبور لو رفته به‌تنهایی نتواند دسترسی بدهد.
</Step>
<Step>
### پنل را پشت TLS قرار دهید
از یک گواهی معتبر (از طریق مدیریت SSL در منوی `x-ui` یا یک reverse proxy)
استفاده کنید تا پنل تنها از طریق HTTPS در دسترس باشد.
</Step>
<Step>
### دسترسی را با فایروال محدود کنید
تنها پورت‌هایی را که واقعاً نیاز دارید باز کنید و محدود کردن دسترسی به پنل بر
اساس IP را در نظر بگیرید.
</Step>
</Steps>
<Callout type="info">
می‌خواهید پنل روی یک دامنهٔ تمیز با HTTPS خودکار باشد؟ به
[Reverse proxy](/docs/operations/reverse-proxy) مراجعه کنید. برای ایمن‌سازی
عمیق‌تر، به [Security](/docs/operations/security) مراجعه کنید.
</Callout>
+73
View File
@@ -0,0 +1,73 @@
---
title: آشنایی با 3x-ui
description: یک پنل تحت وب برای Xray-core — ورودی‌ها، پروتکل‌ها، کلاینت‌ها و اشتراک‌ها را به‌جای ویرایش دستی JSON، از مرورگر خود مدیریت کنید.
icon: Info
---
**3x-ui** یک پنل کنترل تحت وب است که روی
[Xray-core](https://github.com/XTLS/Xray-core)، همان موتور پروکسی که در واقع
ترافیک شما را جابه‌جا می‌کند، قرار می‌گیرد. به‌جای نوشتن و بارگذاری مجدد پیکربندی
JSON ‏Xray به‌صورت دستی، همه‌چیز — ورودی‌ها، پروتکل‌ها، کلاینت‌ها، گواهی‌ها،
اشتراک‌ها — را از یک داشبورد مرورگری مدیریت می‌کنید.
## اجزا چگونه کنار هم کار می‌کنند
<Mermaid
chart={`
flowchart LR
Admin["Admin browser"] -->|HTTPS panel| Panel["3x-ui panel"]
Panel -->|writes config, reloads| Xray["Xray-core"]
Panel --- DB[("SQLite or PostgreSQL")]
Clients["Client apps"] -->|VLESS / VMess / Trojan / ...| Xray
Xray -->|proxied traffic| Internet["Internet"]
`}
/>
- **پنل** لایهٔ مدیریت است: پیکربندی شما را در یک پایگاه‌داده ذخیره می‌کند،
داشبورد را رندر می‌کند، یک REST API ارائه می‌دهد و پیکربندی زندهٔ Xray را
می‌نویسد.
- **Xray-core** لایهٔ داده است: اتصالات کلاینت را روی **ورودی‌های** شما
پایان می‌دهد و ترافیک را به مقصدش هدایت می‌کند.
- **اپلیکیشن‌های کلاینت** (مانند v2rayNG، Clash/Mihomo، Hiddify و دیگران) با
استفاده از یک لینک اشتراک‌گذاری یا اشتراکی که پنل برای هر کلاینت تولید می‌کند
متصل می‌شوند.
## چه چیزی در اختیار شما می‌گذارد
- داشبوردی برای **ورودی‌ها** در تمام پروتکل‌های اصلی — VLESS، VMess،
Trojan، Shadowsocks، WireGuard، Hysteria2، SOCKS، HTTP و Dokodemo-door.
- پشتیبانی درجه‌یک از **REALITY** و **XTLS-Vision** برای ترانسپورت‌های مخفی
و سریع.
- سهمیه‌های ترافیک **به‌ازای هر کلاینت**، تاریخ‌های انقضا، محدودیت‌های IP،
وضعیت آنلاین و لینک‌های اشتراک‌گذاری / کدهای QR با یک کلیک.
- **اشتراک‌ها** در قالب‌های VLESS، Clash/Mihomo و JSON.
- ابزارهای عملیاتی: مدیریت **چندنودی**، یک **ربات Telegram**، پشتیبان‌گیری،
محدودسازی IP مبتنی بر Fail2ban و یک REST API مستندشده.
## پشت صحنه
| لایه | فناوری |
| ------------ | -------------------------------------------- |
| بک‌اند | Go با فریم‌ورک وب Gin |
| فرانت‌اند | TypeScript / React |
| پایگاه‌داده | SQLite (پیش‌فرض) یا PostgreSQL |
| موتور پروکسی | Xray-core (همراه و مدیریت‌شده توسط پنل) |
پایگاه‌دادهٔ پیش‌فرض SQLite در مسیر `/etc/x-ui/x-ui.db` قرار دارد و پنل به‌صورت
پیش‌فرض روی پورت **2053** گوش می‌دهد. هر دو قابل پیکربندی هستند — به
[نخستین ورود](/docs/guide/first-login) و مرجع متغیرهای محیطی مراجعه کنید.
## برای چه کسانی است
3x-ui برای هر کسی که سرور Xray خودش را اجرا می‌کند طراحی شده است: از یک
VPS شخصی منفرد تا اپراتورهایی که نودها و کلاینت‌های فراوانی را مدیریت می‌کنند. اگر
قدرت Xray-core را می‌خواهید بدون اینکه در فایل‌های پیکربندی JSON زندگی کنید، این
برای شماست.
<Callout type="info">
3x-ui یک فورک ارتقایافته از پروژهٔ اصلی X-UI است که پشتیبانی گسترده‌تری از
پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت
چندنودی و بسیاری از قابلیت‌های راحتی‌بخش را اضافه می‌کند.
</Callout>
آماده‌اید نصب کنید؟ به [نصب](/docs/guide/installation) ادامه دهید.
+150
View File
@@ -0,0 +1,150 @@
---
title: نصب
description: نصب 3x-ui با اسکریپت رسمی (نسخهٔ پایدار، نسخهٔ مشخص یا dev-latest)، نصب خودکار/cloud-init یا Docker — و انتخاب میان SQLite و PostgreSQL.
icon: Download
---
‏3x-ui روی طیف گسترده‌ای از توزیع‌های Linux اجرا می‌شود — Ubuntu، Debian، Armbian،
Fedora، CentOS، RHEL، AlmaLinux، Rocky Linux، Oracle Linux، Amazon Linux،
Virtuozzo، Arch، Manjaro، openSUSE (Tumbleweed/Leap)، Alpine — و همچنین Windows،
روی معماری‌های `amd64`، `386`، `arm64`، `armv7`، `armv6`، `armv5` و `s390x`.
<Callout type="warn">
نصب‌کنندهٔ اسکریپتی را به‌صورت **root** (یا با `sudo`) اجرا کنید. این اسکریپت یک
سرویس نصب می‌کند، دستور مدیریتی `x-ui` را راه‌اندازی می‌کند و پنل را در زمان
بوت فعال می‌سازد.
</Callout>
<Tabs items={['Script', 'Docker', 'Manual']}>
<Tab value="Script">
اسکریپت رسمی مسیر توصیه‌شده است. این اسکریپت در طول نصب یک نام کاربری، رمز عبور و
مسیر دسترسی (مسیر پایهٔ وب) **تصادفی** تولید می‌کند، سرویس را راه‌اندازی می‌کند و
دستور مدیریتی `x-ui` را نصب می‌کند.
```bash title="latest stable"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
برای نصب یک **نسخهٔ مشخص**، تگ آن را در انتها اضافه کنید:
```bash title="pinned version"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) v3.4.0
```
برای نصب نسخهٔ **dev** غلتان (آخرین پیش‌انتشار به‌ازای هر کامیت از شاخهٔ `main`
— نه یک نسخهٔ پایدار) عبارت `dev-latest` را پاس دهید:
```bash title="rolling dev build"
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh) dev-latest
```
پس از پایان نصب، مشخصات ورود چاپ‌شده را یادداشت کنید و دستور `x-ui` را اجرا کنید تا
[منوی مدیریت](/docs/guide/update-uninstall#the-x-ui-management-menu) باز شود، سپس
به [نخستین ورود](/docs/guide/first-login) ادامه دهید.
</Tab>
<Tab value="Docker">
پیکربندی پیش‌فرض Compose از SQLite استفاده می‌کند. مخزن را کلون کنید (یا فایل‌های
`docker-compose.yml` و `Dockerfile` آن را کپی کنید) و آن را اجرا کنید:
```bash
docker compose up -d
```
برای اجرا با سرویس **PostgreSQL** همراه، دو خط `XUI_DB_*` را در
`docker-compose.yml` از حالت کامنت خارج کنید و با پروفایل مربوطه اجرا کنید:
```bash
docker compose --profile postgres up -d
```
ترجیح می‌دهید از ایمیج از‌پیش‌ساخته استفاده کنید؟ این ایمیج روی GitHub Container Registry
منتشر شده است. این ایمیج Fail2ban را به‌همراه دارد (برای [محدودیت‌های IP](/docs/operations/security))
که با `iptables` مسدودسازی انجام می‌دهد و بنابراین به `NET_ADMIN` (و `NET_RAW` برای IPv6)
نیاز دارد — در غیر این صورت مسدودسازی‌ها فقط ثبت می‌شوند ولی هرگز اعمال نمی‌شوند:
```bash title="docker run"
docker run -d \
--cap-add=NET_ADMIN \
--cap-add=NET_RAW \
-e XUI_ENABLE_FAIL2BAN=true \
-v $PWD/db/:/etc/x-ui/ \
-v $PWD/cert/:/root/cert/ \
--network=host \
--restart=unless-stopped \
--name 3x-ui \
ghcr.io/mhsanaei/3x-ui:latest
```
والیوم `db/` پایگاه‌دادهٔ SQLite (`/etc/x-ui/x-ui.db`) را نگه می‌دارد و `cert/`
گواهی‌های TLS را، بنابراین داده‌های شما در ارتقاها حفظ می‌شوند.
</Tab>
<Tab value="Manual">
برای کاربران پیشرفته، یک آرشیو انتشار متناسب با معماری خود را از
[صفحهٔ releases](https://github.com/MHSanaei/3x-ui/releases) دانلود کنید، آن را
استخراج کنید و باینری را به‌عنوان یک سرویس systemd اجرا کنید. اسکریپت نصب دقیقاً
همین مراحل را خودکار می‌کند، بنابراین مگر اینکه دلیل خاصی برای نصب دستی داشته
باشید، روش اسکریپتی ترجیح داده می‌شود.
</Tab>
</Tabs>
## دستور نصب خود را بسازید
دستور را متناسب با تنظیمات خود سفارشی کنید:
<InstallCommandBuilder />
## انتخاب یک پایگاه‌داده
شما بک‌اند ذخیره‌سازی را در زمان نصب انتخاب می‌کنید:
- **SQLite** (پیش‌فرض) — یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به هیچ تنظیماتی.
- **PostgreSQL** — برای تعداد کلاینت بالا یا پیکربندی‌های چندنودی. نصب‌کننده
می‌تواند آن را به‌صورت محلی نصب کند یا از یک DSN که شما ارائه می‌دهید استفاده کند.
برای جزئیات و مهاجرت SQLite→PostgreSQL به [پایگاه‌داده](/docs/reference/database)
مراجعه کنید.
## نصب خودکار / cloud-init
نصب‌کننده برای خودکارسازی به‌صورت **غیرتعاملی** نیز اجرا می‌شود.
`XUI_NONINTERACTIVE=1` را تنظیم کنید (یا بدون TTY اجرا کنید) تا نصب به‌صورت
سرتاسری و بدون هیچ پرسشی انجام شود، مشخصات تصادفی تولید کند و آن‌ها را در
`/etc/x-ui/install-result.env` بنویسد:
```bash
XUI_NONINTERACTIVE=1 bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
```
دایرکتوری [`deploy/`](https://github.com/MHSanaei/3x-ui/tree/main/deploy) در مخزن
یک user-data آمادهٔ **cloud-init** برای نصب‌های خودکار روی هر ابری (Hetzner، AWS،
DigitalOcean، Vultr، GCP، Azure، Oracle) دارد.
## گام‌های بعدی
<Cards>
<Card
title="نخستین ورود"
href="/docs/guide/first-login"
description="به پنل دسترسی پیدا کنید و آن را ایمن کنید."
/>
<Card
title="به‌روزرسانی و حذف نصب"
href="/docs/guide/update-uninstall"
description="منوی x-ui، به‌روزرسانی‌ها و حذف."
/>
<Card
title="REALITY"
href="/docs/config/reality"
description="نخستین ورودی مخفی خود را پیکربندی کنید."
/>
</Cards>
+5
View File
@@ -0,0 +1,5 @@
{
"title": "شروع به کار",
"icon": "Rocket",
"pages": ["index", "installation", "first-login", "update-uninstall"]
}
@@ -0,0 +1,99 @@
---
title: به‌روزرسانی و حذف
description: مدیریت 3x-ui با منوی x-ui و خط فرمان — به‌روزرسانی (پایدار، dev یا نسخه‌های قدیمی)، تغییر تنظیمات و حذف تمیز و کامل.
icon: RefreshCw
---
پس از نصب با اسکریپت، دستور `x-ui` مرکز کنترل شماست. آن را بدون هیچ آرگومانی اجرا
کنید تا منوی تعاملی باز شود، یا یک زیردستور به آن بدهید تا یک عملیات تک‌مرحله‌ای انجام شود.
```bash
x-ui
```
## منوی مدیریت `x-ui`
منو (آیتم‌های `0`–`28`) وضعیت پنل/Xray را در بالا نشان می‌دهد و سپس:
| # | آیتم | کاری که انجام می‌دهد |
| ----- | -------------------------------------- | --------------------------------------------------------- |
| 1 | Install | (دوباره) نصب از روی اسکریپت راه دور |
| 2 | Update | به‌روزرسانی به آخرین نسخهٔ **پایدار** |
| 3 | Update to Dev Channel (latest commit) | به‌روزرسانی به بیلد غلتان `dev-latest` |
| 4 | Update Menu | به‌روزرسانی فقط اسکریپت منوی `x-ui` |
| 5 | Legacy Version | نصب یک نسخهٔ قدیمی مشخص (تگ را می‌پرسد) |
| 6 | Uninstall | حذف 3x-ui (در ادامه ببینید) |
| 7 | Reset Username & Password | تنظیم مشخصات جدید؛ اختیاراً غیرفعال‌کردن 2FA |
| 8 | Reset Web Base Path | تصادفی‌کردن مسیر پایهٔ وب |
| 9 | Reset Settings | بازنشانی تنظیمات پنل (حساب شما حفظ می‌شود) |
| 10 | Change Port | تغییر پورت پنل |
| 11 | View Current Settings | نمایش نام کاربری، پورت، مسیر پایهٔ وب، مسیرهای گواهی |
| 1214 | Start / Stop / Restart | کنترل سرویس پنل |
| 15 | Restart Xray | بارگذاری مجدد فقط Xray-core |
| 16 | Check Status | وضعیت سرویس |
| 17 | Logs Management | مشاهدهٔ لاگ‌های دیباگ / پاک‌سازی لاگ‌ها |
| 1819 | Enable / Disable Autostart | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت |
| 20 | SSL Certificate Management | Let's Encrypt (دامنه یا IP)، مسیرهای سفارشی، تمدید/ابطال |
| 21 | Cloudflare SSL Certificate | گواهی wildcard از طریق DNS-01 با Cloudflare |
| 22 | IP Limit Management | محدودیت IP به‌ازای هر کلاینت مبتنی بر Fail2ban |
| 23 | Firewall Management | نصب `ufw` و قواعد پورت |
| 24 | SSH Port Forwarding Management | اتصال پنل به localhost و تونل‌زدن روی SSH |
| 25 | PostgreSQL Management | نصب/مهاجرت/مدیریت PostgreSQL |
| 26 | Enable BBR | فعال/غیرفعال‌کردن sysctl کنترل ازدحام BBR |
| 27 | Update Geo Files | به‌روزرسانی دادهٔ geoip/geosite (Loyalsoldier، IR، RU) |
| 28 | Speedtest by Ookla | اجرای تست سرعت Ookla |
| 0 | Exit | — |
برخی از این موارد صفحهٔ مخصوص خود را دارند: [گواهی‌های SSL](/docs/config/ssl-certificates)
(آیتم‌های 2021)، [امنیت](/docs/operations/security) (محدودیت IP، فایروال)،
[پروکسی معکوس](/docs/operations/reverse-proxy) و [تنظیمات پنل](/docs/config/panel)
(TLS)، و [پایگاه‌داده](/docs/reference/database) (PostgreSQL).
## زیردستورهای خط فرمان
برای اسکریپت‌ها و اقدام‌های سریع، `x-ui` یک زیردستور را هم مستقیماً می‌پذیرد:
| دستور | عملیات |
| -------------------------- | --------------------------------------------------- |
| `x-ui start` / `stop` / `restart` | کنترل سرویس |
| `x-ui restart-xray` | بارگذاری مجدد فقط Xray-core |
| `x-ui status` | نمایش وضعیت |
| `x-ui settings` | نمایش تنظیمات فعلی |
| `x-ui enable` / `disable` | فعال/غیرفعال‌کردن اجرای خودکار در زمان بوت |
| `x-ui log` | دنبال‌کردن لاگ دیباگ |
| `x-ui banlog` | نمایش لاگ مسدودسازی Fail2ban |
| `x-ui update` | به‌روزرسانی به آخرین نسخهٔ پایدار |
| `x-ui update-dev` | به‌روزرسانی به بیلد غلتان `dev-latest` |
| `x-ui legacy` | نصب یک نسخهٔ قدیمی مشخص (می‌پرسد) |
| `x-ui update-all-geofiles` | به‌روزرسانی همهٔ فایل‌های geo و راه‌اندازی مجدد در صورت تغییر |
| `x-ui migrate-db --dsn …` | مهاجرت SQLite ← PostgreSQL (نگاه کنید به [پایگاه‌داده](/docs/reference/database)) |
| `x-ui install` / `uninstall` | نصب / حذف |
## به‌روزرسانی
- **پایدار:** گزینهٔ منوی **۲** یا `x-ui update`. اجرای دوبارهٔ اسکریپت نصب هم
در همان محل به‌روزرسانی می‌کند.
- **کانال dev:** گزینهٔ منوی **۳** یا `x-ui update-dev` — بیلد غلتان
`dev-latest` به‌ازای هر کامیت (نه یک نسخهٔ پایدار).
- **یک نسخهٔ قدیمی مشخص:** گزینهٔ منوی **۵** (Legacy Version).
به‌روزرسانی، پایگاه‌داده و تنظیمات شما را حفظ می‌کند. پیش از یک جهش نسخهٔ اصلی، یک
[پشتیبان](/docs/operations/backup-restore) بگیرید.
<Callout type="info">
کاربران Docker به شیوهٔ دیگری به‌روزرسانی می‌کنند — به‌جای استفاده از دستورهای
به‌روزرسانی `x-ui`، ایمیج جدید را pull کرده و کانتینر را از نو بسازید
(`docker compose pull && docker compose up -d`).
</Callout>
## حذف
گزینهٔ منوی **۶** یا `x-ui uninstall`. سرویس را متوقف و غیرفعال می‌کند، یونیت سرویس
را حذف می‌کند و `/etc/x-ui/` و پوشهٔ نصب را پاک می‌کند. اگر پنل از یک PostgreSQL
نصب‌شده به‌صورت محلی استفاده می‌کرده، پیشنهاد می‌دهد آن را هم پاک‌سازی کند (یک تأیید
جداگانه و برگشت‌ناپذیر).
<Callout type="warn">
حذف، پایگاه‌داده (`/etc/x-ui/x-ui.db`) و پیکربندی شما را پاک می‌کند. اگر ممکن است
بعداً به آن نیاز داشته باشید، ابتدا [پشتیبان بگیرید](/docs/operations/backup-restore).
</Callout>
@@ -0,0 +1,64 @@
---
title: مشارکت
description: چگونه در توسعه 3x-ui مشارکت کنید و این مستندات را ترجمه کنید.
icon: GitPullRequestArrow
---
3x-ui یک پروژه جامعه‌محور است. مشارکت در پنل و در این مستندات با آغوش باز پذیرفته
می‌شود.
## حمایت از توسعه‌دهنده
3x-ui رایگان و متن‌باز است و به‌صورت عمومی ساخته و نگهداری می‌شود. اگر برایتان
مفید بوده است، حمایت از ادامه توسعه را در نظر بگیرید:
- در [donate.sanaei.dev](https://donate.sanaei.dev/) **کمک مالی** کنید — این صفحه
**اهداف و سقف‌های** جاری تأمین مالی را که می‌توانید در رسیدن به آن‌ها کمک کنید نشان می‌دهد.
- به [مخزن](https://github.com/MHSanaei/3x-ui) **ستاره** بدهید و پروژه را به اشتراک
بگذارید.
- به کانال Telegram یعنی [@XrayUI](https://t.me/XrayUI) **بپیوندید** تا اخبار را
دنبال کنید و به دیگران کمک کنید.
## مشارکت در 3x-ui
- فایل `CONTRIBUTING.md` پروژه را در
[مخزن](https://github.com/MHSanaei/3x-ui) بخوانید.
- برای باگ‌ها و درخواست‌های امکانات جدید، با گام‌های بازتولید روشن، issue باز کنید.
- از Conventional Commits استفاده کنید و pull requestها را متمرکز نگه دارید.
## ترجمه مستندات
این سایت برای ترجمه ساخته شده است. محتوا در مسیر `content/docs/<locale>/`
قرار دارد (`en`، `fa`، `ru`، `zh`) و صفحات ترجمه‌نشده **به انگلیسی بازمی‌گردند**، بنابراین
می‌توانید به‌صورت تدریجی ترجمه کنید.
<Steps>
<Step>
### کپی کردن یک صفحه
یک صفحه را از `content/docs/en/...` به همان مسیر زیر زبان خودتان کپی کنید، برای مثال
`content/docs/fa/guide/installation.mdx`.
</Step>
<Step>
### فقط متن را ترجمه کنید
متن اصلی و `title`/`description` در frontmatter را ترجمه کنید. کد، دستورات،
نام متغیرهای محیطی، نام پروتکل‌ها یا لینک‌های اشتراک‌گذاری را ترجمه **نکنید**.
</Step>
<Step>
### به جهت متن توجه کنید
فارسی (`fa`) از راست به چپ نمایش داده می‌شود. بلوک‌های کد و لینک‌ها را از چپ به راست
نگه دارید (طرح‌بندی این مورد را به‌طور خودکار مدیریت می‌کند) و صفحه را در هر دو جهت بررسی کنید.
</Step>
</Steps>
<Callout type="info">
نبودن یک صفحه در زبان شما اشکالی ندارد — به‌جای خطای 404 به انگلیسی بازمی‌گردد.
ابتدا صفحات با بیشترین بازدید را ترجمه کنید (نصب، نخستین ورود،
REALITY).
</Callout>
+47
View File
@@ -0,0 +1,47 @@
---
title: سؤالات متداول
description: پرسش‌های پرتکرار درباره 3x-ui — مجوز، سیستم‌های پشتیبانی‌شده، پایگاه‌های داده و کلاینت‌ها.
icon: CircleQuestionMark
---
## آیا 3x-ui رایگان و متن‌باز است؟
بله. 3x-ui تحت مجوز GPL-3.0 متن‌باز است. کد منبع آن روی
[GitHub](https://github.com/MHSanaei/3x-ui) در دسترس است.
## روی چه سیستم‌هایی اجرا می‌شود؟
روی بیشتر توزیع‌های اصلی Linux (Ubuntu، Debian، CentOS/RHEL و مشتقات آن‌ها،
Fedora، Arch، Alpine و موارد دیگر) روی معماری‌های `amd64`، `arm64` و دیگر معماری‌ها.
همچنین به‌صورت یک کانتینر Docker اجرا می‌شود. به [نصب](/docs/guide/installation) مراجعه کنید.
## SQLite یا PostgreSQL؟
SQLite گزینه پیش‌فرض است و برای بیشتر استقرارها مناسب است. PostgreSQL برای
راه‌اندازی‌های بزرگ‌تر از طریق `XUI_DB_TYPE=postgres` و `XUI_DB_DSN` در دسترس است — به
[متغیرهای محیطی](/docs/reference/env-vars) مراجعه کنید.
## کدام اپلیکیشن‌های کلاینت با آن کار می‌کنند؟
هر کلاینت سازگار با Xray — برای مثال v2rayNG، Hiddify و Clash/Mihomo.
لینک اشتراک‌گذاری یا کد QR یک کلاینت را وارد کنید، یا از
[سابسکریپشن](/docs/config/subscription) استفاده کنید.
## 3x-ui چه تفاوتی با x-ui دارد؟
3x-ui یک فورک ارتقایافته از پروژه اصلی X-UI است. این پروژه پشتیبانی گسترده‌تری از
پروتکل‌ها، پایداری بهبودیافته، حسابداری ترافیک به‌ازای هر کلاینت، مدیریت چندنودی،
یک رابط کاربری ۱۳ زبانه و بسیاری از امکانات رفاهی را اضافه می‌کند.
## چگونه به‌روزرسانی کنم؟
اسکریپت نصب را دوباره اجرا کنید (به‌صورت درجا به‌روزرسانی می‌شود)، یا ایمیج جدید Docker را دریافت کنید.
به [نصب](/docs/guide/installation) و
[صفحه نسخه‌ها](https://github.com/MHSanaei/3x-ui/releases) مراجعه کنید.
## از کجا می‌توانم کمک بگیرم؟
به کانال رسمی Telegram با نشانی [@XrayUI](https://t.me/XrayUI) برای
اطلاعیه‌ها و پشتیبانی انجمن بپیوندید، یا یک ایشو روی
[GitHub](https://github.com/MHSanaei/3x-ui/issues) باز کنید. برای مشکلات رایج، با
[عیب‌یابی](/docs/help/troubleshooting) شروع کنید.
+5
View File
@@ -0,0 +1,5 @@
{
"title": "راهنما",
"icon": "LifeBuoy",
"pages": ["troubleshooting", "faq", "migration", "contributing"]
}
+51
View File
@@ -0,0 +1,51 @@
---
title: مهاجرت
description: مهاجرت به 3x-ui از x-ui، بین سرورها یا بین نسخه‌های 3x-ui.
icon: ArrowRightLeft
---
## بین سرورها
انتقال به سرور جدید در واقع یک جابه‌جایی پایگاه‌داده است:
<Steps>
<Step>
### از سرور قدیمی نسخه پشتیبان بگیرید
از پایگاه‌داده (به‌صورت پیش‌فرض `/etc/x-ui/x-ui.db`) و گواهی‌نامه‌های خود یک کپی تهیه کنید.
[پشتیبان‌گیری و بازیابی](/docs/operations/backup-restore) را ببینید.
</Step>
<Step>
### 3x-ui را روی سرور جدید نصب کنید
از همان روش نصب و یک نسخهٔ سازگار استفاده کنید.
[نصب](/docs/guide/installation) را ببینید.
</Step>
<Step>
### پایگاه‌داده را بازیابی کنید
پنل را متوقف کنید، پایگاه‌داده را در جای خود قرار دهید، گواهی‌نامه‌ها را بازیابی کرده و پنل را راه‌اندازی کنید. هر تنظیم وابسته به IP یا دامنه را به‌روزرسانی کنید.
</Step>
</Steps>
## بین نسخه‌های 3x-ui
در محدودهٔ یک backend یکسان، ارتقا معمولاً تنها به اجرای دوبارهٔ نصب‌کننده یا
کشیدن یک image جدید خلاصه می‌شود — پنل خودش پایگاه‌داده‌اش را مهاجرت می‌دهد. هنگام تغییر بین نسخه‌های **اصلی**،
ابتدا [یادداشت‌های انتشار](https://github.com/MHSanaei/3x-ui/releases)
را بخوانید و یک نسخهٔ پشتیبان تهیه کنید.
## از x-ui
وارد کردن مستقیم پایگاه‌دادهٔ یک پنل قدیمی x-ui به 3x-ui **پشتیبانی نمی‌شود** —
چون ساختار schema آن‌ها متفاوت است. 3x-ui را از نو نصب کنید و inboundها/کلاینت‌ها را
دوباره بسازید و در همین حین لینک‌های اشتراک‌گذاری را از پنل قدیمی خروجی بگیرید.
<Callout type="warn">
پیش از هر مهاجرتی همیشه یک نسخهٔ پشتیبان تهیه کنید و سرور قدیمی را تا زمانی که
از درستی عملکرد سرور جدید مطمئن نشده‌اید، روشن نگه دارید.
</Callout>
@@ -0,0 +1,42 @@
---
title: عیب‌یابی
description: رفع مشکلات رایج 3x-ui — اجرا نشدن پنل، خطاهای 502، مشکلات گواهی و کلاینت‌هایی که نمی‌توانند متصل شوند.
icon: Wrench
---
فهرستی برای رسیدگی به رایج‌ترین مشکلات. هرگاه مطمئن نبودید، سطح لاگ را بالا ببرید
(`XUI_LOG_LEVEL=debug`) و لاگ‌های پنل و Xray را بررسی کنید.
## پنل اجرا نمی‌شود
- وضعیت سرویس و لاگ‌ها را بررسی کنید (منوی `x-ui` ← وضعیت/لاگ‌ها).
- مطمئن شوید که **پورت پنل از قبل توسط سرویس دیگری اشغال نشده** باشد.
- بررسی کنید که مسیر دیتابیس قابل نوشتن باشد (پیش‌فرض `/etc/x-ui/x-ui.db`).
## خطای 502 / در دسترس نبودن پنل پشت یک پروکسی
- مطمئن شوید که پنل واقعاً روی پورت upstream در حال شنود است (مثلاً `2053`).
- اطمینان حاصل کنید که [پروکسی معکوس](/docs/operations/reverse-proxy) شما هدرهای
ارتقای WebSocket را عبور می‌دهد و به پورت درست و **مسیر پایه وب** صحیح اشاره می‌کند.
- بررسی کنید که فایروال اتصال پروکسی ← پنل را مسدود نکرده باشد.
## مشکلات گواهی
- پیش از صدور گواهی، DNS دامنه باید به سرور اشاره کند.
- پورت‌های 80/443 باید برای اعتبارسنجی HTTP/TLS در دسترس باشند (یا از اعتبارسنجی DNS استفاده کنید).
- برای REALITY به یاد داشته باشید که **به هیچ گواهی نیازی ندارد** — مشکل معمولاً یک
`dest`/SNI نادرست است (به [نکات کلیدی REALITY](/docs/config/reality) مراجعه کنید).
## یک کلاینت نمی‌تواند متصل شود
- لینک کلاینت را با
[بازرس لینک اشتراک](/docs/config/share-links) رمزگشایی کنید و تک‌تک پارامترها را تأیید کنید.
- بررسی کنید که **transport و security در دو طرف مطابقت داشته باشند**.
- مطمئن شوید که کلاینت به **محدودیت ترافیک، انقضا یا IP** خود نرسیده باشد.
- اطمینان حاصل کنید که پورت inbound در فایروال باز است.
<Callout type="info">
همچنان به مشکل خورده‌اید؟ در میان
[مسائل GitHub](https://github.com/MHSanaei/3x-ui/issues) جست‌وجو کنید — احتمالاً
علامت مشکل شما قبلاً دیده شده است.
</Callout>
+54
View File
@@ -0,0 +1,54 @@
---
title: مستندات 3x-ui
description: مستندات رسمی 3x-ui — یک پنل وب پیشرفته برای مدیریت سرورهای Xray-core، پروکسی‌ها، کلاینت‌ها و سابسکریپشن‌ها.
icon: House
---
**3x-ui** یک پنل وب متن‌باز برای استقرار و مدیریت سرورهای
[Xray-core](https://github.com/XTLS/Xray-core) است. این پنل یک داشبورد مدرن برای
اینباندها، پروتکل‌ها، کلاینت‌ها، حسابداری ترافیک، سابسکریپشن‌ها و موارد دیگر در
اختیار شما می‌گذارد — بدون نیاز به ویرایش دستی JSON مربوط به Xray از طریق خط فرمان.
این سایت، مستندات رسمی و مجموعه‌ای از **ابزارهای تعاملی و درون‌مرورگری**
(تولیدکننده‌های پیکربندی) است که کاملاً روی دستگاه شما اجرا می‌شوند — هیچ داده‌ای
هرگز از صفحه خارج نمی‌شود.
## از اینجا شروع کنید
<Cards>
<Card
title="3x-ui چیست؟"
href="/docs/guide"
description="نمای کلی: Xray-core، پنل، و اینکه برای چه کسانی مناسب است."
/>
<Card
title="نصب"
href="/docs/guide/installation"
description="نصب از طریق اسکریپت، Docker یا به‌صورت دستی."
/>
<Card
title="نخستین ورود"
href="/docs/guide/first-login"
description="به پنل دسترسی پیدا کنید و پیش از هر کار دیگری آن را ایمن‌سازی کنید."
/>
<Card
title="REALITY"
href="/docs/config/reality"
description="راه‌اندازی VLESS + REALITY همراه با XTLS-Vision."
/>
</Cards>
## ویژگی‌های شاخص
- **همه پروتکل‌های اصلی** — VLESS، VMess، Trojan، Shadowsocks، WireGuard،
Hysteria2، SOCKS، HTTP و Dokodemo-door.
- **REALITY و XTLS-Vision** — ترنسپورت‌های مدرن و مقاوم در برابر سانسور.
- **کنترل‌های اختصاصی هر کلاینت** — سهمیه ترافیک، تاریخ انقضا، محدودیت IP، لینک‌های
اشتراک‌گذاری و کدهای QR.
- **سابسکریپشن‌ها** — قالب‌های VLESS، Clash/Mihomo و JSON.
- **عملیات** — مدیریت چندنودی، ربات Telegram، پشتیبان‌گیری و یک REST API.
<Callout type="info">
با Xray تازه آشنا شده‌اید؟ ابتدا [3x-ui چیست؟](/docs/guide) را بخوانید — توضیح می‌دهد که پنل، Xray-core و
اپلیکیشن‌های کلاینت شما چگونه در کنار هم کار می‌کنند.
</Callout>
+3
View File
@@ -0,0 +1,3 @@
{
"pages": ["index", "guide", "config", "operations", "reference", "help"]
}
@@ -0,0 +1,57 @@
---
title: پشتیبان‌گیری و بازیابی
description: از پایگاه‌داده و گواهی‌های 3x-ui خود به‌صورت دستی یا از طریق ربات Telegram پشتیبان بگیرید و آن‌ها را بازیابی کنید.
icon: DatabaseBackup
---
تمام پیکربندی شما — ورودی‌ها، کلاینت‌ها و تنظیمات — در پایگاه‌داده‌ی پنل
قرار دارد. مرتب از آن پشتیبان بگیرید تا بتوانید بازیابی یا مهاجرت کنید.
## از چه چیزی پشتیبان بگیریم
- **پایگاه‌داده** — به‌صورت پیش‌فرض یک SQLite در `/etc/x-ui/x-ui.db` (یا پایگاه‌داده‌ی
PostgreSQL شما اگر از آن backend استفاده می‌کنید).
- **گواهی‌ها** — هر چیزی که زیر `/root/cert/` (یا هر جایی که گواهی‌های TLS را نگه می‌دارید)
قرار دارد.
## پشتیبان‌گیری دستی
می‌توانید یک نسخه‌ی پشتیبان را از صفحه‌ی نمای کلی پنل دانلود کنید، یا فایل پایگاه‌داده را
مستقیماً از سرور کپی نمایید:
```bash title="copy the SQLite database"
cp /etc/x-ui/x-ui.db /root/x-ui-backup-$(date +%F).db
```
برای بازیابی، پنل را متوقف کنید، پایگاه‌داده را سر جای خود برگردانید و دوباره آن را اجرا کنید.
<Callout type="warn">
هر وقت ممکن است، یک نسخه‌ی پشتیبان را روی **همان نسخه‌ی اصلی (major)** که از آن گرفته شده
بازیابی کنید. در ارتقاهای میان‌نسخه‌ای اصلی، به‌جای تحمیل یک شِمای قدیمی، بگذارید پنل
مهاجرت‌های خود را اجرا کند.
</Callout>
## پشتیبان‌گیری با Telegram
اگر [ربات Telegram](/docs/operations/telegram-bot) را پیکربندی کرده‌اید، گزینه‌ی
**`tgBotBackup`** را فعال کنید تا یک نسخه‌ی پشتیبان به گزارش دوره‌ای ضمیمه شود (بر اساس
زمان‌بندی `tgRunTime`، به‌صورت پیش‌فرض روزانه). ربات هم **پایگاه‌داده** و هم **`config.json`
مربوط به Xray** را به چت ادمین شما می‌فرستد، بنابراین همیشه یک نسخه‌ی خارج از سرور در اختیار
دارید. ادمین‌ها همچنین می‌توانند به‌صورت درخواستی از منوی ربات یک نسخه‌ی پشتیبان بخواهند.
## دامپ / بازیابی SQLite
دستور `x-ui migrate-db` پایگاه‌داده‌ی SQLite را به یک دامپ متنی SQL ساده و بالعکس تبدیل
می‌کند (برای بررسی یا انتقال میان دستگاه‌ها کاربردی است):
```bash
x-ui migrate-db --dump /root/x-ui.sql # SQLite -> SQL text
x-ui migrate-db --restore /root/x-ui.sql # SQL text -> SQLite
```
برای مهاجرت به PostgreSQL، به [پایگاه‌داده](/docs/reference/database) مراجعه کنید.
<Callout type="info">
از هر روشی که استفاده می‌کنید، نسخه‌های پشتیبان را **خارج از سرور** نگه دارید و هرازگاهی
یک بازیابی را آزمایش کنید — یک نسخه‌ی پشتیبانِ آزمایش‌نشده، پشتیبان به‌حساب نمی‌آید.
</Callout>
+12
View File
@@ -0,0 +1,12 @@
{
"title": "عملیات",
"icon": "ServerCog",
"pages": [
"reverse-proxy",
"multi-node",
"outbounds-routing",
"backup-restore",
"telegram-bot",
"security"
]
}
@@ -0,0 +1,86 @@
---
title: چندنودی و میزبان‌های مدیریت‌شده
description: مدیریت چند پنل 3x-ui از یک مستر، با اعتماد مبتنی بر توکن API یا mTLS، ضربان قلب، و بازنویسی میزبان برای هر inbound جهت اشتراک‌ها.
icon: Boxes
---
3x-ui می‌تواند **چندین سرور** را از یک پنل مستر واحد مدیریت کند و با **میزبان‌های مدیریت‌شده** نحوهٔ معرفی هر inbound در اشتراک‌ها را بازنویسی کند.
## نودها
یک **نود** پنل 3x-ui دیگری است که پنل مستر شما آن را از طریق API نود مدیریت می‌کند. مستر هر نود را فراخوانی (poll) می‌کند و وضعیت، نسخه‌ها، CPU/حافظه، آپ‌تایم و ترافیک آن را در یک مکان نمایش می‌دهد.
### افزودن یک نود
جزئیات اتصال نود را وارد کنید:
| فیلد | توضیحات |
| ----------------- | --------------------------------------------------------------------- |
| **Name** | برچسب یکتا (مثلاً `de-fra-1`). |
| **Scheme** | `https` (پیش‌فرض) یا `http`. |
| **Address / Port**| میزبان و پورت پنل نود. |
| **Base path** | مسیر پایهٔ وب نود. |
| **API token** | یک توکن Bearer که روی نود ساخته می‌شود (در حالت mTLS لازم نیست). |
| **TLS verify** | `verify` (پیش‌فرض)، `skip`، `pin` (پین‌کردن SHA-256 گواهی) یا `mtls`. |
| **Inbound sync** | همهٔ inboundها (`all`) یا انتخاب‌شده (`selected`) بر اساس تگ. |
| **Outbound tag** | به‌اختیار از طریق یک outbound نام‌دار به نود برسید (پل خروجی). |
مستر هنگام افزودن یا آزمودن یک نود، قابلیت دسترسی به آن را بررسی می‌کند. سپس هر چند ثانیه یک **ضربان قلب (heartbeat)** ارسال می‌کند، وضعیت نود را به‌روزرسانی می‌کند (`online` / `offline`) و رویدادهای `node.up` / `node.down` را منتشر می‌کند (به [بات Telegram](/docs/operations/telegram-bot) مراجعه کنید).
<Callout type="info">
نودها با یک GUID پایدار به‌ازای هر پنل شناسایی می‌شوند، بنابراین یک نود هویت خود
را در طول راه‌اندازی‌های مجدد حفظ می‌کند. یک نود می‌تواند خودش نودهای دیگری را
مدیریت کند — مستر آن‌ها را به‌صورت زیرنودهای **گذرا (transitive)** فقط‌خواندنی نمایش
می‌دهد (Node 1 ← Node 2 ← Node 3).
</Callout>
### TLS دوطرفه (mTLS) بین مستر و نود
برای قوی‌ترین سطح اعتماد، از `tlsVerifyMode = mtls` استفاده کنید (نیازمند `https`):
<Steps>
<Step>
### CA مستر را دریافت کنید
روی مستر، گواهی CA احراز هویت نود آن را دریافت کنید (کلید خصوصی CA هرگز از پنل
خارج نمی‌شود).
</Step>
<Step>
### آن را روی نود مورد اعتماد قرار دهید
آن CA را در تنظیم «trusted CA» نود جای‌گذاری کنید. در راه‌اندازی مجدد بعدی نود
اعمال می‌شود.
</Step>
<Step>
### نود را به حالت mTLS تغییر دهید
حالت TLS verify نود را روی `mtls` تنظیم کنید. اکنون مستر به‌جای یک توکن API یک
گواهی کلاینت ارائه می‌دهد.
</Step>
</Steps>
## میزبان‌های مدیریت‌شده
یک **میزبان مدیریت‌شده** یک نقطهٔ پایانی بازنویسی است که به یک inbound متصل می‌شود. در زمان اشتراک، هر میزبان فعال یک لینک اشتراک‌گذاری / پراکسی اضافی با آدرس، پورت، TLS، SNI، هدر host، مسیر و موارد دیگر مخصوص خود تولید می‌کند — که جایگزین فهرست قدیمی‌تر «external proxy» می‌شود. از آن‌ها برای موارد زیر استفاده کنید:
- قراردادن یک inbound پشت یک **CDN** (Cloudflare) با آدرس/SNI متفاوت،
- معرفی **چند دامنه** یا نقاط پایانی به‌ازای هر منطقه برای یک inbound،
- تنظیم ALPN، fingerprint، ECH یا mux به‌ازای هر نقطهٔ پایانی.
هر میزبان یک ملاحظه (remark) دارد (که از همان [متغیرهای قالب](/docs/config/share-links#remark-template-variables) پشتیبانی می‌کند)، یک کلید فعال‌سازی، یک ترتیب مرتب‌سازی، و می‌تواند **از قالب‌های اشتراک خاصی مستثنا شود** یا **به نودهای مشخصی محدود گردد**.
<Callout type="info">
میزبان‌هایی که آدرس/پورت آن‌ها به یک CDN اشاره می‌کند، به شما اجازه می‌دهند آدرس
واقعی سرور را خصوصی نگه دارید در حالی که کلاینت‌ها از طریق لبهٔ CDN متصل می‌شوند.
</Callout>
## مرتبط
<Cards>
<Card title="Outboundها و مسیریابی" href="/docs/operations/outbounds-routing" description="WARP، NordVPN، اشتراک‌های outbound و مسیریابی." />
<Card title="اشتراک" href="/docs/config/subscription" description="چگونه میزبان‌ها خروجی اشتراک را شکل می‌دهند." />
</Cards>
@@ -0,0 +1,156 @@
---
title: خروجی‌ها و مسیریابی
description: مدیریت ترافیک خروجی در 3x-ui — خروجی‌های WARP و NordVPN، اشتراک‌های خروجی (مجموعه سرورها)، قواعد مسیریابی و متعادل‌کننده‌های بار.
icon: Route
---
ورودی‌ها کلاینت‌ها را می‌پذیرند؛ **خروجی‌ها** تعیین می‌کنند ترافیک آن‌ها در ادامه به کجا برود.
3x-ui می‌تواند ترافیک را از طریق Cloudflare WARP، NordVPN یا مجموعه‌های خروجی دلخواه
وارد‌شده از یک اشتراک مسیریابی کند و با قواعد مسیریابی و متعادل‌کننده‌ها میان آن‌ها
انتخاب نماید.
## ویرایش خروجی‌ها و مسیریابی
خروجی‌ها، قواعد مسیریابی، متعادل‌کننده‌ها، DNS و ثبت رویداد همگی در **پیکربندی Xray**
قرار دارند (همان قالب پیکربندی که زیر Xray Settings ویرایش می‌کنید). رابط کاربری جداگانه‌ای
برای هر قاعده وجود ندارد — شما JSON را ویرایش می‌کنید و پنل Xray را بارگذاری مجدد می‌کند. پنل
همچنین یک **آزمون اتصال‌پذیری خروجی** و یک **آزمون مسیر** ارائه می‌دهد (از هسته در حال اجرا
بپرسید که برای یک مقصد مشخص از کدام خروجی استفاده خواهد شد).
## ساخت یک خروجی
هر خروجی یک شیء JSON است با حداکثر چهار بخش: یک **`tag`** (که قواعد مسیریابی و
متعادل‌کننده‌ها به آن ارجاع می‌دهند)، یک **`protocol`**، **`settings`** مخصوص پروتکل،
و — برای پروتکل‌های proxy — **`streamSettings`** که باید با انتقال و امنیت ورودی راه دور
مطابقت داشته باشد. دو خروجی تقریباً همیشه حضور دارند:
- **`freedom`** ترافیک را مستقیماً به مقصدش می‌فرستد — خروجی پیش‌فرض.
به‌صورت اختیاری می‌توانید یک `domainStrategy` (مثلاً `UseIP`) تنظیم کنید تا نحوه تفکیک نام‌های میزبان را کنترل کنید.
- **`blackhole`** ترافیک را دور می‌اندازد. مقصدهای ناخواسته (تبلیغات، تورنت‌ها) را به اینجا هدایت کنید.
```json title="freedom + blackhole"
{
"outbounds": [
{ "tag": "direct", "protocol": "freedom", "settings": {} },
{ "tag": "block", "protocol": "blackhole", "settings": {} }
]
}
```
یک خروجی **proxy** (VLESS، VMess، Trojan، Shadowsocks) به سرور دیگری ارسال می‌کند —
که برای زنجیره‌کردن یا فرستادن ترافیک منتخب به خارج مفید است. به شکل‌های سیمی که 3x-ui
استفاده می‌کند توجه کنید: **VLESS شکل تخت است** (`address`/`port`/`id`/`flow`/
`encryption`)، **VMess از `settings.vnext[]` استفاده می‌کند**، و **Trojan/Shadowsocks از
`settings.servers[]` استفاده می‌کنند**. مقدار `streamSettings` باید با
[انتقال و امنیت](/docs/config/transports) مقصد همخوانی داشته باشد.
هر خروجی را در زیر سرهم کنید و JSON را در **Xray Settings → Outbounds** بچسبانید:
<OutboundGenerator />
## Cloudflare WARP
WARP به سرور شما امکان می‌دهد ترافیک خود را از طریق شبکه Cloudflare خارج کند. 3x-ui می‌تواند
یک حساب WARP برای شما ثبت کند و آن را به یک خروجی WireGuard با برچسب **`warp`** متصل نماید:
<Steps>
<Step>
### افزودن یک خروجی با برچسب `warp`
یک خروجی WireGuard با برچسب `warp` در پیکربندی Xray خود بسازید.
</Step>
<Step>
### ثبت WARP
از کنترل‌های WARP در پنل، یک حساب ثبت کنید. 3x-ui کلیدها، نشانی‌ها، بایت‌های رزروشده و نقطه
انتهایی peer مربوط به خروجی را به‌صورت خودکار پر می‌کند.
</Step>
<Step>
### (اختیاری) چرخش خودکار IP
یک بازه به‌روزرسانی WARP (بر حسب **روز**) تنظیم کنید تا IP مربوط به WARP به‌صورت دوره‌ای چرخش
یابد. یک لایسنس رایگان نیز می‌تواند اعمال شود.
</Step>
</Steps>
ترافیک موردنظر خود (برای مثال دامنه‌های خاص) را با یک قاعده مسیریابی به خروجی `warp` هدایت
کنید.
## NordVPN
3x-ui می‌تواند اعتبارنامه‌های NordVPN (NordLynx/WireGuard) را از یک توکن دسترسی دریافت کند (یا
یک کلید خصوصی را مستقیماً بپذیرد) و کشورها/سرورها را فهرست کند تا بتوانید یک خروجی NordVPN
بسازید.
## اشتراک‌های خروجی (مجموعه سرورها)
یک **اشتراک خروجی** یک اشتراک share-link از راه دور را وارد می‌کند و سرورهای آن را به‌عنوان
**خروجی** به پیکربندی در حال اجرای Xray تزریق می‌کند — بدون دست‌زدن به قالب ذخیره‌شده شما. این
روش توصیه‌شده برای اشتراک در یک *مجموعه* از سرورهاست.
| فیلد | پیش‌فرض | معنا |
| ---------------- | ------- | -------------------------------------------------------------- |
| `url` | — | نشانی اشتراک از راه دور (محافظت‌شده در برابر SSRF). |
| `tagPrefix` | auto | پیشوند برچسب‌های خروجی تولیدشده (مثلاً `hk-`)؛ خالی = `subN-`. |
| `updateInterval` | `600` | بازه تازه‌سازی بر حسب **ثانیه**. |
| `prepend` | `false` | این خروجی‌ها را پیش از خروجی‌های دستی شما قرار می‌دهد. |
| `priority` | `0` | ترتیب ادغام (مقدار کمتر، زودتر). |
خروجی‌های وارد‌شده **برچسب‌های پایدار** می‌گیرند: همان سرور در طول تازه‌سازی‌ها همان برچسب را
حفظ می‌کند، بنابراین انتخاب‌گرهای مسیریابی/متعادل‌کننده مبتنی بر برچسب دقیق پایدار می‌مانند —
در حالی که انتخاب‌گرهای پیشوندی/wildcard (مثلاً `hk-*`) با تغییر مجموعه، به‌صورت خودکار سرورهای
جدید را در بر می‌گیرند. طرح‌های پیوند پشتیبانی‌شده: `vmess`، `vless`، `trojan`، `ss`،
`hysteria2` (`hy2`) و `wireguard` (`wg`). پنل اشتراک‌های فعال را روی یک زمان‌سنج تازه می‌کند و
هنگام تغییر چیزی، Xray را بارگذاری مجدد می‌کند.
## قواعد مسیریابی
**قواعد مسیریابی** تعیین می‌کنند هر اتصال از کدام خروجی (یا متعادل‌کننده) استفاده کند. هر
قاعده یک تطبیق‌دهنده از نوع `field` است: هر یک از `domain`، `ip`، `port`، `network`،
`protocol`، `inboundTag`، `sourceIP`، … را تنظیم کنید و آن را به یک **`outboundTag`** یا یک
**`balancerTag`** اشاره دهید. قواعد **از بالا به پایین — نخستین تطبیق برنده است** ارزیابی می‌شوند، بنابراین
قواعد خاص را بالای قواعد عمومی قرار دهید.
```json title="route ads to blackhole, private IPs direct"
{
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{ "type": "field", "domain": ["geosite:category-ads-all"], "outboundTag": "block" },
{ "type": "field", "ip": ["geoip:private"], "outboundTag": "direct" }
]
}
}
```
## متعادل‌کننده‌ها
یک **متعادل‌کننده** خروجی‌ها را با یک **انتخاب‌گر** (پیشوندهای برچسب، از جمله مجموعه‌های
wildcard حاصل از اشتراک‌های خروجی) گروه‌بندی می‌کند و ترافیک را با یک **استراتژی** میان آن‌ها
توزیع یا در صورت خرابی منتقل می‌کند:
| استراتژی | انتخاب می‌کند… | به مانیتور نیاز دارد |
| ------------- | ----------------------------------------------- | ------------------------ |
| `random` | یک عضو تصادفی برای هر اتصال | خیر |
| `roundRobin` | اعضا به‌صورت چرخشی | خیر |
| `leastPing` | عضو با کمترین تأخیر | **`observatory`** |
| `leastLoad` | پایدارترین عضو بر اساس بار نمونه‌برداری‌شده | **`burstObservatory`** |
از یک قاعده با `balancerTag` به یک متعادل‌کننده ارجاع دهید. `leastPing` و `leastLoad`
به یک مانیتور سلامت نیاز دارند که Xray آن را در **سطح بالای** پیکربندی قرار می‌دهد
(`observatory` / `burstObservatory`، **نه** درون `routing`). پنل می‌تواند وضعیت
متعادل‌کننده را گزارش کند و برای آزمایش یک متعادل‌کننده را به یک خروجی مشخص **بازنویسی** کند.
بلوک مسیریابی — قواعد، متعادل‌کننده‌ها و observatory متناظر — را در اینجا بسازید:
<RoutingBuilder />
<Callout type="warn">
خروجی‌هایی که به سرویس‌های خارجی دسترسی می‌یابند با محافظت SSRF واکشی می‌شوند — به‌صورت
پیش‌فرض نشانی‌های خصوصی/داخلی مسدود هستند مگر آنکه به‌طور صریح آن‌ها را به‌ازای هر منبع مجاز
کنید.
</Callout>
@@ -0,0 +1,51 @@
---
title: پراکسی معکوس
description: قرار دادن پنل و اشتراک 3x-ui پشت Nginx یا Caddy همراه با TLS از Let's Encrypt.
icon: Waypoints
---
پراکسی معکوس به شما امکان می‌دهد پنل و اشتراک را روی یک دامنه تمیز با HTTPS خودکار
ارائه دهید و پورت‌های واقعی را پشت پورت‌های 80/443 پنهان کنید. ترجیح می‌دهید خودِ
پنل مستقیماً TLS را مدیریت کند؟ به‌جای آن، گواهی را از طریق
[منوی SSL در `x-ui`](/docs/config/ssl-certificates) دریافت کنید.
## ساخت یک پیکربندی
<ReverseProxyGenerator />
<Callout type="info">
پنل برای به‌روزرسانی‌های زنده از WebSockets استفاده می‌کند، بنابراین پراکسی باید
هدرهای `Upgrade`/`Connection` را عبور دهد (خروجی Nginx بالا این کار را انجام
می‌دهد). Caddy ارتقاهای WebSocket را به‌صورت خودکار مدیریت می‌کند.
</Callout>
## Nginx + گواهی
با Nginx، گواهی را با `certbot` (یا `acme.sh`) دریافت کنید و در بلوک server به آن
ارجاع دهید:
```bash title="certbot"
certbot certonly --nginx -d panel.example.com
```
پس از نصب گواهی، Nginx را بارگذاری مجدد کنید و تمدید خودکار را راه‌اندازی کنید
(`certbot renew` به‌صورت پیش‌فرض روی یک تایمر اجرا می‌شود).
## Caddy
Caddy گواهی‌ها را برای شما دریافت و تمدید می‌کند — یک Caddyfile را به پنل اشاره
دهید و همه‌چیز کار می‌کند:
```text title="Caddyfile"
panel.example.com {
reverse_proxy 127.0.0.1:2053
}
```
## نکته‌ها
- حتی پشت یک پراکسی هم **مسیر پایه وب** پنل را حفظ کنید؛ دفاع لایه‌به‌لایه.
- اگر TLS را در پراکسی مدیریت می‌کنید، ممکن است بخواهید `XUI_SKIP_HSTS=true` را روی
پنل تنظیم کنید — به [مرجع متغیرهای محیطی](/docs/reference/env-vars) مراجعه کنید.
- سرور [اشتراک](/docs/config/subscription) را هم پراکسی کنید تا محتوای آن نیز روی
HTTPS ارائه شود.
@@ -0,0 +1,53 @@
---
title: امنیت
description: سخت‌سازی 3x-ui — احراز هویت پنل و 2FA، محدودیت IP با Fail2ban، قوانین فایروال، BBR و به‌روز ماندن.
icon: ShieldCheck
---
یک پنل پروکسی هدفی پرارزش است. چند لایه سخت‌سازی تأثیر زیادی دارد.
## سخت‌سازی پنل
- اعتبارنامه‌های قوی و یکتا و **احراز هویت دومرحله‌ای** (TOTP).
- یک پورت غیرپیش‌فرض برای پنل و یک مسیر پایه وب طولانی و تصادفی.
- TLS روی پنل (مستقیماً یا از طریق یک [پروکسی معکوس](/docs/operations/reverse-proxy)).
- **محدودکننده ورود** داخلی، یک IP/نام کاربری را پس از ۵ تلاش ناموفق در بازه ۵ دقیقه (به مدت ۱۵ دقیقه) مسدود می‌کند، و پنل می‌تواند ترافیک خروجی خود را از طریق یک outbound مسیریابی کند.
برای فهرست کامل به [نخستین ورود](/docs/guide/first-login) مراجعه کنید.
## Fail2ban و محدودیت‌های IP
برای هر کلاینت یک **محدودیت IP** تنظیم کنید (به [کلاینت‌ها](/docs/config/clients) مراجعه کنید) تا تعداد IPهای مبدأ همزمان محدود شود. اعمال این محدودیت توسط **Fail2ban** انجام می‌شود که 3x-ui آن را برای شما نصب و پیکربندی می‌کند (در نصب‌های اسکریپتی به‌طور پیش‌فرض فعال است و در Docker از طریق `XUI_ENABLE_FAIL2BAN=true`).
آن را از منوی `x-ui` مدیریت کنید (**۲۲ — IP Limit Management**): نصب/پیکربندی، تغییر مدت مسدودسازی (پیش‌فرض **۳۰ دقیقه**)، مسدودسازی/رفع مسدودی یک IP، مشاهده لاگ‌های مسدودسازی و بررسی وضعیت. در پشت صحنه:
- این jail با نام **`3x-ipl`** شناخته می‌شود؛ لاگ‌های مسدودسازی در `/var/log/x-ui/3xipl.log` و `/var/log/x-ui/3xipl-banned.log` قرار دارند (همچنین از طریق `x-ui banlog`).
- مسدودسازی‌ها همه TCP/UDP را پوشش می‌دهند **به‌جز** پورت‌های SSH و پنل شما، بنابراین یک مسدودسازی نمی‌تواند شما را از سرور یا پنل بیرون بیندازد.
<Callout type="warn">
در Docker، Fail2ban با `iptables` مسدودسازی می‌کند که به قابلیت `NET_ADMIN` (و
`NET_RAW`) نیاز دارد — `docker-compose.yml` آن‌ها را اعطا می‌کند. با یک
`docker run` ساده، `--cap-add=NET_ADMIN --cap-add=NET_RAW` را اضافه کنید وگرنه
مسدودسازی‌ها لاگ می‌شوند اما هرگز اعمال نمی‌شوند.
</Callout>
## فایروال
تنها پورت‌هایی را باز کنید که واقعاً استفاده می‌کنید: SSH، پورت پنل، پورت اشتراک و پورت‌های inbound خود. منوی `x-ui` (**۲۳ — Firewall Management**) ابزار `ufw` را در بر می‌گیرد، یا اینجا قوانین را تولید کنید:
<FirewallRulesGenerator />
<Callout type="warn">
پیش از فعال‌سازی یک فایروال با سیاست رد پیش‌فرض، مطمئن شوید که SSH همچنان مجاز
می‌ماند، وگرنه ممکن است خودتان را بیرون بیندازید. با یک نشست دوم باز آن را آزمایش
کنید.
</Callout>
## تنظیم شبکه (BBR)
منوی `x-ui` (**۲۶ — Enable BBR**) کنترل ازدحام BBR گوگل را فعال/غیرفعال می‌کند
(`net.ipv4.tcp_congestion_control = bbr`، `net.core.default_qdisc = fq`) که اغلب توان عملیاتی را روی لینک‌های شلوغ بهبود می‌بخشد.
## به‌روز ماندن
3x-ui و Xray-core را به‌طور منظم به‌روزرسانی کنید — اصلاحات امنیتی در نسخه‌های جدید منتشر می‌شوند. [صفحه انتشارها](https://github.com/MHSanaei/3x-ui/releases) را دنبال کنید و به [به‌روزرسانی و حذف نصب](/docs/guide/update-uninstall) مراجعه کنید.
@@ -0,0 +1,112 @@
---
title: ربات Telegram
description: یک ربات Telegram را به 3x-ui متصل کنید تا فرمان‌ها، گزارش‌های دوره‌ای، هشدارهای رویداد (ورود، CPU، بالا/پایین شدن نود)، پشتیبان‌گیری و سلف‌سرویس کلاینت‌ها را در اختیار داشته باشید.
icon: Send
---
3x-ui می‌تواند یک ربات Telegram را برای پایش، هشدار، پشتیبان‌گیری و مدیریت از راه دور
به کار گیرد. ادمین‌ها کنترل کامل دارند؛ کاربران عادی (که با Telegram ID پیوند خورده‌اند)
می‌توانند مصرف و لینک‌های خودشان را بررسی کنند.
<Callout type="info">
دنبال اخبار و پشتیبانی انجمن هستید؟ به کانال رسمی Telegram یعنی
[@XrayUI](https://t.me/XrayUI) بپیوندید. این از ربات زیر جداست، رباتی که خودتان
آن را برای مدیریت پنل خودتان اجرا می‌کنید.
</Callout>
## راه‌اندازی
<Steps>
<Step>
### ساختن یک ربات
به [@BotFather](https://t.me/BotFather) پیام بدهید، `/newbot` را ارسال کنید و **توکن
ربات** را کپی نمایید.
</Step>
<Step>
### پیدا کردن Telegram ID خودتان
شناسه‌ی عددی کاربری Telegram خود را به دست آورید (پس از اتصال، فرمان `/id` خودِ ربات
آن را گزارش می‌کند). این همان **شناسه‌ی ادمین** شماست.
</Step>
<Step>
### پیکربندی پنل
در تنظیمات پنل، ربات Telegram را فعال کنید و **توکن** و **شناسه‌(های) چت ادمین** را
(با کاما جداشده) تنظیم نمایید. ذخیره کنید، سپس به ربات خود پیام بدهید.
</Step>
</Steps>
پیش از چسباندن توکن، شناسه‌های ادمین و زمان‌بندی گزارش در پنل، آن‌ها را اعتبارسنجی
کنید:
<TelegramSetupHelper />
## فرمان‌ها
این‌ها در منوی فرمان Telegram ظاهر می‌شوند: `/start`، `/help`، `/status`، `/id`.
فرمان‌های دیگر:
| فرمان | چه کسی | عملکرد |
| ------------------ | ------ | ------------------------------------------------------------ |
| `/start`، `/help` | همه | پیام خوش‌آمدگویی و منوی دکمه‌های درون‌خطی |
| `/status` | همه | تأیید فعال بودن ربات |
| `/id` | همه | نمایش شناسه‌ی عددی Telegram شما |
| `/usage <arg>` | هر دو | ادمین‌ها کلاینت‌ها را جست‌وجو می‌کنند؛ کاربران مصرف خود را می‌بینند |
| `/inbound <remark>`| ادمین | نمایش جزئیات یک ورودی |
| `/restart` | ادمین | راه‌اندازی مجدد Xray |
ادمین‌ها همچنین جریان‌های دکمه‌ی درون‌خطی برای مصرف سرور، گزارش‌های ترافیک مرتب‌شده،
بازنشانی ترافیک، پشتیبان‌گیری از DB، گزارش‌های مسدودسازی، فهرست کردن ورودی‌ها/کلاینت‌ها،
کلاینت‌های آنلاین، «به‌زودی تمام‌شونده» و یک جادوگر کامل **افزودن کلاینت** را در اختیار دارند.
کاربران عادی دکمه‌هایی برای مصرف خودشان، لینک‌های اشتراک، لینک‌های منفرد و کدهای QR دارند.
## گزارش‌ها و هشدارها
- **گزارش دوره‌ای** — بر اساس زمان‌بندی `tgRunTime` (به‌صورت پیش‌فرض `@daily`)، ربات
مصرف سرور (هاست، نسخه‌ها، آپ‌تایم، بار، حافظه، کلاینت‌های آنلاین، ترافیک)، فهرستی از
کلاینت‌های تمام‌شده/در‌حال‌انقضا و — اگر `tgBotBackup` فعال باشد — یک نسخه‌ی پشتیبان از
پایگاه‌داده و پیکربندی Xray را برای ادمین‌ها می‌فرستد. کلاینت‌هایی که با Telegram ID
پیوند خورده‌اند، هشدارهای انقضا/سهمیه‌ی خودشان را دریافت می‌کنند.
- **هشدارهای رویداد** — با `tgEnabledEvents` انتخاب می‌شوند (به‌صورت پیش‌فرض `login.attempt,cpu.high`):
| رویداد | چه زمانی |
| --------------- | ------------------------------------------------------- |
| `login.attempt` | ورود به پنل موفق یا ناموفق شود (همراه با IP و نام کاربری) |
| `cpu.high` | CPU از `tgCpu` درصد فراتر برود (به‌صورت پیش‌فرض ۸۰) |
| `memory.high` | حافظه از `tgMemory` درصد فراتر برود (به‌صورت پیش‌فرض ۸۰) |
| `xray.crash` | Xray-core کرش کند |
| `outbound.down` / `outbound.up` | یک خروجی از کار بیفتد / بازیابی شود |
| `node.down` / `node.up` | یک نود آفلاین شود / بازگردد |
زمان‌های پیش‌هشدار از `expireDiff` (روزهای پیش از انقضا) و `trafficDiff` (گیگابایتِ
باقی‌مانده از سهمیه) می‌آیند؛ هر دو به‌صورت پیش‌فرض `0` هستند (خاموش).
## تنظیمات
| تنظیم | پیش‌فرض | معنا |
| -------------- | -------------------------- | ---------------------------------------------- |
| `tgBotEnable` | `false` | روشن/خاموش اصلی. |
| `tgBotToken` | _(محرمانه)_ | توکن API ربات. |
| `tgBotChatId` | _(هیچ‌کدام)_ | شناسه‌های Telegram **ادمین**، جداشده با کاما. |
| `tgBotProxy` | _(هیچ‌کدام)_ | پروکسی `socks5://`، `http://` یا `https://`. |
| `tgBotAPIServer` | _(پیش‌فرض)_ | سرور سفارشی Telegram Bot API. |
| `tgRunTime` | `@daily` | زمان‌بندی گزارش (cron / `@daily` / `@every …`). |
| `tgBotBackup` | `false` | ضمیمه کردن یک نسخه‌ی پشتیبان DB به گزارش دوره‌ای. |
| `tgCpu` / `tgMemory` | `80` / `80` | آستانه‌های هشدار CPU / حافظه (درصد). |
| `tgLang` | `en-US` | زبان ربات. |
| `tgEnabledEvents` | `login.attempt,cpu.high`| اینکه کدام رویدادها تحویل داده شوند. |
<Callout type="warn">
توکن ربات کنترل ربات شما را در دست دارد — آن را محرمانه نگه دارید و فقط شناسه‌های چت
ادمین **مورد اعتماد** را اضافه کنید. هشدارهای ورود هرگز شامل رمزهای عبور نمی‌شوند.
</Callout>
<Callout type="info">
اگر ترجیح می‌دهید هشدارها را از طریق ایمیل دریافت کنید، اعلان‌های ایمیل (SMTP) همان
رویدادها را بازتاب می‌دهند (`smtpEnabledEvents`) — SMTP را در تنظیمات پنل پیکربندی نمایید.
</Callout>
@@ -0,0 +1,80 @@
---
title: توکن‌های API
description: >-
مدیریت توکن‌های Bearer برای احراز هویت برنامه‌نویسی‌شده (ربات‌ها، پنل‌های مرکزی
که از طرف این نود عمل می‌کنند، CI). هر توکن یک نام یکتا و یک پرچم فعال‌سازی دارد —
برای لغو بدون حذف، آن را غیرفعال کنید و برای لغو دائمی، آن را حذف کنید. توکن‌ها به
صورت هش SHA-256 ذخیره می‌شوند و متن خام تنها یک‌بار، در پاسخ ایجاد، بازگردانده
می‌شود — پس از آن قابل بازیابی نیست، بنابراین همان موقع آن را کپی کنید. برای هر
درخواست /panel/api/* یکی را به صورت
<code>Authorization: Bearer &lt;token&gt;</code> ارسال کنید — این توکن یک اعتبارنامهٔ
مدیر کامل است.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every API token, enabled or not. The token value is never returned
— only metadata.
url: >-
#list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata
- depth: 2
title: >-
Mint a new API token. Name must be unique and 1-64 characters; the token
string is server-generated and returned only in this response — it is
stored hashed and cannot be retrieved later.
url: >-
#mint-a-new-api-token-name-must-be-unique-and-1-64-characters-the-token-string-is-server-generated-and-returned-only-in-this-response--it-is-stored-hashed-and-cannot-be-retrieved-later
- depth: 2
title: >-
Permanently delete a token. Any caller using it stops authenticating
immediately.
url: >-
#permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately
- depth: 2
title: >-
Toggle a token enabled/disabled without deleting it. Disabled tokens are
rejected by checkAPIAuth on the next request.
url: >-
#toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request
structuredData:
headings:
- content: >-
List every API token, enabled or not. The token value is never
returned — only metadata.
id: >-
list-every-api-token-enabled-or-not-the-token-value-is-never-returned--only-metadata
- content: >-
Mint a new API token. Name must be unique and 1-64 characters; the
token string is server-generated and returned only in this response —
it is stored hashed and cannot be retrieved later.
id: >-
mint-a-new-api-token-name-must-be-unique-and-1-64-characters-the-token-string-is-server-generated-and-returned-only-in-this-response--it-is-stored-hashed-and-cannot-be-retrieved-later
- content: >-
Permanently delete a token. Any caller using it stops authenticating
immediately.
id: >-
permanently-delete-a-token-any-caller-using-it-stops-authenticating-immediately
- content: >-
Toggle a token enabled/disabled without deleting it. Disabled tokens
are rejected by checkAPIAuth on the next request.
id: >-
toggle-a-token-enableddisabled-without-deleting-it-disabled-tokens-are-rejected-by-checkapiauth-on-the-next-request
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/setting/apiTokens","method":"get"},{"path":"/panel/api/setting/apiTokens/create","method":"post"},{"path":"/panel/api/setting/apiTokens/delete/{id}","method":"post"},{"path":"/panel/api/setting/apiTokens/setEnabled/{id}","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,75 @@
---
title: احراز هویت
description: >-
دو حالت احراز هویت پشتیبانی می‌شود. نشست‌های UI از یک کوکی استفاده می‌کنند که
توسط نقطه‌پایانی ورود تنظیم می‌شود. کلاینت‌های برنامه‌نویسی‌شده (ربات‌ها،
اسکریپت‌ها، پنل‌های راه دور) با یک توکن Bearer که از مسیر Settings → Security →
API Token گرفته می‌شود احراز هویت می‌کنند. هر دو روش برای همهٔ نقاط‌پایانی زیر
/panel/api/* کار می‌کنند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
با نام کاربری + رمز عبور احراز هویت کنید و یک کوکی نشست دریافت کنید.
پیش از هر فراخوانی API مبتنی بر کوکی الزامی است.
url: >-
#authenticate-with-username--password-and-receive-a-session-cookie-required-before-any-cookie-based-api-call
- depth: 2
title: کوکی نشست را پاک می‌کند. برای نشست‌های مرورگر به هدر CSRF نیاز دارد.
url: '#clear-the-session-cookie-requires-the-csrf-header-for-browser-sessions'
- depth: 2
title: >-
یک توکن CSRF برای نشست جاری صادر می‌کند. SPA آن را در هدر X-CSRF-Token
روی درخواست‌های ناامن بازپخش می‌کند. فراخوانندگانی که از توکن Bearer
استفاده می‌کنند می‌توانند از این مرحله صرف‌نظر کنند — میان‌افزار برای
درخواست‌های API احراز هویت‌شده CSRF را دور می‌زند.
url: >-
#mint-a-csrf-token-for-the-current-session-the-spa-replays-it-in-the-x-csrf-token-header-on-unsafe-requests-bearer-token-callers-can-skip-this--the-middleware-short-circuits-csrf-for-authenticated-api-requests
- depth: 2
title: >-
مشخص می‌کند که آیا 2FA روی پنل فعال است یا خیر — صفحهٔ ورود از آن برای
تصمیم‌گیری دربارهٔ نمایش فیلد OTP استفاده می‌کند.
url: >-
#returns-whether-2fa-is-enabled-on-the-panel--used-by-the-login-page-to-decide-whether-to-show-the-otp-field
structuredData:
headings:
- content: >-
با نام کاربری + رمز عبور احراز هویت کنید و یک کوکی نشست دریافت کنید.
پیش از هر فراخوانی API مبتنی بر کوکی الزامی است.
id: >-
authenticate-with-username--password-and-receive-a-session-cookie-required-before-any-cookie-based-api-call
- content: >-
کوکی نشست را پاک می‌کند. برای نشست‌های مرورگر به هدر CSRF نیاز
دارد.
id: clear-the-session-cookie-requires-the-csrf-header-for-browser-sessions
- content: >-
یک توکن CSRF برای نشست جاری صادر می‌کند. SPA آن را در هدر X-CSRF-Token
روی درخواست‌های ناامن بازپخش می‌کند. فراخوانندگانی که از توکن Bearer
استفاده می‌کنند می‌توانند از این مرحله صرف‌نظر کنند — میان‌افزار برای
درخواست‌های API احراز هویت‌شده CSRF را دور می‌زند.
id: >-
mint-a-csrf-token-for-the-current-session-the-spa-replays-it-in-the-x-csrf-token-header-on-unsafe-requests-bearer-token-callers-can-skip-this--the-middleware-short-circuits-csrf-for-authenticated-api-requests
- content: >-
مشخص می‌کند که آیا 2FA روی پنل فعال است یا خیر — صفحهٔ ورود از آن
برای تصمیم‌گیری دربارهٔ نمایش فیلد OTP استفاده می‌کند.
id: >-
returns-whether-2fa-is-enabled-on-the-panel--used-by-the-login-page-to-decide-whether-to-show-the-otp-field
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/login","method":"post"},{"path":"/logout","method":"post"},{"path":"/csrf-token","method":"get"},{"path":"/getTwoFactorEnable","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,37 @@
---
title: پشتیبان‌گیری
description: عملیات‌هایی که با ربات Telegram پیکربندی‌شده تعامل دارند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Send a fresh DB backup to every Telegram chat configured as an admin
recipient. No body, no params.
url: >-
#send-a-fresh-db-backup-to-every-telegram-chat-configured-as-an-admin-recipient-no-body-no-params
structuredData:
headings:
- content: >-
Send a fresh DB backup to every Telegram chat configured as an admin
recipient. No body, no params.
id: >-
send-a-fresh-db-backup-to-every-telegram-chat-configured-as-an-admin-recipient-no-body-no-params
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/backuptotgbot","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,628 @@
---
title: کلاینت‌ها
description: >-
کلاینت‌ها را به‌عنوان موجودیت‌های مستقل مدیریت کنید که می‌توانند به یک یا چند
inbound متصل شوند. هر رکورد کلاینت، ورودی settings.clients را در تمام
inboundهایی که به آن‌ها تعلق دارد هدایت می‌کند. این endpointها زیر مسیر
/panel/api/clients قرار دارند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every client with its attached inbound IDs and traffic record. The
reverse field, if set, is returned as a nested JSON object (legacy
JSON-encoded-string form is still accepted on write).
url: >-
#list-every-client-with-its-attached-inbound-ids-and-traffic-record-the-reverse-field-if-set-is-returned-as-a-nested-json-object-legacy-json-encoded-string-form-is-still-accepted-on-write
- depth: 2
title: >-
Filter, sort, and paginate clients on the server. Each item is a slim
row (no uuid/password/auth/flow/security/reverse/tgId) so the clients
page can ship 25-ish rows in a few KB instead of the full table. The
response also includes a summary computed across the full DB row set so
dashboard counters stay stable as the user paginates or filters. Page
size capped at 200; fetch /get/:email to obtain the full per-client
payload for an edit/info modal.
url: >-
#filter-sort-and-paginate-clients-on-the-server-each-item-is-a-slim-row-no-uuidpasswordauthflowsecurityreversetgid-so-the-clients-page-can-ship-25-ish-rows-in-a-few-kb-instead-of-the-full-table-the-response-also-includes-a-summary-computed-across-the-full-db-row-set-so-dashboard-counters-stay-stable-as-the-user-paginates-or-filters-page-size-capped-at-200-fetch-getemail-to-obtain-the-full-per-client-payload-for-an-editinfo-modal
- depth: 2
title: >-
Fetch one client by email, including the inbound IDs and external config
IDs it is attached to.
url: >-
#fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to
- depth: 2
title: >-
Create a new client and attach it to one or more inbounds in a single
call. Body is JSON. Per-protocol secrets (UUID for VLESS/VMess, password
for Trojan/Shadowsocks, auth for Hysteria) are generated server-side
when omitted, so callers can send only the universal fields.
url: >-
#create-a-new-client-and-attach-it-to-one-or-more-inbounds-in-a-single-call-body-is-json-per-protocol-secrets-uuid-for-vlessvmess-password-for-trojanshadowsocks-auth-for-hysteria-are-generated-server-side-when-omitted-so-callers-can-send-only-the-universal-fields
- depth: 2
title: >-
Update an existing client by email. Changes propagate to every attached
inbound. Body is the JSON client payload — supply the full set of fields
you want to keep (the server replaces the row, it does not patch).
url: >-
#update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
- depth: 2
title: >-
Delete a client by email. Removes it from every attached inbound and
drops its traffic record unless keepTraffic=1 is passed.
url: >-
#delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
- depth: 2
title: >-
Attach an existing client to one or more additional inbounds. Body is
JSON.
url: >-
#attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json
- depth: 2
title: Detach a client from one or more inbounds without deleting the client.
url: '#detach-a-client-from-one-or-more-inbounds-without-deleting-the-client'
- depth: 2
title: >-
Replace a client's external links (per-client share links and remote
subscription URLs surfaced in their subscription). Sends the full set;
the server replaces all rows.
url: >-
#replace-a-clients-external-links-per-client-share-links-and-remote-subscription-urls-surfaced-in-their-subscription-sends-the-full-set-the-server-replaces-all-rows
- depth: 2
title: >-
Reset the up/down counters for every client globally. Quotas and expiry
are not affected. Triggers an Xray restart if any counter actually
moved.
url: >-
#reset-the-updown-counters-for-every-client-globally-quotas-and-expiry-are-not-affected-triggers-an-xray-restart-if-any-counter-actually-moved
- depth: 2
title: >-
Delete every client whose traffic quota is exhausted (used >= total,
when reset is disabled) or whose expiry has passed. Returns the deleted
count and triggers an Xray restart when any client was on a running
inbound.
url: >-
#delete-every-client-whose-traffic-quota-is-exhausted-used--total-when-reset-is-disabled-or-whose-expiry-has-passed-returns-the-deleted-count-and-triggers-an-xray-restart-when-any-client-was-on-a-running-inbound
- depth: 2
title: >-
Delete every client that is not attached to any inbound, along with its
traffic record, IP log, and external links. Useful for clearing clients
left unattached after their inbounds were removed. Returns the deleted
count. Cannot be undone.
url: >-
#delete-every-client-that-is-not-attached-to-any-inbound-along-with-its-traffic-record-ip-log-and-external-links-useful-for-clearing-clients-left-unattached-after-their-inbounds-were-removed-returns-the-deleted-count-cannot-be-undone
- depth: 2
title: >-
Return every client as a {client, inboundIds} array — the same shape
/bulkCreate and /import accept — so the payload round-trips straight
back through /import. Clients with no inbound attachment are included
with an empty inboundIds list. The UI shows this in a CodeMirror viewer
(copy / download); programmatic callers get the array in obj.
url: >-
#return-every-client-as-a-client-inboundids-array--the-same-shape-bulkcreate-and-import-accept--so-the-payload-round-trips-straight-back-through-import-clients-with-no-inbound-attachment-are-included-with-an-empty-inboundids-list-the-ui-shows-this-in-a-codemirror-viewer-copy--download-programmatic-callers-get-the-array-in-obj
- depth: 2
title: >-
Import clients from a JSON body { "data": "<json>" }, where data is a
string-encoded array produced by /export ([{client, inboundIds}]). Items
with inboundIds are created and attached to those inbounds; items with
an empty inboundIds list are restored as unattached client records.
Existing emails are never overwritten — they are returned in skipped.
Triggers a single Xray restart at the end if any target inbound was
running.
url: >-
#import-clients-from-a-json-body--data-json--where-data-is-a-string-encoded-array-produced-by-export-client-inboundids-items-with-inboundids-are-created-and-attached-to-those-inbounds-items-with-an-empty-inboundids-list-are-restored-as-unattached-client-records-existing-emails-are-never-overwritten--they-are-returned-in-skipped-triggers-a-single-xray-restart-at-the-end-if-any-target-inbound-was-running
- depth: 2
title: >-
Shift expiry and/or traffic quota for many clients in one call.
addDays/addBytes may be negative. Clients with unlimited expiry
(expiryTime=0) or unlimited traffic (totalGB=0) are skipped for the
corresponding field — bulk extend never converts unlimited to limited.
The optional flow directive sets the XTLS flow on every client: "none"
clears it, "xtls-rprx-vision"/"xtls-rprx-vision-udp443" set it where the
inbound supports it (omit or "" to leave it unchanged). Returns the
adjusted count and per-email skip reasons.
url: >-
#shift-expiry-andor-traffic-quota-for-many-clients-in-one-call-adddaysaddbytes-may-be-negative-clients-with-unlimited-expiry-expirytime0-or-unlimited-traffic-totalgb0-are-skipped-for-the-corresponding-field--bulk-extend-never-converts-unlimited-to-limited-the-optional-flow-directive-sets-the-xtls-flow-on-every-client-none-clears-it-xtls-rprx-visionxtls-rprx-vision-udp443-set-it-where-the-inbound-supports-it-omit-or--to-leave-it-unchanged-returns-the-adjusted-count-and-per-email-skip-reasons
- depth: 2
title: >-
Enable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to add each user. Note that enabling a
client whose quota is exhausted or whose expiry has passed only flips
the flag — the traffic loop will disable it again on the next tick.
Returns the changed count and per-email skip reasons.
url: >-
#enable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-add-each-user-note-that-enabling-a-client-whose-quota-is-exhausted-or-whose-expiry-has-passed-only-flips-the-flag--the-traffic-loop-will-disable-it-again-on-the-next-tick-returns-the-changed-count-and-per-email-skip-reasons
- depth: 2
title: >-
Disable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to remove each user. Returns the
changed count and per-email skip reasons.
url: >-
#disable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-remove-each-user-returns-the-changed-count-and-per-email-skip-reasons
- depth: 2
title: >-
Delete many clients in one call. The server processes the list
sequentially so each delete sees the committed state of the previous one
— avoids the race the per-email fan-out had on the panel side. Pass
keepTraffic=true to retain the xray_client_traffic rows after deletion.
url: >-
#delete-many-clients-in-one-call-the-server-processes-the-list-sequentially-so-each-delete-sees-the-committed-state-of-the-previous-one--avoids-the-race-the-per-email-fan-out-had-on-the-panel-side-pass-keeptraffictrue-to-retain-the-xray_client_traffic-rows-after-deletion
- depth: 2
title: >-
Create many clients in one call. Body is a JSON array of {client,
inboundIds} payloads — the same shape /add accepts. Items are processed
sequentially; per-email skip reasons are returned for items that fail
(e.g., duplicate email). Triggers a single Xray restart at the end if
any inbound was running.
url: >-
#create-many-clients-in-one-call-body-is-a-json-array-of-client-inboundids-payloads--the-same-shape-add-accepts-items-are-processed-sequentially-per-email-skip-reasons-are-returned-for-items-that-fail-eg-duplicate-email-triggers-a-single-xray-restart-at-the-end-if-any-inbound-was-running
- depth: 2
title: >-
Add many clients to a group in one call. Updates clients.group_name and
patches the matching client entry inside every owning inbound's settings
JSON in a single transaction. If the group name does not yet exist (in
client_groups or as a derived label), it is auto-created as a persistent
group. To clear the group label, use /groups/bulkRemove instead.
url: >-
#add-many-clients-to-a-group-in-one-call-updates-clientsgroup_name-and-patches-the-matching-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-if-the-group-name-does-not-yet-exist-in-client_groups-or-as-a-derived-label-it-is-auto-created-as-a-persistent-group-to-clear-the-group-label-use-groupsbulkremove-instead
- depth: 2
title: >-
Clear the group label on many clients in one call. Inverse of
/groups/bulkAdd. Clients themselves are kept — only the group label is
cleared from clients.group_name and from each owning inbound's settings
JSON. Groups become empty if all their members are removed.
url: >-
#clear-the-group-label-on-many-clients-in-one-call-inverse-of-groupsbulkadd-clients-themselves-are-kept--only-the-group-label-is-cleared-from-clientsgroup_name-and-from-each-owning-inbounds-settings-json-groups-become-empty-if-all-their-members-are-removed
- depth: 2
title: >-
Attach many existing clients to many inbounds in one call. Each client
keeps its identity (email/UUID/password/subId) and a shared traffic row;
all clients are added to a target inbound in a single AddInboundClient
call. Clients already present on a target are reported under skipped.
Returns per-email attached/skipped/errors lists and triggers a single
Xray restart if any target inbound was running.
url: >-
#attach-many-existing-clients-to-many-inbounds-in-one-call-each-client-keeps-its-identity-emailuuidpasswordsubid-and-a-shared-traffic-row-all-clients-are-added-to-a-target-inbound-in-a-single-addinboundclient-call-clients-already-present-on-a-target-are-reported-under-skipped-returns-per-email-attachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- depth: 2
title: >-
Mirror of bulkAttach: detach many existing clients from many inbounds in
one call. For each email, intersects the client's current inbounds with
the requested set and detaches from those only; (email, inbound) pairs
where the client is not currently attached are silently no-ops. Emails
not attached to any of the requested inbounds are reported under
skipped. Client records are kept even if they become orphaned — use
bulkDel for full removal. Returns per-email detached/skipped/errors
lists and triggers a single Xray restart if any target inbound was
running.
url: >-
#mirror-of-bulkattach-detach-many-existing-clients-from-many-inbounds-in-one-call-for-each-email-intersects-the-clients-current-inbounds-with-the-requested-set-and-detaches-from-those-only-email-inbound-pairs-where-the-client-is-not-currently-attached-are-silently-no-ops-emails-not-attached-to-any-of-the-requested-inbounds-are-reported-under-skipped-client-records-are-kept-even-if-they-become-orphaned--use-bulkdel-for-full-removal-returns-per-email-detachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- depth: 2
title: >-
Zero up/down counters for many clients in one call. Loops the
single-reset path so each client is re-enabled across its attached
inbounds and pushed to Xray/remote nodes. Returns the count of
successfully reset clients.
url: >-
#zero-updown-counters-for-many-clients-in-one-call-loops-the-single-reset-path-so-each-client-is-re-enabled-across-its-attached-inbounds-and-pushed-to-xrayremote-nodes-returns-the-count-of-successfully-reset-clients
- depth: 2
title: >-
List all client groups with their member counts. Merges persisted groups
(rows in client_groups, including empty placeholders) with the distinct
group_name values currently set on clients. Sorted alphabetically
(case-insensitive).
url: >-
#list-all-client-groups-with-their-member-counts-merges-persisted-groups-rows-in-client_groups-including-empty-placeholders-with-the-distinct-group_name-values-currently-set-on-clients-sorted-alphabetically-case-insensitive
- depth: 2
title: >-
Return just the email list of clients that currently belong to the given
group. Useful for fanning a single bulk action over an entire group
without round-tripping the full client list.
url: >-
#return-just-the-email-list-of-clients-that-currently-belong-to-the-given-group-useful-for-fanning-a-single-bulk-action-over-an-entire-group-without-round-tripping-the-full-client-list
- depth: 2
title: >-
Create a new empty (placeholder) group. The group becomes selectable in
client forms and the filter drawer even before any client is added to
it. Errors if a group with the same name already exists.
url: >-
#create-a-new-empty-placeholder-group-the-group-becomes-selectable-in-client-forms-and-the-filter-drawer-even-before-any-client-is-added-to-it-errors-if-a-group-with-the-same-name-already-exists
- depth: 2
title: >-
Rename a group. The new name is applied to the client_groups row AND
propagated to every matching client (both clients.group_name and the
client entry inside every owning inbound's settings JSON) in a single
transaction. Returns the number of clients whose label was updated.
url: >-
#rename-a-group-the-new-name-is-applied-to-the-client_groups-row-and-propagated-to-every-matching-client-both-clientsgroup_name-and-the-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-returns-the-number-of-clients-whose-label-was-updated
- depth: 2
title: >-
Remove a group. Deletes the client_groups row and clears the group label
from every matching client (both clients.group_name and the inbound
settings JSON). The clients themselves are NOT deleted — use /bulkDel
after filtering by group for that. Returns the count of clients whose
label was cleared.
url: >-
#remove-a-group-deletes-the-client_groups-row-and-clears-the-group-label-from-every-matching-client-both-clientsgroup_name-and-the-inbound-settings-json-the-clients-themselves-are-not-deleted--use-bulkdel-after-filtering-by-group-for-that-returns-the-count-of-clients-whose-label-was-cleared
- depth: 2
title: >-
Zero out a single clients up/down counters. Re-enables the client
across every attached inbound and pushes the change to Xray (or the
remote node) so depleted users can connect again immediately.
url: >-
#zero-out-a-single-clients-updown-counters-re-enables-the-client-across-every-attached-inbound-and-pushes-the-change-to-xray-or-the-remote-node-so-depleted-users-can-connect-again-immediately
- depth: 2
title: >-
Manually adjust a clients upload + download counters. Useful for
migrations from external accounting systems.
url: >-
#manually-adjust-a-clients-upload--download-counters-useful-for-migrations-from-external-accounting-systems
- depth: 2
title: >-
List source IPs that have connected with the given clients credentials.
Returns an array of "ip (timestamp)" strings.
url: >-
#list-source-ips-that-have-connected-with-the-given-clients-credentials-returns-an-array-of-ip-timestamp-strings
- depth: 2
title: Reset the recorded IP list for a client.
url: '#reset-the-recorded-ip-list-for-a-client'
- depth: 2
title: >-
List the emails of currently connected clients (last seen within the
heartbeat window), deduped across every node.
url: >-
#list-the-emails-of-currently-connected-clients-last-seen-within-the-heartbeat-window-deduped-across-every-node
- depth: 2
title: >-
Online client emails grouped by the panelGuid of the node that
physically hosts each client. The local panel uses its own GUID; each
node (at any depth in a chain) uses its GUID. Lets the inbounds page
attribute online status to the real node instead of the intermediate one
it syncs through.
url: >-
#online-client-emails-grouped-by-the-panelguid-of-the-node-that-physically-hosts-each-client-the-local-panel-uses-its-own-guid-each-node-at-any-depth-in-a-chain-uses-its-guid-lets-the-inbounds-page-attribute-online-status-to-the-real-node-instead-of-the-intermediate-one-it-syncs-through
- depth: 2
title: >-
Per-client source IPs grouped by the panelGuid of the node that observed
them. Lets the central panel attribute and enforce per-client IP limits
using the real visitor IPs each node sees, instead of the address of the
intermediate panel it syncs through.
url: >-
#per-client-source-ips-grouped-by-the-panelguid-of-the-node-that-observed-them-lets-the-central-panel-attribute-and-enforce-per-client-ip-limits-using-the-real-visitor-ips-each-node-sees-instead-of-the-address-of-the-intermediate-panel-it-syncs-through
- depth: 2
title: >-
Inbound tags that carried traffic within the heartbeat window, grouped
by the hosting node's panelGuid. Pairs with onlinesByGuid so the
inbounds page only marks a multi-inbound client online on the inbounds
it actually used. Nodes that do not report per-inbound activity are
absent.
url: >-
#inbound-tags-that-carried-traffic-within-the-heartbeat-window-grouped-by-the-hosting-nodes-panelguid-pairs-with-onlinesbyguid-so-the-inbounds-page-only-marks-a-multi-inbound-client-online-on-the-inbounds-it-actually-used-nodes-that-do-not-report-per-inbound-activity-are-absent
- depth: 2
title: Map of client email → last-seen unix timestamp.
url: '#map-of-client-email--last-seen-unix-timestamp'
- depth: 2
title: Traffic counters for a client identified by email.
url: '#traffic-counters-for-a-client-identified-by-email'
- depth: 2
title: >-
Return every protocol URL (vless://, vmess://, trojan://, ss://,
hysteria://, hy2://) for clients matching the subscription ID. Same
result set as /sub/<subId>, but as a JSON array — no base64. When an
inbound has streamSettings.externalProxy set, one URL is emitted per
external proxy. Empty array when the subId has no enabled clients.
url: >-
#return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-subsubid-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
- depth: 2
title: >-
Return every URL for one client across all attached inbounds — the same
strings the Copy URL button copies in the panel UI. Supported protocols:
vmess, vless, trojan, shadowsocks, hysteria. If
streamSettings.externalProxy is set, returns one URL per external proxy.
Protocols without a URL form (socks, http, mixed, wireguard, dokodemo,
tunnel) contribute nothing.
url: >-
#return-every-url-for-one-client-across-all-attached-inbounds--the-same-strings-the-copy-url-button-copies-in-the-panel-ui-supported-protocols-vmess-vless-trojan-shadowsocks-hysteria-if-streamsettingsexternalproxy-is-set-returns-one-url-per-external-proxy-protocols-without-a-url-form-socks-http-mixed-wireguard-dokodemo-tunnel-contribute-nothing
structuredData:
headings:
- content: >-
List every client with its attached inbound IDs and traffic record.
The reverse field, if set, is returned as a nested JSON object (legacy
JSON-encoded-string form is still accepted on write).
id: >-
list-every-client-with-its-attached-inbound-ids-and-traffic-record-the-reverse-field-if-set-is-returned-as-a-nested-json-object-legacy-json-encoded-string-form-is-still-accepted-on-write
- content: >-
Filter, sort, and paginate clients on the server. Each item is a slim
row (no uuid/password/auth/flow/security/reverse/tgId) so the clients
page can ship 25-ish rows in a few KB instead of the full table. The
response also includes a summary computed across the full DB row set
so dashboard counters stay stable as the user paginates or filters.
Page size capped at 200; fetch /get/:email to obtain the full
per-client payload for an edit/info modal.
id: >-
filter-sort-and-paginate-clients-on-the-server-each-item-is-a-slim-row-no-uuidpasswordauthflowsecurityreversetgid-so-the-clients-page-can-ship-25-ish-rows-in-a-few-kb-instead-of-the-full-table-the-response-also-includes-a-summary-computed-across-the-full-db-row-set-so-dashboard-counters-stay-stable-as-the-user-paginates-or-filters-page-size-capped-at-200-fetch-getemail-to-obtain-the-full-per-client-payload-for-an-editinfo-modal
- content: >-
Fetch one client by email, including the inbound IDs and external
config IDs it is attached to.
id: >-
fetch-one-client-by-email-including-the-inbound-ids-and-external-config-ids-it-is-attached-to
- content: >-
Create a new client and attach it to one or more inbounds in a single
call. Body is JSON. Per-protocol secrets (UUID for VLESS/VMess,
password for Trojan/Shadowsocks, auth for Hysteria) are generated
server-side when omitted, so callers can send only the universal
fields.
id: >-
create-a-new-client-and-attach-it-to-one-or-more-inbounds-in-a-single-call-body-is-json-per-protocol-secrets-uuid-for-vlessvmess-password-for-trojanshadowsocks-auth-for-hysteria-are-generated-server-side-when-omitted-so-callers-can-send-only-the-universal-fields
- content: >-
Update an existing client by email. Changes propagate to every
attached inbound. Body is the JSON client payload — supply the full
set of fields you want to keep (the server replaces the row, it does
not patch).
id: >-
update-an-existing-client-by-email-changes-propagate-to-every-attached-inbound-body-is-the-json-client-payload--supply-the-full-set-of-fields-you-want-to-keep-the-server-replaces-the-row-it-does-not-patch
- content: >-
Delete a client by email. Removes it from every attached inbound and
drops its traffic record unless keepTraffic=1 is passed.
id: >-
delete-a-client-by-email-removes-it-from-every-attached-inbound-and-drops-its-traffic-record-unless-keeptraffic1-is-passed
- content: >-
Attach an existing client to one or more additional inbounds. Body is
JSON.
id: >-
attach-an-existing-client-to-one-or-more-additional-inbounds-body-is-json
- content: Detach a client from one or more inbounds without deleting the client.
id: detach-a-client-from-one-or-more-inbounds-without-deleting-the-client
- content: >-
Replace a client's external links (per-client share links and remote
subscription URLs surfaced in their subscription). Sends the full set;
the server replaces all rows.
id: >-
replace-a-clients-external-links-per-client-share-links-and-remote-subscription-urls-surfaced-in-their-subscription-sends-the-full-set-the-server-replaces-all-rows
- content: >-
Reset the up/down counters for every client globally. Quotas and
expiry are not affected. Triggers an Xray restart if any counter
actually moved.
id: >-
reset-the-updown-counters-for-every-client-globally-quotas-and-expiry-are-not-affected-triggers-an-xray-restart-if-any-counter-actually-moved
- content: >-
Delete every client whose traffic quota is exhausted (used >= total,
when reset is disabled) or whose expiry has passed. Returns the
deleted count and triggers an Xray restart when any client was on a
running inbound.
id: >-
delete-every-client-whose-traffic-quota-is-exhausted-used--total-when-reset-is-disabled-or-whose-expiry-has-passed-returns-the-deleted-count-and-triggers-an-xray-restart-when-any-client-was-on-a-running-inbound
- content: >-
Delete every client that is not attached to any inbound, along with
its traffic record, IP log, and external links. Useful for clearing
clients left unattached after their inbounds were removed. Returns the
deleted count. Cannot be undone.
id: >-
delete-every-client-that-is-not-attached-to-any-inbound-along-with-its-traffic-record-ip-log-and-external-links-useful-for-clearing-clients-left-unattached-after-their-inbounds-were-removed-returns-the-deleted-count-cannot-be-undone
- content: >-
Return every client as a {client, inboundIds} array — the same shape
/bulkCreate and /import accept — so the payload round-trips straight
back through /import. Clients with no inbound attachment are included
with an empty inboundIds list. The UI shows this in a CodeMirror
viewer (copy / download); programmatic callers get the array in obj.
id: >-
return-every-client-as-a-client-inboundids-array--the-same-shape-bulkcreate-and-import-accept--so-the-payload-round-trips-straight-back-through-import-clients-with-no-inbound-attachment-are-included-with-an-empty-inboundids-list-the-ui-shows-this-in-a-codemirror-viewer-copy--download-programmatic-callers-get-the-array-in-obj
- content: >-
Import clients from a JSON body { "data": "<json>" }, where data is a
string-encoded array produced by /export ([{client, inboundIds}]).
Items with inboundIds are created and attached to those inbounds;
items with an empty inboundIds list are restored as unattached client
records. Existing emails are never overwritten — they are returned in
skipped. Triggers a single Xray restart at the end if any target
inbound was running.
id: >-
import-clients-from-a-json-body--data-json--where-data-is-a-string-encoded-array-produced-by-export-client-inboundids-items-with-inboundids-are-created-and-attached-to-those-inbounds-items-with-an-empty-inboundids-list-are-restored-as-unattached-client-records-existing-emails-are-never-overwritten--they-are-returned-in-skipped-triggers-a-single-xray-restart-at-the-end-if-any-target-inbound-was-running
- content: >-
Shift expiry and/or traffic quota for many clients in one call.
addDays/addBytes may be negative. Clients with unlimited expiry
(expiryTime=0) or unlimited traffic (totalGB=0) are skipped for the
corresponding field — bulk extend never converts unlimited to limited.
The optional flow directive sets the XTLS flow on every client: "none"
clears it, "xtls-rprx-vision"/"xtls-rprx-vision-udp443" set it where
the inbound supports it (omit or "" to leave it unchanged). Returns
the adjusted count and per-email skip reasons.
id: >-
shift-expiry-andor-traffic-quota-for-many-clients-in-one-call-adddaysaddbytes-may-be-negative-clients-with-unlimited-expiry-expirytime0-or-unlimited-traffic-totalgb0-are-skipped-for-the-corresponding-field--bulk-extend-never-converts-unlimited-to-limited-the-optional-flow-directive-sets-the-xtls-flow-on-every-client-none-clears-it-xtls-rprx-visionxtls-rprx-vision-udp443-set-it-where-the-inbound-supports-it-omit-or--to-leave-it-unchanged-returns-the-adjusted-count-and-per-email-skip-reasons
- content: >-
Enable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to add each user. Note that enabling
a client whose quota is exhausted or whose expiry has passed only
flips the flag — the traffic loop will disable it again on the next
tick. Returns the changed count and per-email skip reasons.
id: >-
enable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-add-each-user-note-that-enabling-a-client-whose-quota-is-exhausted-or-whose-expiry-has-passed-only-flips-the-flag--the-traffic-loop-will-disable-it-again-on-the-next-tick-returns-the-changed-count-and-per-email-skip-reasons
- content: >-
Disable many clients in one call. Emails are grouped by inbound and
applied with a single read-modify-write per inbound; the running Xray
(local or remote node) is updated to remove each user. Returns the
changed count and per-email skip reasons.
id: >-
disable-many-clients-in-one-call-emails-are-grouped-by-inbound-and-applied-with-a-single-read-modify-write-per-inbound-the-running-xray-local-or-remote-node-is-updated-to-remove-each-user-returns-the-changed-count-and-per-email-skip-reasons
- content: >-
Delete many clients in one call. The server processes the list
sequentially so each delete sees the committed state of the previous
one — avoids the race the per-email fan-out had on the panel side.
Pass keepTraffic=true to retain the xray_client_traffic rows after
deletion.
id: >-
delete-many-clients-in-one-call-the-server-processes-the-list-sequentially-so-each-delete-sees-the-committed-state-of-the-previous-one--avoids-the-race-the-per-email-fan-out-had-on-the-panel-side-pass-keeptraffictrue-to-retain-the-xray_client_traffic-rows-after-deletion
- content: >-
Create many clients in one call. Body is a JSON array of {client,
inboundIds} payloads — the same shape /add accepts. Items are
processed sequentially; per-email skip reasons are returned for items
that fail (e.g., duplicate email). Triggers a single Xray restart at
the end if any inbound was running.
id: >-
create-many-clients-in-one-call-body-is-a-json-array-of-client-inboundids-payloads--the-same-shape-add-accepts-items-are-processed-sequentially-per-email-skip-reasons-are-returned-for-items-that-fail-eg-duplicate-email-triggers-a-single-xray-restart-at-the-end-if-any-inbound-was-running
- content: >-
Add many clients to a group in one call. Updates clients.group_name
and patches the matching client entry inside every owning inbound's
settings JSON in a single transaction. If the group name does not yet
exist (in client_groups or as a derived label), it is auto-created as
a persistent group. To clear the group label, use /groups/bulkRemove
instead.
id: >-
add-many-clients-to-a-group-in-one-call-updates-clientsgroup_name-and-patches-the-matching-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-if-the-group-name-does-not-yet-exist-in-client_groups-or-as-a-derived-label-it-is-auto-created-as-a-persistent-group-to-clear-the-group-label-use-groupsbulkremove-instead
- content: >-
Clear the group label on many clients in one call. Inverse of
/groups/bulkAdd. Clients themselves are kept — only the group label is
cleared from clients.group_name and from each owning inbound's
settings JSON. Groups become empty if all their members are removed.
id: >-
clear-the-group-label-on-many-clients-in-one-call-inverse-of-groupsbulkadd-clients-themselves-are-kept--only-the-group-label-is-cleared-from-clientsgroup_name-and-from-each-owning-inbounds-settings-json-groups-become-empty-if-all-their-members-are-removed
- content: >-
Attach many existing clients to many inbounds in one call. Each client
keeps its identity (email/UUID/password/subId) and a shared traffic
row; all clients are added to a target inbound in a single
AddInboundClient call. Clients already present on a target are
reported under skipped. Returns per-email attached/skipped/errors
lists and triggers a single Xray restart if any target inbound was
running.
id: >-
attach-many-existing-clients-to-many-inbounds-in-one-call-each-client-keeps-its-identity-emailuuidpasswordsubid-and-a-shared-traffic-row-all-clients-are-added-to-a-target-inbound-in-a-single-addinboundclient-call-clients-already-present-on-a-target-are-reported-under-skipped-returns-per-email-attachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- content: >-
Mirror of bulkAttach: detach many existing clients from many inbounds
in one call. For each email, intersects the client's current inbounds
with the requested set and detaches from those only; (email, inbound)
pairs where the client is not currently attached are silently no-ops.
Emails not attached to any of the requested inbounds are reported
under skipped. Client records are kept even if they become orphaned —
use bulkDel for full removal. Returns per-email
detached/skipped/errors lists and triggers a single Xray restart if
any target inbound was running.
id: >-
mirror-of-bulkattach-detach-many-existing-clients-from-many-inbounds-in-one-call-for-each-email-intersects-the-clients-current-inbounds-with-the-requested-set-and-detaches-from-those-only-email-inbound-pairs-where-the-client-is-not-currently-attached-are-silently-no-ops-emails-not-attached-to-any-of-the-requested-inbounds-are-reported-under-skipped-client-records-are-kept-even-if-they-become-orphaned--use-bulkdel-for-full-removal-returns-per-email-detachedskippederrors-lists-and-triggers-a-single-xray-restart-if-any-target-inbound-was-running
- content: >-
Zero up/down counters for many clients in one call. Loops the
single-reset path so each client is re-enabled across its attached
inbounds and pushed to Xray/remote nodes. Returns the count of
successfully reset clients.
id: >-
zero-updown-counters-for-many-clients-in-one-call-loops-the-single-reset-path-so-each-client-is-re-enabled-across-its-attached-inbounds-and-pushed-to-xrayremote-nodes-returns-the-count-of-successfully-reset-clients
- content: >-
List all client groups with their member counts. Merges persisted
groups (rows in client_groups, including empty placeholders) with the
distinct group_name values currently set on clients. Sorted
alphabetically (case-insensitive).
id: >-
list-all-client-groups-with-their-member-counts-merges-persisted-groups-rows-in-client_groups-including-empty-placeholders-with-the-distinct-group_name-values-currently-set-on-clients-sorted-alphabetically-case-insensitive
- content: >-
Return just the email list of clients that currently belong to the
given group. Useful for fanning a single bulk action over an entire
group without round-tripping the full client list.
id: >-
return-just-the-email-list-of-clients-that-currently-belong-to-the-given-group-useful-for-fanning-a-single-bulk-action-over-an-entire-group-without-round-tripping-the-full-client-list
- content: >-
Create a new empty (placeholder) group. The group becomes selectable
in client forms and the filter drawer even before any client is added
to it. Errors if a group with the same name already exists.
id: >-
create-a-new-empty-placeholder-group-the-group-becomes-selectable-in-client-forms-and-the-filter-drawer-even-before-any-client-is-added-to-it-errors-if-a-group-with-the-same-name-already-exists
- content: >-
Rename a group. The new name is applied to the client_groups row AND
propagated to every matching client (both clients.group_name and the
client entry inside every owning inbound's settings JSON) in a single
transaction. Returns the number of clients whose label was updated.
id: >-
rename-a-group-the-new-name-is-applied-to-the-client_groups-row-and-propagated-to-every-matching-client-both-clientsgroup_name-and-the-client-entry-inside-every-owning-inbounds-settings-json-in-a-single-transaction-returns-the-number-of-clients-whose-label-was-updated
- content: >-
Remove a group. Deletes the client_groups row and clears the group
label from every matching client (both clients.group_name and the
inbound settings JSON). The clients themselves are NOT deleted — use
/bulkDel after filtering by group for that. Returns the count of
clients whose label was cleared.
id: >-
remove-a-group-deletes-the-client_groups-row-and-clears-the-group-label-from-every-matching-client-both-clientsgroup_name-and-the-inbound-settings-json-the-clients-themselves-are-not-deleted--use-bulkdel-after-filtering-by-group-for-that-returns-the-count-of-clients-whose-label-was-cleared
- content: >-
Zero out a single clients up/down counters. Re-enables the client
across every attached inbound and pushes the change to Xray (or the
remote node) so depleted users can connect again immediately.
id: >-
zero-out-a-single-clients-updown-counters-re-enables-the-client-across-every-attached-inbound-and-pushes-the-change-to-xray-or-the-remote-node-so-depleted-users-can-connect-again-immediately
- content: >-
Manually adjust a clients upload + download counters. Useful for
migrations from external accounting systems.
id: >-
manually-adjust-a-clients-upload--download-counters-useful-for-migrations-from-external-accounting-systems
- content: >-
List source IPs that have connected with the given clients
credentials. Returns an array of "ip (timestamp)" strings.
id: >-
list-source-ips-that-have-connected-with-the-given-clients-credentials-returns-an-array-of-ip-timestamp-strings
- content: Reset the recorded IP list for a client.
id: reset-the-recorded-ip-list-for-a-client
- content: >-
List the emails of currently connected clients (last seen within the
heartbeat window), deduped across every node.
id: >-
list-the-emails-of-currently-connected-clients-last-seen-within-the-heartbeat-window-deduped-across-every-node
- content: >-
Online client emails grouped by the panelGuid of the node that
physically hosts each client. The local panel uses its own GUID; each
node (at any depth in a chain) uses its GUID. Lets the inbounds page
attribute online status to the real node instead of the intermediate
one it syncs through.
id: >-
online-client-emails-grouped-by-the-panelguid-of-the-node-that-physically-hosts-each-client-the-local-panel-uses-its-own-guid-each-node-at-any-depth-in-a-chain-uses-its-guid-lets-the-inbounds-page-attribute-online-status-to-the-real-node-instead-of-the-intermediate-one-it-syncs-through
- content: >-
Per-client source IPs grouped by the panelGuid of the node that
observed them. Lets the central panel attribute and enforce per-client
IP limits using the real visitor IPs each node sees, instead of the
address of the intermediate panel it syncs through.
id: >-
per-client-source-ips-grouped-by-the-panelguid-of-the-node-that-observed-them-lets-the-central-panel-attribute-and-enforce-per-client-ip-limits-using-the-real-visitor-ips-each-node-sees-instead-of-the-address-of-the-intermediate-panel-it-syncs-through
- content: >-
Inbound tags that carried traffic within the heartbeat window, grouped
by the hosting node's panelGuid. Pairs with onlinesByGuid so the
inbounds page only marks a multi-inbound client online on the inbounds
it actually used. Nodes that do not report per-inbound activity are
absent.
id: >-
inbound-tags-that-carried-traffic-within-the-heartbeat-window-grouped-by-the-hosting-nodes-panelguid-pairs-with-onlinesbyguid-so-the-inbounds-page-only-marks-a-multi-inbound-client-online-on-the-inbounds-it-actually-used-nodes-that-do-not-report-per-inbound-activity-are-absent
- content: Map of client email → last-seen unix timestamp.
id: map-of-client-email--last-seen-unix-timestamp
- content: Traffic counters for a client identified by email.
id: traffic-counters-for-a-client-identified-by-email
- content: >-
Return every protocol URL (vless://, vmess://, trojan://, ss://,
hysteria://, hy2://) for clients matching the subscription ID. Same
result set as /sub/<subId>, but as a JSON array — no base64. When an
inbound has streamSettings.externalProxy set, one URL is emitted per
external proxy. Empty array when the subId has no enabled clients.
id: >-
return-every-protocol-url-vless-vmess-trojan-ss-hysteria-hy2-for-clients-matching-the-subscription-id-same-result-set-as-subsubid-but-as-a-json-array--no-base64-when-an-inbound-has-streamsettingsexternalproxy-set-one-url-is-emitted-per-external-proxy-empty-array-when-the-subid-has-no-enabled-clients
- content: >-
Return every URL for one client across all attached inbounds — the
same strings the Copy URL button copies in the panel UI. Supported
protocols: vmess, vless, trojan, shadowsocks, hysteria. If
streamSettings.externalProxy is set, returns one URL per external
proxy. Protocols without a URL form (socks, http, mixed, wireguard,
dokodemo, tunnel) contribute nothing.
id: >-
return-every-url-for-one-client-across-all-attached-inbounds--the-same-strings-the-copy-url-button-copies-in-the-panel-ui-supported-protocols-vmess-vless-trojan-shadowsocks-hysteria-if-streamsettingsexternalproxy-is-set-returns-one-url-per-external-proxy-protocols-without-a-url-form-socks-http-mixed-wireguard-dokodemo-tunnel-contribute-nothing
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/clients/list","method":"get"},{"path":"/panel/api/clients/list/paged","method":"get"},{"path":"/panel/api/clients/get/{email}","method":"get"},{"path":"/panel/api/clients/add","method":"post"},{"path":"/panel/api/clients/update/{email}","method":"post"},{"path":"/panel/api/clients/del/{email}","method":"post"},{"path":"/panel/api/clients/{email}/attach","method":"post"},{"path":"/panel/api/clients/{email}/detach","method":"post"},{"path":"/panel/api/clients/{email}/externalLinks","method":"post"},{"path":"/panel/api/clients/resetAllTraffics","method":"post"},{"path":"/panel/api/clients/delDepleted","method":"post"},{"path":"/panel/api/clients/delOrphans","method":"post"},{"path":"/panel/api/clients/export","method":"get"},{"path":"/panel/api/clients/import","method":"post"},{"path":"/panel/api/clients/bulkAdjust","method":"post"},{"path":"/panel/api/clients/bulkEnable","method":"post"},{"path":"/panel/api/clients/bulkDisable","method":"post"},{"path":"/panel/api/clients/bulkDel","method":"post"},{"path":"/panel/api/clients/bulkCreate","method":"post"},{"path":"/panel/api/clients/groups/bulkAdd","method":"post"},{"path":"/panel/api/clients/groups/bulkRemove","method":"post"},{"path":"/panel/api/clients/bulkAttach","method":"post"},{"path":"/panel/api/clients/bulkDetach","method":"post"},{"path":"/panel/api/clients/bulkResetTraffic","method":"post"},{"path":"/panel/api/clients/groups","method":"get"},{"path":"/panel/api/clients/groups/{name}/emails","method":"get"},{"path":"/panel/api/clients/groups/create","method":"post"},{"path":"/panel/api/clients/groups/rename","method":"post"},{"path":"/panel/api/clients/groups/delete","method":"post"},{"path":"/panel/api/clients/resetTraffic/{email}","method":"post"},{"path":"/panel/api/clients/updateTraffic/{email}","method":"post"},{"path":"/panel/api/clients/ips/{email}","method":"post"},{"path":"/panel/api/clients/clearIps/{email}","method":"post"},{"path":"/panel/api/clients/onlines","method":"post"},{"path":"/panel/api/clients/onlinesByGuid","method":"post"},{"path":"/panel/api/clients/clientIpsByGuid","method":"post"},{"path":"/panel/api/clients/activeInbounds","method":"post"},{"path":"/panel/api/clients/lastOnline","method":"post"},{"path":"/panel/api/clients/traffic/{email}","method":"get"},{"path":"/panel/api/clients/subLinks/{subId}","method":"get"},{"path":"/panel/api/clients/links/{email}","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,108 @@
---
title: هاست‌ها
description: >-
نقاط پایانی بازنویسی به ازای هر inbound. هر host فعال یک لینک اشتراک/پراکسی
اضافی با آدرس/پورت/TLS مخصوص خودش ارائه می‌دهد و جایگزین آرایه‌ی قدیمی
externalProxy می‌شود. همه‌ی نقاط پایانی زیر /panel/api/hosts قرار دارند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every host across all inbounds, grouped by inbound then ordered by
sort order.
url: >-
#list-every-host-across-all-inbounds-grouped-by-inbound-then-ordered-by-sort-order
- depth: 2
title: Fetch a single host by ID.
url: '#fetch-a-single-host-by-id'
- depth: 2
title: Fetch one inbound's hosts, ordered by sort order then id.
url: '#fetch-one-inbounds-hosts-ordered-by-sort-order-then-id'
- depth: 2
title: Distinct, sorted set of tags used across all hosts.
url: '#distinct-sorted-set-of-tags-used-across-all-hosts'
- depth: 2
title: >-
Create a host on an inbound. inboundId and remark are required; security
defaults to "same" (inherit the inbound).
url: >-
#create-a-host-on-an-inbound-inboundid-and-remark-are-required-security-defaults-to-same-inherit-the-inbound
- depth: 2
title: >-
Replace a hosts content. The inbound and sort order are immutable here
(use /reorder for ordering).
url: >-
#replace-a-hosts-content-the-inbound-and-sort-order-are-immutable-here-use-reorder-for-ordering
- depth: 2
title: Delete a host.
url: '#delete-a-host'
- depth: 2
title: >-
Enable or disable a single host (disabled hosts are skipped in
subscriptions).
url: >-
#enable-or-disable-a-single-host-disabled-hosts-are-skipped-in-subscriptions
- depth: 2
title: Set host sort order by the position of each id in the array.
url: '#set-host-sort-order-by-the-position-of-each-id-in-the-array'
- depth: 2
title: Enable or disable many hosts in one call.
url: '#enable-or-disable-many-hosts-in-one-call'
- depth: 2
title: Delete many hosts in one call.
url: '#delete-many-hosts-in-one-call'
structuredData:
headings:
- content: >-
List every host across all inbounds, grouped by inbound then ordered
by sort order.
id: >-
list-every-host-across-all-inbounds-grouped-by-inbound-then-ordered-by-sort-order
- content: Fetch a single host by ID.
id: fetch-a-single-host-by-id
- content: Fetch one inbound's hosts, ordered by sort order then id.
id: fetch-one-inbounds-hosts-ordered-by-sort-order-then-id
- content: Distinct, sorted set of tags used across all hosts.
id: distinct-sorted-set-of-tags-used-across-all-hosts
- content: >-
Create a host on an inbound. inboundId and remark are required;
security defaults to "same" (inherit the inbound).
id: >-
create-a-host-on-an-inbound-inboundid-and-remark-are-required-security-defaults-to-same-inherit-the-inbound
- content: >-
Replace a hosts content. The inbound and sort order are immutable
here (use /reorder for ordering).
id: >-
replace-a-hosts-content-the-inbound-and-sort-order-are-immutable-here-use-reorder-for-ordering
- content: Delete a host.
id: delete-a-host
- content: >-
Enable or disable a single host (disabled hosts are skipped in
subscriptions).
id: >-
enable-or-disable-a-single-host-disabled-hosts-are-skipped-in-subscriptions
- content: Set host sort order by the position of each id in the array.
id: set-host-sort-order-by-the-position-of-each-id-in-the-array
- content: Enable or disable many hosts in one call.
id: enable-or-disable-many-hosts-in-one-call
- content: Delete many hosts in one call.
id: delete-many-hosts-in-one-call
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/hosts/list","method":"get"},{"path":"/panel/api/hosts/get/{id}","method":"get"},{"path":"/panel/api/hosts/byInbound/{inboundId}","method":"get"},{"path":"/panel/api/hosts/tags","method":"get"},{"path":"/panel/api/hosts/add","method":"post"},{"path":"/panel/api/hosts/update/{id}","method":"post"},{"path":"/panel/api/hosts/del/{id}","method":"post"},{"path":"/panel/api/hosts/setEnable/{id}","method":"post"},{"path":"/panel/api/hosts/reorder","method":"post"},{"path":"/panel/api/hosts/bulk/setEnable","method":"post"},{"path":"/panel/api/hosts/bulk/del","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,242 @@
---
title: ورودی‌ها
description: >-
مدیریت پیکربندی‌های ورودی و کلاینت‌های آن‌ها. همهٔ endpointها زیر
/panel/api/inbounds قرار دارند و به یک نشست واردشده یا توکن Bearer نیاز دارند.
endpointهای تولیدکنندهٔ لینک تنها زمانی به هدرهای forwarded اعتنا می‌کنند که
درخواست از یک پراکسی مورد اعتماد پیکربندی‌شده برسد.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every inbound owned by the authenticated user, including each
inbounds clientStats traffic counters. settings, streamSettings, and
sniffing are returned as nested JSON objects (no escaped strings);
legacy callers that send them back as JSON-encoded strings are still
accepted on write.
url: >-
#list-every-inbound-owned-by-the-authenticated-user-including-each-inbounds-clientstats-traffic-counters-settings-streamsettings-and-sniffing-are-returned-as-nested-json-objects-no-escaped-strings-legacy-callers-that-send-them-back-as-json-encoded-strings-are-still-accepted-on-write
- depth: 2
title: >-
Same shape as /list but with settings.clients[] stripped down to {email,
enable, comment} and ClientStats not enriched with UUID/SubId. Use this
for list pages; fetch /get/:id when you need the full per-client payload
(uuid, password, flow, ...).
url: >-
#same-shape-as-list-but-with-settingsclients-stripped-down-to-email-enable-comment-and-clientstats-not-enriched-with-uuidsubid-use-this-for-list-pages-fetch-getid-when-you-need-the-full-per-client-payload-uuid-password-flow-
- depth: 2
title: >-
Lightweight picker projection of the authenticated users inbounds.
Returns id, remark, tag, protocol, port, a server-computed
tlsFlowCapable flag (true for VLESS on TCP with tls or reality, or on
XHTTP with VLESS encryption / vlessenc enabled), and ssMethod (the
Shadowsocks cipher, empty for non-Shadowsocks inbounds — used by the
client UI to generate a valid Shadowsocks 2022 PSK). Use this for
dropdowns and attach pickers — it skips settings, streamSettings, and
clientStats so the payload stays small even on panels with thousands of
clients.
url: >-
#lightweight-picker-projection-of-the-authenticated-users-inbounds-returns-id-remark-tag-protocol-port-a-server-computed-tlsflowcapable-flag-true-for-vless-on-tcp-with-tls-or-reality-or-on-xhttp-with-vless-encryption--vlessenc-enabled-and-ssmethod-the-shadowsocks-cipher-empty-for-non-shadowsocks-inbounds--used-by-the-client-ui-to-generate-a-valid-shadowsocks-2022-psk-use-this-for-dropdowns-and-attach-pickers--it-skips-settings-streamsettings-and-clientstats-so-the-payload-stays-small-even-on-panels-with-thousands-of-clients
- depth: 2
title: Fetch a single inbound by numeric ID.
url: '#fetch-a-single-inbound-by-numeric-id'
- depth: 2
title: >-
Create a new inbound. Send the full inbound payload (protocol, port,
settings, streamSettings, sniffing, remark, expiryTime, total, enable).
settings, streamSettings, and sniffing may be sent as nested JSON
objects (preferred) or as JSON-encoded strings (legacy).
url: >-
#create-a-new-inbound-send-the-full-inbound-payload-protocol-port-settings-streamsettings-sniffing-remark-expirytime-total-enable-settings-streamsettings-and-sniffing-may-be-sent-as-nested-json-objects-preferred-or-as-json-encoded-strings-legacy
- depth: 2
title: Delete an inbound by ID. Also removes its associated client stats rows.
url: '#delete-an-inbound-by-id-also-removes-its-associated-client-stats-rows'
- depth: 2
title: >-
Delete many inbounds in one call. Processes the list sequentially;
failures are reported per id and the rest still proceed. Restarts xray
at most once.
url: >-
#delete-many-inbounds-in-one-call-processes-the-list-sequentially-failures-are-reported-per-id-and-the-rest-still-proceed-restarts-xray-at-most-once
- depth: 2
title: >-
Replace an inbounds configuration. Body shape mirrors /add. Heavy on
inbounds with thousands of clients — prefer /setEnable for enable-only
flips.
url: >-
#replace-an-inbounds-configuration-body-shape-mirrors-add-heavy-on-inbounds-with-thousands-of-clients--prefer-setenable-for-enable-only-flips
- depth: 2
title: >-
Toggle only the enable flag without serialising the whole settings JSON.
Recommended for UI switches on large inbounds.
url: >-
#toggle-only-the-enable-flag-without-serialising-the-whole-settings-json-recommended-for-ui-switches-on-large-inbounds
- depth: 2
title: >-
Zero out upload + download counters for a single inbound. Does not touch
per-client counters.
url: >-
#zero-out-upload--download-counters-for-a-single-inbound-does-not-touch-per-client-counters
- depth: 2
title: >-
Remove every client attached to a single inbound while keeping the
inbound itself. Collects emails from settings.clients[] and feeds them
into the optimized bulk-delete path (runtime user removal + traffic-row
cleanup + SyncInbound). Destructive and cannot be undone.
url: >-
#remove-every-client-attached-to-a-single-inbound-while-keeping-the-inbound-itself-collects-emails-from-settingsclients-and-feeds-them-into-the-optimized-bulk-delete-path-runtime-user-removal--traffic-row-cleanup--syncinbound-destructive-and-cannot-be-undone
- depth: 2
title: >-
Reset upload + download counters on every inbound. Destructive —
accounting history is lost.
url: >-
#reset-upload--download-counters-on-every-inbound-destructive--accounting-history-is-lost
- depth: 2
title: >-
Bulk-import an inbound from a JSON blob (e.g. one exported via the UI).
The body uses form encoding with a single "data" field.
url: >-
#bulk-import-an-inbound-from-a-json-blob-eg-one-exported-via-the-ui-the-body-uses-form-encoding-with-a-single-data-field
- depth: 2
title: >-
Receive a master panel's aggregated per-client usage, keyed by the
master's GUID. Stored in a side table used only for the UI display
overlay and local quota enforcement — never folded into the local
counters that masters poll, so delta accounting stays intact. Called
panel-to-panel by the node traffic sync job.
url: >-
#receive-a-master-panels-aggregated-per-client-usage-keyed-by-the-masters-guid-stored-in-a-side-table-used-only-for-the-ui-display-overlay-and-local-quota-enforcement--never-folded-into-the-local-counters-that-masters-poll-so-delta-accounting-stays-intact-called-panel-to-panel-by-the-node-traffic-sync-job
- depth: 2
title: >-
List the fallback rules attached to a master VLESS/Trojan TCP-TLS
inbound. Each rule links one child inbound (the dest) to optional
SNI/ALPN/path/dest/xver match criteria. When dest is empty the child
inbound's listen+port is used.
url: >-
#list-the-fallback-rules-attached-to-a-master-vlesstrojan-tcp-tls-inbound-each-rule-links-one-child-inbound-the-dest-to-optional-snialpnpathdestxver-match-criteria-when-dest-is-empty-the-child-inbounds-listenport-is-used
- depth: 2
title: >-
Replace the entire fallback list for a master inbound. Body is JSON.
Triggers an Xray restart.
url: >-
#replace-the-entire-fallback-list-for-a-master-inbound-body-is-json-triggers-an-xray-restart
structuredData:
headings:
- content: >-
List every inbound owned by the authenticated user, including each
inbounds clientStats traffic counters. settings, streamSettings, and
sniffing are returned as nested JSON objects (no escaped strings);
legacy callers that send them back as JSON-encoded strings are still
accepted on write.
id: >-
list-every-inbound-owned-by-the-authenticated-user-including-each-inbounds-clientstats-traffic-counters-settings-streamsettings-and-sniffing-are-returned-as-nested-json-objects-no-escaped-strings-legacy-callers-that-send-them-back-as-json-encoded-strings-are-still-accepted-on-write
- content: >-
Same shape as /list but with settings.clients[] stripped down to
{email, enable, comment} and ClientStats not enriched with UUID/SubId.
Use this for list pages; fetch /get/:id when you need the full
per-client payload (uuid, password, flow, ...).
id: >-
same-shape-as-list-but-with-settingsclients-stripped-down-to-email-enable-comment-and-clientstats-not-enriched-with-uuidsubid-use-this-for-list-pages-fetch-getid-when-you-need-the-full-per-client-payload-uuid-password-flow-
- content: >-
Lightweight picker projection of the authenticated users inbounds.
Returns id, remark, tag, protocol, port, a server-computed
tlsFlowCapable flag (true for VLESS on TCP with tls or reality, or on
XHTTP with VLESS encryption / vlessenc enabled), and ssMethod (the
Shadowsocks cipher, empty for non-Shadowsocks inbounds — used by the
client UI to generate a valid Shadowsocks 2022 PSK). Use this for
dropdowns and attach pickers — it skips settings, streamSettings, and
clientStats so the payload stays small even on panels with thousands
of clients.
id: >-
lightweight-picker-projection-of-the-authenticated-users-inbounds-returns-id-remark-tag-protocol-port-a-server-computed-tlsflowcapable-flag-true-for-vless-on-tcp-with-tls-or-reality-or-on-xhttp-with-vless-encryption--vlessenc-enabled-and-ssmethod-the-shadowsocks-cipher-empty-for-non-shadowsocks-inbounds--used-by-the-client-ui-to-generate-a-valid-shadowsocks-2022-psk-use-this-for-dropdowns-and-attach-pickers--it-skips-settings-streamsettings-and-clientstats-so-the-payload-stays-small-even-on-panels-with-thousands-of-clients
- content: Fetch a single inbound by numeric ID.
id: fetch-a-single-inbound-by-numeric-id
- content: >-
Create a new inbound. Send the full inbound payload (protocol, port,
settings, streamSettings, sniffing, remark, expiryTime, total,
enable). settings, streamSettings, and sniffing may be sent as nested
JSON objects (preferred) or as JSON-encoded strings (legacy).
id: >-
create-a-new-inbound-send-the-full-inbound-payload-protocol-port-settings-streamsettings-sniffing-remark-expirytime-total-enable-settings-streamsettings-and-sniffing-may-be-sent-as-nested-json-objects-preferred-or-as-json-encoded-strings-legacy
- content: >-
Delete an inbound by ID. Also removes its associated client stats
rows.
id: delete-an-inbound-by-id-also-removes-its-associated-client-stats-rows
- content: >-
Delete many inbounds in one call. Processes the list sequentially;
failures are reported per id and the rest still proceed. Restarts xray
at most once.
id: >-
delete-many-inbounds-in-one-call-processes-the-list-sequentially-failures-are-reported-per-id-and-the-rest-still-proceed-restarts-xray-at-most-once
- content: >-
Replace an inbounds configuration. Body shape mirrors /add. Heavy on
inbounds with thousands of clients — prefer /setEnable for enable-only
flips.
id: >-
replace-an-inbounds-configuration-body-shape-mirrors-add-heavy-on-inbounds-with-thousands-of-clients--prefer-setenable-for-enable-only-flips
- content: >-
Toggle only the enable flag without serialising the whole settings
JSON. Recommended for UI switches on large inbounds.
id: >-
toggle-only-the-enable-flag-without-serialising-the-whole-settings-json-recommended-for-ui-switches-on-large-inbounds
- content: >-
Zero out upload + download counters for a single inbound. Does not
touch per-client counters.
id: >-
zero-out-upload--download-counters-for-a-single-inbound-does-not-touch-per-client-counters
- content: >-
Remove every client attached to a single inbound while keeping the
inbound itself. Collects emails from settings.clients[] and feeds them
into the optimized bulk-delete path (runtime user removal +
traffic-row cleanup + SyncInbound). Destructive and cannot be undone.
id: >-
remove-every-client-attached-to-a-single-inbound-while-keeping-the-inbound-itself-collects-emails-from-settingsclients-and-feeds-them-into-the-optimized-bulk-delete-path-runtime-user-removal--traffic-row-cleanup--syncinbound-destructive-and-cannot-be-undone
- content: >-
Reset upload + download counters on every inbound. Destructive —
accounting history is lost.
id: >-
reset-upload--download-counters-on-every-inbound-destructive--accounting-history-is-lost
- content: >-
Bulk-import an inbound from a JSON blob (e.g. one exported via the
UI). The body uses form encoding with a single "data" field.
id: >-
bulk-import-an-inbound-from-a-json-blob-eg-one-exported-via-the-ui-the-body-uses-form-encoding-with-a-single-data-field
- content: >-
Receive a master panel's aggregated per-client usage, keyed by the
master's GUID. Stored in a side table used only for the UI display
overlay and local quota enforcement — never folded into the local
counters that masters poll, so delta accounting stays intact. Called
panel-to-panel by the node traffic sync job.
id: >-
receive-a-master-panels-aggregated-per-client-usage-keyed-by-the-masters-guid-stored-in-a-side-table-used-only-for-the-ui-display-overlay-and-local-quota-enforcement--never-folded-into-the-local-counters-that-masters-poll-so-delta-accounting-stays-intact-called-panel-to-panel-by-the-node-traffic-sync-job
- content: >-
List the fallback rules attached to a master VLESS/Trojan TCP-TLS
inbound. Each rule links one child inbound (the dest) to optional
SNI/ALPN/path/dest/xver match criteria. When dest is empty the child
inbound's listen+port is used.
id: >-
list-the-fallback-rules-attached-to-a-master-vlesstrojan-tcp-tls-inbound-each-rule-links-one-child-inbound-the-dest-to-optional-snialpnpathdestxver-match-criteria-when-dest-is-empty-the-child-inbounds-listenport-is-used
- content: >-
Replace the entire fallback list for a master inbound. Body is JSON.
Triggers an Xray restart.
id: >-
replace-the-entire-fallback-list-for-a-master-inbound-body-is-json-triggers-an-xray-restart
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/inbounds/list","method":"get"},{"path":"/panel/api/inbounds/list/slim","method":"get"},{"path":"/panel/api/inbounds/options","method":"get"},{"path":"/panel/api/inbounds/get/{id}","method":"get"},{"path":"/panel/api/inbounds/add","method":"post"},{"path":"/panel/api/inbounds/del/{id}","method":"post"},{"path":"/panel/api/inbounds/bulkDel","method":"post"},{"path":"/panel/api/inbounds/update/{id}","method":"post"},{"path":"/panel/api/inbounds/setEnable/{id}","method":"post"},{"path":"/panel/api/inbounds/{id}/resetTraffic","method":"post"},{"path":"/panel/api/inbounds/{id}/delAllClients","method":"post"},{"path":"/panel/api/inbounds/resetAllTraffics","method":"post"},{"path":"/panel/api/inbounds/import","method":"post"},{"path":"/panel/api/inbounds/pushClientTraffics","method":"post"},{"path":"/panel/api/inbounds/{id}/fallbacks","method":"get"},{"path":"/panel/api/inbounds/{id}/fallbacks","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,40 @@
---
title: مرجع API
description: REST API پنل 3x-ui — احراز هویت، inboundها، کلاینت‌ها، آمار سرور و موارد دیگر، تولیدشده از مشخصات OpenAPI.
icon: Webhook
---
پنل 3x-ui یک REST API برای خودکارسازی در اختیار می‌گذارد. این صفحات از مشخصات
OpenAPI پنل تولید شده‌اند، بنابراین همواره با اسکیمای مستندشده هماهنگ هستند.
## احراز هویت
درخواست‌ها یا با یک **کوکی نشست** (از `POST /login`) یا با یک
**توکن Bearer** احراز هویت می‌شوند:
```text
Authorization: Bearer <token>
```
توکن‌های API را در پنل بسازید؛ این توکن‌ها اعتبارنامه‌های ادمین کامل هستند، پس آن‌ها را
به‌صورت ایمن نگهداری کنید. به [توکن‌های API](/docs/reference/api/api-tokens) مراجعه کنید.
برای هر یک از endpointهای زیر یک درخواست احرازهویت‌شده بسازید:
<ApiRequestBuilder />
## مرور بر اساس حوزه
<Cards>
<Card title="احراز هویت" href="/docs/reference/api/authentication" />
<Card title="Inboundها" href="/docs/reference/api/inbounds" />
<Card title="کلاینت‌ها" href="/docs/reference/api/clients" />
<Card title="سرور" href="/docs/reference/api/server" />
<Card title="تنظیمات" href="/docs/reference/api/settings" />
<Card title="تنظیمات Xray" href="/docs/reference/api/xray-settings" />
</Cards>
<Callout type="info">
این مرجع با اجرای `pnpm gen:api` از `public/openapi.json` بازتولید می‌شود.
صفحات تگ تولیدشده را به‌صورت دستی ویرایش نکنید.
</Callout>
@@ -0,0 +1,19 @@
{
"title": "مرجع API",
"icon": "Webhook",
"pages": [
"index",
"authentication",
"api-tokens",
"inbounds",
"clients",
"server",
"settings",
"xray-settings",
"subscription-server",
"hosts",
"nodes",
"backup",
"websocket"
]
}
@@ -0,0 +1,183 @@
---
title: نودها
description: >-
مدیریت پنل‌های راه‌دور 3x-ui که به‌عنوان نود برای یک پنل مرکزی عمل می‌کنند. همهٔ
اندپوینت‌ها زیر مسیر /panel/api/nodes.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every configured node with its connection details, health, and last
heartbeat patch.
url: >-
#list-every-configured-node-with-its-connection-details-health-and-last-heartbeat-patch
- depth: 2
title: >-
This panel's node-auth CA certificate (public, PEM) to paste into a
node's mTLS trust setting. Lazily mints the CA and the master client
cert on first call. Pair with setting tlsVerifyMode=mtls on the node.
url: >-
#this-panels-node-auth-ca-certificate-public-pem-to-paste-into-a-nodes-mtls-trust-setting-lazily-mints-the-ca-and-the-master-client-cert-on-first-call-pair-with-setting-tlsverifymodemtls-on-the-node
- depth: 2
title: >-
Set the CA certificate this panel trusts for incoming node-API client
certificates (this panel acting as a node). Paste the managing panel's
CA (from nodes/mtls/ca). An empty caCert disables it. A non-empty value
must be a PEM certificate. Applied on the next panel restart.
url: >-
#set-the-ca-certificate-this-panel-trusts-for-incoming-node-api-client-certificates-this-panel-acting-as-a-node-paste-the-managing-panels-ca-from-nodesmtlsca-an-empty-cacert-disables-it-a-non-empty-value-must-be-a-pem-certificate-applied-on-the-next-panel-restart
- depth: 2
title: Fetch a single node by ID.
url: '#fetch-a-single-node-by-id'
- depth: 2
title: >-
Fetch a node's own web TLS certificate/key file paths (proxied to the
node). Used by the inbound form's "Set Cert from Panel" so a
node-assigned inbound gets paths that exist on the node, not the central
panel.
url: >-
#fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel
- depth: 2
title: >-
Register a new remote node. Provide its URL, apiToken, and optional
remark / allowPrivateAddress flag.
url: >-
#register-a-new-remote-node-provide-its-url-apitoken-and-optional-remark--allowprivateaddress-flag
- depth: 2
title: Replace a nodes connection details. Same body shape as /add.
url: '#replace-a-nodes-connection-details-same-body-shape-as-add'
- depth: 2
title: Delete a node. Inbounds bound to it are not auto-migrated.
url: '#delete-a-node-inbounds-bound-to-it-are-not-auto-migrated'
- depth: 2
title: Pause or resume traffic sync with this node.
url: '#pause-or-resume-traffic-sync-with-this-node'
- depth: 2
title: >-
Probe a node without saving it. Uses the body as connection details and
returns the same heartbeat snapshot a registered node would have.
url: >-
#probe-a-node-without-saving-it-uses-the-body-as-connection-details-and-returns-the-same-heartbeat-snapshot-a-registered-node-would-have
- depth: 2
title: >-
Connect to the node over HTTPS without verifying its certificate and
return the leaf certificate's SHA-256 (base64). Used by the Add/Edit
Node dialog to fetch and pin a self-signed certificate. Uses the same
body as /test.
url: >-
#connect-to-the-node-over-https-without-verifying-its-certificate-and-return-the-leaf-certificates-sha-256-base64-used-by-the-addedit-node-dialog-to-fetch-and-pin-a-self-signed-certificate-uses-the-same-body-as-test
- depth: 2
title: >-
Use unsaved node connection details to list the remote inbounds
available for selective import.
url: >-
#use-unsaved-node-connection-details-to-list-the-remote-inbounds-available-for-selective-import
- depth: 2
title: Probe an existing node, updating its cached health state.
url: '#probe-an-existing-node-updating-its-cached-health-state'
- depth: 2
title: >-
Trigger the official panel self-updater on each given node (downloads
the latest release and restarts). Only enabled, online nodes are
updated; offline/disabled ones are reported as skipped. Set "dev": true
to move the nodes to the rolling per-commit dev channel instead of the
latest stable release. Returns a per-node result list.
url: >-
#trigger-the-official-panel-self-updater-on-each-given-node-downloads-the-latest-release-and-restarts-only-enabled-online-nodes-are-updated-offlinedisabled-ones-are-reported-as-skipped-set-dev-true-to-move-the-nodes-to-the-rolling-per-commit-dev-channel-instead-of-the-latest-stable-release-returns-a-per-node-result-list
- depth: 2
title: >-
Aggregated metric history for a node — same shape as /server/history,
scoped to one node.
url: >-
#aggregated-metric-history-for-a-node--same-shape-as-serverhistory-scoped-to-one-node
structuredData:
headings:
- content: >-
List every configured node with its connection details, health, and
last heartbeat patch.
id: >-
list-every-configured-node-with-its-connection-details-health-and-last-heartbeat-patch
- content: >-
This panel's node-auth CA certificate (public, PEM) to paste into a
node's mTLS trust setting. Lazily mints the CA and the master client
cert on first call. Pair with setting tlsVerifyMode=mtls on the node.
id: >-
this-panels-node-auth-ca-certificate-public-pem-to-paste-into-a-nodes-mtls-trust-setting-lazily-mints-the-ca-and-the-master-client-cert-on-first-call-pair-with-setting-tlsverifymodemtls-on-the-node
- content: >-
Set the CA certificate this panel trusts for incoming node-API client
certificates (this panel acting as a node). Paste the managing panel's
CA (from nodes/mtls/ca). An empty caCert disables it. A non-empty
value must be a PEM certificate. Applied on the next panel restart.
id: >-
set-the-ca-certificate-this-panel-trusts-for-incoming-node-api-client-certificates-this-panel-acting-as-a-node-paste-the-managing-panels-ca-from-nodesmtlsca-an-empty-cacert-disables-it-a-non-empty-value-must-be-a-pem-certificate-applied-on-the-next-panel-restart
- content: Fetch a single node by ID.
id: fetch-a-single-node-by-id
- content: >-
Fetch a node's own web TLS certificate/key file paths (proxied to the
node). Used by the inbound form's "Set Cert from Panel" so a
node-assigned inbound gets paths that exist on the node, not the
central panel.
id: >-
fetch-a-nodes-own-web-tls-certificatekey-file-paths-proxied-to-the-node-used-by-the-inbound-forms-set-cert-from-panel-so-a-node-assigned-inbound-gets-paths-that-exist-on-the-node-not-the-central-panel
- content: >-
Register a new remote node. Provide its URL, apiToken, and optional
remark / allowPrivateAddress flag.
id: >-
register-a-new-remote-node-provide-its-url-apitoken-and-optional-remark--allowprivateaddress-flag
- content: Replace a nodes connection details. Same body shape as /add.
id: replace-a-nodes-connection-details-same-body-shape-as-add
- content: Delete a node. Inbounds bound to it are not auto-migrated.
id: delete-a-node-inbounds-bound-to-it-are-not-auto-migrated
- content: Pause or resume traffic sync with this node.
id: pause-or-resume-traffic-sync-with-this-node
- content: >-
Probe a node without saving it. Uses the body as connection details
and returns the same heartbeat snapshot a registered node would have.
id: >-
probe-a-node-without-saving-it-uses-the-body-as-connection-details-and-returns-the-same-heartbeat-snapshot-a-registered-node-would-have
- content: >-
Connect to the node over HTTPS without verifying its certificate and
return the leaf certificate's SHA-256 (base64). Used by the Add/Edit
Node dialog to fetch and pin a self-signed certificate. Uses the same
body as /test.
id: >-
connect-to-the-node-over-https-without-verifying-its-certificate-and-return-the-leaf-certificates-sha-256-base64-used-by-the-addedit-node-dialog-to-fetch-and-pin-a-self-signed-certificate-uses-the-same-body-as-test
- content: >-
Use unsaved node connection details to list the remote inbounds
available for selective import.
id: >-
use-unsaved-node-connection-details-to-list-the-remote-inbounds-available-for-selective-import
- content: Probe an existing node, updating its cached health state.
id: probe-an-existing-node-updating-its-cached-health-state
- content: >-
Trigger the official panel self-updater on each given node (downloads
the latest release and restarts). Only enabled, online nodes are
updated; offline/disabled ones are reported as skipped. Set "dev":
true to move the nodes to the rolling per-commit dev channel instead
of the latest stable release. Returns a per-node result list.
id: >-
trigger-the-official-panel-self-updater-on-each-given-node-downloads-the-latest-release-and-restarts-only-enabled-online-nodes-are-updated-offlinedisabled-ones-are-reported-as-skipped-set-dev-true-to-move-the-nodes-to-the-rolling-per-commit-dev-channel-instead-of-the-latest-stable-release-returns-a-per-node-result-list
- content: >-
Aggregated metric history for a node — same shape as /server/history,
scoped to one node.
id: >-
aggregated-metric-history-for-a-node--same-shape-as-serverhistory-scoped-to-one-node
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/nodes/list","method":"get"},{"path":"/panel/api/nodes/mtls/ca","method":"post"},{"path":"/panel/api/nodes/mtls/trustCA","method":"post"},{"path":"/panel/api/nodes/get/{id}","method":"get"},{"path":"/panel/api/nodes/webCert/{id}","method":"get"},{"path":"/panel/api/nodes/add","method":"post"},{"path":"/panel/api/nodes/update/{id}","method":"post"},{"path":"/panel/api/nodes/del/{id}","method":"post"},{"path":"/panel/api/nodes/setEnable/{id}","method":"post"},{"path":"/panel/api/nodes/test","method":"post"},{"path":"/panel/api/nodes/certFingerprint","method":"post"},{"path":"/panel/api/nodes/inbounds","method":"post"},{"path":"/panel/api/nodes/probe/{id}","method":"post"},{"path":"/panel/api/nodes/updatePanel","method":"post"},{"path":"/panel/api/nodes/history/{id}/{metric}/{bucket}","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,381 @@
---
title: سرور
description: >-
وضعیت سیستم، دریافت لاگ، تولیدکننده‌های گواهی، مدیریت باینری Xray و
پشتیبان‌گیری/بازیابی. همگی زیرمجموعهٔ /panel/api/server.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Real-time machine snapshot: CPU, memory, swap, disk, network IO, load
averages, open connections, Xray state. Cached and refreshed every 2
seconds in the background.
url: >-
#real-time-machine-snapshot-cpu-memory-swap-disk-network-io-load-averages-open-connections-xray-state-cached-and-refreshed-every-2-seconds-in-the-background
- depth: 2
title: >-
Reports whether per-client IP limits can be enforced on this host. The
panel uses it to gate the "IP Limit" field, since enforcement depends on
Fail2ban being installed.
url: >-
#reports-whether-per-client-ip-limits-can-be-enforced-on-this-host-the-panel-uses-it-to-gate-the-ip-limit-field-since-enforcement-depends-on-fail2ban-being-installed
- depth: 2
title: >-
Legacy: aggregated CPU history. Use /history/cpu/:bucket instead — same
data with a uniform {t, v} shape.
url: >-
#legacy-aggregated-cpu-history-use-historycpubucket-instead--same-data-with-a-uniform-t-v-shape
- depth: 2
title: >-
Aggregated time-series for one metric. Returns an array of {t, v}
samples covering the last ~6 hours.
url: >-
#aggregated-time-series-for-one-metric-returns-an-array-of-t-v-samples-covering-the-last-6-hours
- depth: 2
title: >-
Xray runtime metrics state — whether the xray config has a `metrics`
block, which expvar keys are flowing, and the current snapshot values
for each. Returns an empty state when metrics are not configured.
url: >-
#xray-runtime-metrics-state--whether-the-xray-config-has-a-metrics-block-which-expvar-keys-are-flowing-and-the-current-snapshot-values-for-each-returns-an-empty-state-when-metrics-are-not-configured
- depth: 2
title: >-
Time-series history for one Xray runtime metric over the last ~6 hours.
Same {t, v} shape as /history/:metric/:bucket.
url: >-
#time-series-history-for-one-xray-runtime-metric-over-the-last-6-hours-same-t-v-shape-as-historymetricbucket
- depth: 2
title: >-
Latest snapshot from the Xray observatory — per-outbound latency, health
status, and last-probe time. Only populated when the Xray config has an
observatory configured.
url: >-
#latest-snapshot-from-the-xray-observatory--per-outbound-latency-health-status-and-last-probe-time-only-populated-when-the-xray-config-has-an-observatory-configured
- depth: 2
title: >-
Time-series of observatory probe results for one outbound tag. Same {t,
v} shape as the other history endpoints.
url: >-
#time-series-of-observatory-probe-results-for-one-outbound-tag-same-t-v-shape-as-the-other-history-endpoints
- depth: 2
title: List Xray binary versions available for install on this host.
url: '#list-xray-binary-versions-available-for-install-on-this-host'
- depth: 2
title: Check whether a newer 3x-ui release is available on GitHub.
url: '#check-whether-a-newer-3x-ui-release-is-available-on-github'
- depth: 2
title: Return the assembled Xray config thats currently running on this host.
url: '#return-the-assembled-xray-config-thats-currently-running-on-this-host'
- depth: 2
title: >-
Stream the SQLite database file as an attachment. Use as a manual
backup.
url: '#stream-the-sqlite-database-file-as-an-attachment-use-as-a-manual-backup'
- depth: 2
title: >-
Stream a cross-engine migration file as an attachment: a .dump (SQL
text) on SQLite, or a .db SQLite database built from the live data on
PostgreSQL.
url: >-
#stream-a-cross-engine-migration-file-as-an-attachment-a-dump-sql-text-on-sqlite-or-a-db-sqlite-database-built-from-the-live-data-on-postgresql
- depth: 2
title: Generate a fresh UUID v4. Convenience helper for client IDs.
url: '#generate-a-fresh-uuid-v4-convenience-helper-for-client-ids'
- depth: 2
title: >-
Return this panel's own web TLS certificate and key file paths. The
central panel calls it on a node (via the node API token) so "Set Cert
from Panel" fills a node-assigned inbound with paths that exist on the
node.
url: >-
#return-this-panels-own-web-tls-certificate-and-key-file-paths-the-central-panel-calls-it-on-a-node-via-the-node-api-token-so-set-cert-from-panel-fills-a-node-assigned-inbound-with-paths-that-exist-on-the-node
- depth: 2
title: >-
Read-only summaries (guid, parentGuid, name, address, status, versions)
of the nodes this panel manages. A parent panel calls it on a node (via
the node API token) to surface transitive sub-nodes in a chained
topology. Counts are computed by the parent, not returned here.
url: >-
#read-only-summaries-guid-parentguid-name-address-status-versions-of-the-nodes-this-panel-manages-a-parent-panel-calls-it-on-a-node-via-the-node-api-token-to-surface-transitive-sub-nodes-in-a-chained-topology-counts-are-computed-by-the-parent-not-returned-here
- depth: 2
title: Generate a new X25519 keypair for Reality.
url: '#generate-a-new-x25519-keypair-for-reality'
- depth: 2
title: >-
Generate a new ML-DSA-65 keypair (post-quantum signature). Returns
{privateKey, publicKey, seed}.
url: >-
#generate-a-new-ml-dsa-65-keypair-post-quantum-signature-returns-privatekey-publickey-seed
- depth: 2
title: >-
Generate a new ML-KEM-768 keypair (post-quantum KEM). Returns
{clientKey, serverKey}.
url: >-
#generate-a-new-ml-kem-768-keypair-post-quantum-kem-returns-clientkey-serverkey
- depth: 2
title: >-
Generate VLESS encryption auth options. Returns an auths array each with
id, label, encryption, and decryption fields.
url: >-
#generate-vless-encryption-auth-options-returns-an-auths-array-each-with-id-label-encryption-and-decryption-fields
- depth: 2
title: Stop the Xray binary. All proxies go offline immediately.
url: '#stop-the-xray-binary-all-proxies-go-offline-immediately'
- depth: 2
title: >-
Reload Xray with the current config. Typically required after structural
inbound or routing changes.
url: >-
#reload-xray-with-the-current-config-typically-required-after-structural-inbound-or-routing-changes
- depth: 2
title: >-
Download and install the specified Xray version. Pass "latest" for the
newest release.
url: >-
#download-and-install-the-specified-xray-version-pass-latest-for-the-newest-release
- depth: 2
title: >-
Self-update the panel to the latest version. The server restarts on
success.
url: >-
#self-update-the-panel-to-the-latest-version-the-server-restarts-on-success
- depth: 2
title: >-
Toggle the panel update channel between stable and the rolling
per-commit dev release. Only effective on dev builds.
url: >-
#toggle-the-panel-update-channel-between-stable-and-the-rolling-per-commit-dev-release-only-effective-on-dev-builds
- depth: 2
title: >-
Refresh the default GeoIP / GeoSite data files. Body can include a
fileName, or use the /:fileName variant.
url: >-
#refresh-the-default-geoip--geosite-data-files-body-can-include-a-filename-or-use-the-filename-variant
- depth: 2
title: Refresh a single Geo file by filename (e.g. geoip.dat, geosite.dat).
url: '#refresh-a-single-geo-file-by-filename-eg-geoipdat-geositedat'
- depth: 2
title: Return the last N lines of the panels own log.
url: '#return-the-last-n-lines-of-the-panels-own-log'
- depth: 2
title: Return the last N lines of the Xray process log.
url: '#return-the-last-n-lines-of-the-xray-process-log'
- depth: 2
title: >-
Restore the panel DB from an uploaded SQLite file (multipart form, field
name "db"). The panel restarts after restore. Destructive.
url: >-
#restore-the-panel-db-from-an-uploaded-sqlite-file-multipart-form-field-name-db-the-panel-restarts-after-restore-destructive
- depth: 2
title: >-
Generate a new ECH (Encrypted Client Hello) keypair and config list for
the given SNI.
url: >-
#generate-a-new-ech-encrypted-client-hello-keypair-and-config-list-for-the-given-sni
- depth: 2
title: >-
Compute the hex SHA-256 of a certificate (DER) for pinning
(pinnedPeerCertSha256). Provide either a server file path or inline
PEM/DER content.
url: >-
#compute-the-hex-sha-256-of-a-certificate-der-for-pinning-pinnedpeercertsha256-provide-either-a-server-file-path-or-inline-pemder-content
- depth: 2
title: >-
Run `xray tls ping` against a remote server and return its live
leaf-certificate SHA-256 hash(es) for pinning (pinnedPeerCertSha256).
url: >-
#run-xray-tls-ping-against-a-remote-server-and-return-its-live-leaf-certificate-sha-256-hashes-for-pinning-pinnedpeercertsha256
- depth: 2
title: >-
Fetch the fully aggregated inbound_client_ips database table. Used by
nodes to sync recently active IPs across the cluster.
url: >-
#fetch-the-fully-aggregated-inbound_client_ips-database-table-used-by-nodes-to-sync-recently-active-ips-across-the-cluster
- depth: 2
title: >-
Submit a list of recently active IP timestamps. The panel merges them
with the existing database to maintain a unified global IP-limit view.
url: >-
#submit-a-list-of-recently-active-ip-timestamps-the-panel-merges-them-with-the-existing-database-to-maintain-a-unified-global-ip-limit-view
structuredData:
headings:
- content: >-
Real-time machine snapshot: CPU, memory, swap, disk, network IO, load
averages, open connections, Xray state. Cached and refreshed every 2
seconds in the background.
id: >-
real-time-machine-snapshot-cpu-memory-swap-disk-network-io-load-averages-open-connections-xray-state-cached-and-refreshed-every-2-seconds-in-the-background
- content: >-
Reports whether per-client IP limits can be enforced on this host. The
panel uses it to gate the "IP Limit" field, since enforcement depends
on Fail2ban being installed.
id: >-
reports-whether-per-client-ip-limits-can-be-enforced-on-this-host-the-panel-uses-it-to-gate-the-ip-limit-field-since-enforcement-depends-on-fail2ban-being-installed
- content: >-
Legacy: aggregated CPU history. Use /history/cpu/:bucket instead —
same data with a uniform {t, v} shape.
id: >-
legacy-aggregated-cpu-history-use-historycpubucket-instead--same-data-with-a-uniform-t-v-shape
- content: >-
Aggregated time-series for one metric. Returns an array of {t, v}
samples covering the last ~6 hours.
id: >-
aggregated-time-series-for-one-metric-returns-an-array-of-t-v-samples-covering-the-last-6-hours
- content: >-
Xray runtime metrics state — whether the xray config has a `metrics`
block, which expvar keys are flowing, and the current snapshot values
for each. Returns an empty state when metrics are not configured.
id: >-
xray-runtime-metrics-state--whether-the-xray-config-has-a-metrics-block-which-expvar-keys-are-flowing-and-the-current-snapshot-values-for-each-returns-an-empty-state-when-metrics-are-not-configured
- content: >-
Time-series history for one Xray runtime metric over the last ~6
hours. Same {t, v} shape as /history/:metric/:bucket.
id: >-
time-series-history-for-one-xray-runtime-metric-over-the-last-6-hours-same-t-v-shape-as-historymetricbucket
- content: >-
Latest snapshot from the Xray observatory — per-outbound latency,
health status, and last-probe time. Only populated when the Xray
config has an observatory configured.
id: >-
latest-snapshot-from-the-xray-observatory--per-outbound-latency-health-status-and-last-probe-time-only-populated-when-the-xray-config-has-an-observatory-configured
- content: >-
Time-series of observatory probe results for one outbound tag. Same
{t, v} shape as the other history endpoints.
id: >-
time-series-of-observatory-probe-results-for-one-outbound-tag-same-t-v-shape-as-the-other-history-endpoints
- content: List Xray binary versions available for install on this host.
id: list-xray-binary-versions-available-for-install-on-this-host
- content: Check whether a newer 3x-ui release is available on GitHub.
id: check-whether-a-newer-3x-ui-release-is-available-on-github
- content: >-
Return the assembled Xray config thats currently running on this
host.
id: return-the-assembled-xray-config-thats-currently-running-on-this-host
- content: >-
Stream the SQLite database file as an attachment. Use as a manual
backup.
id: >-
stream-the-sqlite-database-file-as-an-attachment-use-as-a-manual-backup
- content: >-
Stream a cross-engine migration file as an attachment: a .dump (SQL
text) on SQLite, or a .db SQLite database built from the live data on
PostgreSQL.
id: >-
stream-a-cross-engine-migration-file-as-an-attachment-a-dump-sql-text-on-sqlite-or-a-db-sqlite-database-built-from-the-live-data-on-postgresql
- content: Generate a fresh UUID v4. Convenience helper for client IDs.
id: generate-a-fresh-uuid-v4-convenience-helper-for-client-ids
- content: >-
Return this panel's own web TLS certificate and key file paths. The
central panel calls it on a node (via the node API token) so "Set Cert
from Panel" fills a node-assigned inbound with paths that exist on the
node.
id: >-
return-this-panels-own-web-tls-certificate-and-key-file-paths-the-central-panel-calls-it-on-a-node-via-the-node-api-token-so-set-cert-from-panel-fills-a-node-assigned-inbound-with-paths-that-exist-on-the-node
- content: >-
Read-only summaries (guid, parentGuid, name, address, status,
versions) of the nodes this panel manages. A parent panel calls it on
a node (via the node API token) to surface transitive sub-nodes in a
chained topology. Counts are computed by the parent, not returned
here.
id: >-
read-only-summaries-guid-parentguid-name-address-status-versions-of-the-nodes-this-panel-manages-a-parent-panel-calls-it-on-a-node-via-the-node-api-token-to-surface-transitive-sub-nodes-in-a-chained-topology-counts-are-computed-by-the-parent-not-returned-here
- content: Generate a new X25519 keypair for Reality.
id: generate-a-new-x25519-keypair-for-reality
- content: >-
Generate a new ML-DSA-65 keypair (post-quantum signature). Returns
{privateKey, publicKey, seed}.
id: >-
generate-a-new-ml-dsa-65-keypair-post-quantum-signature-returns-privatekey-publickey-seed
- content: >-
Generate a new ML-KEM-768 keypair (post-quantum KEM). Returns
{clientKey, serverKey}.
id: >-
generate-a-new-ml-kem-768-keypair-post-quantum-kem-returns-clientkey-serverkey
- content: >-
Generate VLESS encryption auth options. Returns an auths array each
with id, label, encryption, and decryption fields.
id: >-
generate-vless-encryption-auth-options-returns-an-auths-array-each-with-id-label-encryption-and-decryption-fields
- content: Stop the Xray binary. All proxies go offline immediately.
id: stop-the-xray-binary-all-proxies-go-offline-immediately
- content: >-
Reload Xray with the current config. Typically required after
structural inbound or routing changes.
id: >-
reload-xray-with-the-current-config-typically-required-after-structural-inbound-or-routing-changes
- content: >-
Download and install the specified Xray version. Pass "latest" for the
newest release.
id: >-
download-and-install-the-specified-xray-version-pass-latest-for-the-newest-release
- content: >-
Self-update the panel to the latest version. The server restarts on
success.
id: >-
self-update-the-panel-to-the-latest-version-the-server-restarts-on-success
- content: >-
Toggle the panel update channel between stable and the rolling
per-commit dev release. Only effective on dev builds.
id: >-
toggle-the-panel-update-channel-between-stable-and-the-rolling-per-commit-dev-release-only-effective-on-dev-builds
- content: >-
Refresh the default GeoIP / GeoSite data files. Body can include a
fileName, or use the /:fileName variant.
id: >-
refresh-the-default-geoip--geosite-data-files-body-can-include-a-filename-or-use-the-filename-variant
- content: Refresh a single Geo file by filename (e.g. geoip.dat, geosite.dat).
id: refresh-a-single-geo-file-by-filename-eg-geoipdat-geositedat
- content: Return the last N lines of the panels own log.
id: return-the-last-n-lines-of-the-panels-own-log
- content: Return the last N lines of the Xray process log.
id: return-the-last-n-lines-of-the-xray-process-log
- content: >-
Restore the panel DB from an uploaded SQLite file (multipart form,
field name "db"). The panel restarts after restore. Destructive.
id: >-
restore-the-panel-db-from-an-uploaded-sqlite-file-multipart-form-field-name-db-the-panel-restarts-after-restore-destructive
- content: >-
Generate a new ECH (Encrypted Client Hello) keypair and config list
for the given SNI.
id: >-
generate-a-new-ech-encrypted-client-hello-keypair-and-config-list-for-the-given-sni
- content: >-
Compute the hex SHA-256 of a certificate (DER) for pinning
(pinnedPeerCertSha256). Provide either a server file path or inline
PEM/DER content.
id: >-
compute-the-hex-sha-256-of-a-certificate-der-for-pinning-pinnedpeercertsha256-provide-either-a-server-file-path-or-inline-pemder-content
- content: >-
Run `xray tls ping` against a remote server and return its live
leaf-certificate SHA-256 hash(es) for pinning (pinnedPeerCertSha256).
id: >-
run-xray-tls-ping-against-a-remote-server-and-return-its-live-leaf-certificate-sha-256-hashes-for-pinning-pinnedpeercertsha256
- content: >-
Fetch the fully aggregated inbound_client_ips database table. Used by
nodes to sync recently active IPs across the cluster.
id: >-
fetch-the-fully-aggregated-inbound_client_ips-database-table-used-by-nodes-to-sync-recently-active-ips-across-the-cluster
- content: >-
Submit a list of recently active IP timestamps. The panel merges them
with the existing database to maintain a unified global IP-limit view.
id: >-
submit-a-list-of-recently-active-ip-timestamps-the-panel-merges-them-with-the-existing-database-to-maintain-a-unified-global-ip-limit-view
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/server/status","method":"get"},{"path":"/panel/api/server/fail2banStatus","method":"get"},{"path":"/panel/api/server/cpuHistory/{bucket}","method":"get"},{"path":"/panel/api/server/history/{metric}/{bucket}","method":"get"},{"path":"/panel/api/server/xrayMetricsState","method":"get"},{"path":"/panel/api/server/xrayMetricsHistory/{metric}/{bucket}","method":"get"},{"path":"/panel/api/server/xrayObservatory","method":"get"},{"path":"/panel/api/server/xrayObservatoryHistory/{tag}/{bucket}","method":"get"},{"path":"/panel/api/server/getXrayVersion","method":"get"},{"path":"/panel/api/server/getPanelUpdateInfo","method":"get"},{"path":"/panel/api/server/getConfigJson","method":"get"},{"path":"/panel/api/server/getDb","method":"get"},{"path":"/panel/api/server/getMigration","method":"get"},{"path":"/panel/api/server/getNewUUID","method":"get"},{"path":"/panel/api/server/getWebCertFiles","method":"get"},{"path":"/panel/api/server/descendants","method":"get"},{"path":"/panel/api/server/getNewX25519Cert","method":"get"},{"path":"/panel/api/server/getNewmldsa65","method":"get"},{"path":"/panel/api/server/getNewmlkem768","method":"get"},{"path":"/panel/api/server/getNewVlessEnc","method":"get"},{"path":"/panel/api/server/stopXrayService","method":"post"},{"path":"/panel/api/server/restartXrayService","method":"post"},{"path":"/panel/api/server/installXray/{version}","method":"post"},{"path":"/panel/api/server/updatePanel","method":"post"},{"path":"/panel/api/server/setUpdateChannel","method":"post"},{"path":"/panel/api/server/updateGeofile","method":"post"},{"path":"/panel/api/server/updateGeofile/{fileName}","method":"post"},{"path":"/panel/api/server/logs/{count}","method":"post"},{"path":"/panel/api/server/xraylogs/{count}","method":"post"},{"path":"/panel/api/server/importDB","method":"post"},{"path":"/panel/api/server/getNewEchCert","method":"post"},{"path":"/panel/api/server/getCertHash","method":"post"},{"path":"/panel/api/server/getRemoteCertHash","method":"post"},{"path":"/panel/api/server/clientIps","method":"get"},{"path":"/panel/api/server/clientIps","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,122 @@
---
title: تنظیمات
description: >-
پیکربندی پنل و اطلاعات ورود کاربر. همه‌ی نقاط پایانی زیر /panel/api/setting
قرار دارند و به یک نشست واردشده یا توکن Bearer نیاز دارند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Return every panel setting: web server, Telegram bot, subscription,
security, LDAP. The full JSON blob that the Settings page edits.
url: >-
#return-every-panel-setting-web-server-telegram-bot-subscription-security-ldap-the-full-json-blob-that-the-settings-page-edits
- depth: 2
title: >-
Return the computed default settings based on the request host. Useful
to preview what a fresh install would use.
url: >-
#return-the-computed-default-settings-based-on-the-request-host-useful-to-preview-what-a-fresh-install-would-use
- depth: 2
title: >-
Persist every setting at once. The body mirrors the shape returned by
/all. Invalid values (bad ports, missing cert pairs, etc.) are rejected
before write.
url: >-
#persist-every-setting-at-once-the-body-mirrors-the-shape-returned-by-all-invalid-values-bad-ports-missing-cert-pairs-etc-are-rejected-before-write
- depth: 2
title: >-
Change the panel admin username and password. Requires the current
credentials for verification. The session is refreshed with the new
values on success.
url: >-
#change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success
- depth: 2
title: >-
Restart the entire 3x-ui process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10 seconds
later.
url: >-
#restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
- depth: 2
title: >-
Test SMTP connection with stage-by-stage reporting (connect, auth,
send). Returns structured result with stage and message.
url: >-
#test-smtp-connection-with-stage-by-stage-reporting-connect-auth-send-returns-structured-result-with-stage-and-message
- depth: 2
title: >-
Test Telegram bot connection by sending a test message to the configured
chat.
url: >-
#test-telegram-bot-connection-by-sending-a-test-message-to-the-configured-chat
- depth: 2
title: >-
Return the built-in default Xray JSON config template that ships with
this panel version.
url: >-
#return-the-built-in-default-xray-json-config-template-that-ships-with-this-panel-version
structuredData:
headings:
- content: >-
Return every panel setting: web server, Telegram bot, subscription,
security, LDAP. The full JSON blob that the Settings page edits.
id: >-
return-every-panel-setting-web-server-telegram-bot-subscription-security-ldap-the-full-json-blob-that-the-settings-page-edits
- content: >-
Return the computed default settings based on the request host. Useful
to preview what a fresh install would use.
id: >-
return-the-computed-default-settings-based-on-the-request-host-useful-to-preview-what-a-fresh-install-would-use
- content: >-
Persist every setting at once. The body mirrors the shape returned by
/all. Invalid values (bad ports, missing cert pairs, etc.) are
rejected before write.
id: >-
persist-every-setting-at-once-the-body-mirrors-the-shape-returned-by-all-invalid-values-bad-ports-missing-cert-pairs-etc-are-rejected-before-write
- content: >-
Change the panel admin username and password. Requires the current
credentials for verification. The session is refreshed with the new
values on success.
id: >-
change-the-panel-admin-username-and-password-requires-the-current-credentials-for-verification-the-session-is-refreshed-with-the-new-values-on-success
- content: >-
Restart the entire 3x-ui process after a 3-second grace period. The
connection drops immediately; the panel comes back online ~5-10
seconds later.
id: >-
restart-the-entire-3x-ui-process-after-a-3-second-grace-period-the-connection-drops-immediately-the-panel-comes-back-online-5-10-seconds-later
- content: >-
Test SMTP connection with stage-by-stage reporting (connect, auth,
send). Returns structured result with stage and message.
id: >-
test-smtp-connection-with-stage-by-stage-reporting-connect-auth-send-returns-structured-result-with-stage-and-message
- content: >-
Test Telegram bot connection by sending a test message to the
configured chat.
id: >-
test-telegram-bot-connection-by-sending-a-test-message-to-the-configured-chat
- content: >-
Return the built-in default Xray JSON config template that ships with
this panel version.
id: >-
return-the-built-in-default-xray-json-config-template-that-ships-with-this-panel-version
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/setting/all","method":"post"},{"path":"/panel/api/setting/defaultSettings","method":"post"},{"path":"/panel/api/setting/update","method":"post"},{"path":"/panel/api/setting/updateUser","method":"post"},{"path":"/panel/api/setting/restartPanel","method":"post"},{"path":"/panel/api/setting/testSmtp","method":"post"},{"path":"/panel/api/setting/testTgBot","method":"post"},{"path":"/panel/api/setting/getDefaultJsonConfig","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,73 @@
---
title: سرور اشتراک
description: >-
یک سرور HTTP/HTTPS جداگانه که لینک‌های اشتراک پراکسی (استاندارد، JSON و Clash)
را به کلاینت‌ها ارائه می‌دهد. این سرور روی پورت اختصاصی خودش (به‌صورت پیش‌فرض
10882) گوش می‌دهد و در بخش Settings ← Subscription پیکربندی می‌شود. مسیرها قابل
پیکربندی هستند؛ مقادیر پیش‌فرض در ادامه نشان داده شده‌اند. همه‌ی نقاط پایانی
اشتراک، هدرهای پاسخ را برای خواندن اطلاعات ترافیک/انقضا توسط برنامه‌های کلاینت
تنظیم می‌کنند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Return base64-encoded subscription links for all enabled clients
matching the subscription ID. When the request has an Accept: text/html
header or ?html=1, renders a styled info page instead. Default path:
/sub/:subid.
url: >-
#return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-default-path-subsubid
- depth: 2
title: >-
Return subscription as a JSON array of proxy configs (one per enabled
client). Only when JSON subscription is enabled in settings. Default
path: /json/:subid.
url: >-
#return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-default-path-jsonsubid
- depth: 2
title: >-
Return subscription as a Clash/Mihomo-compatible YAML config, including
configured global Clash routing rules. Only when Clash subscription is
enabled in settings. Default path: /clash/:subid.
url: >-
#return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-default-path-clashsubid
structuredData:
headings:
- content: >-
Return base64-encoded subscription links for all enabled clients
matching the subscription ID. When the request has an Accept:
text/html header or ?html=1, renders a styled info page instead.
Default path: /sub/:subid.
id: >-
return-base64-encoded-subscription-links-for-all-enabled-clients-matching-the-subscription-id-when-the-request-has-an-accept-texthtml-header-or-html1-renders-a-styled-info-page-instead-default-path-subsubid
- content: >-
Return subscription as a JSON array of proxy configs (one per enabled
client). Only when JSON subscription is enabled in settings. Default
path: /json/:subid.
id: >-
return-subscription-as-a-json-array-of-proxy-configs-one-per-enabled-client-only-when-json-subscription-is-enabled-in-settings-default-path-jsonsubid
- content: >-
Return subscription as a Clash/Mihomo-compatible YAML config,
including configured global Clash routing rules. Only when Clash
subscription is enabled in settings. Default path: /clash/:subid.
id: >-
return-subscription-as-a-clashmihomo-compatible-yaml-config-including-configured-global-clash-routing-rules-only-when-clash-subscription-is-enabled-in-settings-default-path-clashsubid
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/{subPath}{subid}","method":"get"},{"path":"/{jsonPath}{subid}","method":"get"},{"path":"/{clashPath}{subid}","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,46 @@
---
title: WebSocket
description: >-
دریافت به‌روزرسانی‌های وضعیت در لحظه از طریق WebSocket. تنها یک‌بار به
<code>ws://<panel>/ws</code> متصل شوید تا بدون نیاز به polling، جریانی از
پیام‌های JSON دریافت کنید. به یک کوکی نشست احرازهویت‌شده نیاز دارد (احرازهویت با
توکن Bearer پشتیبانی نمی‌شود). هر پیام دارای یک فیلد <code>type</code> است که
شکل داده‌ی آن را مشخص می‌کند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Upgrade an HTTP connection to a WebSocket. Requires an authenticated
session cookie (Bearer token auth is not supported here). Returns 101
Switching Protocols on success. The server then pushes JSON messages
described below.
url: >-
#upgrade-an-http-connection-to-a-websocket-requires-an-authenticated-session-cookie-bearer-token-auth-is-not-supported-here-returns-101-switching-protocols-on-success-the-server-then-pushes-json-messages-described-below
structuredData:
headings:
- content: >-
Upgrade an HTTP connection to a WebSocket. Requires an authenticated
session cookie (Bearer token auth is not supported here). Returns 101
Switching Protocols on success. The server then pushes JSON messages
described below.
id: >-
upgrade-an-http-connection-to-a-websocket-requires-an-authenticated-session-cookie-bearer-token-auth-is-not-supported-here-returns-101-switching-protocols-on-success-the-server-then-pushes-json-messages-described-below
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/ws","method":"get"}]} showTitle />
</>
);
}
@@ -0,0 +1,257 @@
---
title: تنظیمات Xray
description: >-
قالب پیکربندی Xray، مدیریت outboundها، یکپارچه‌سازی Warp/Nord و آزمایش
پیکربندی. همه‌ی نقاط پایانی زیر /panel/api/xray قرار دارند.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
Return the Xray config template (JSON string), available inbound tags,
client reverse tags, and the configured outbound test URL in one
response.
url: >-
#return-the-xray-config-template-json-string-available-inbound-tags-client-reverse-tags-and-the-configured-outbound-test-url-in-one-response
- depth: 2
title: >-
Return the built-in default Xray config shipped with the panel
(identical to /panel/api/setting/getDefaultJsonConfig).
url: >-
#return-the-built-in-default-xray-config-shipped-with-the-panel-identical-to-panelapisettinggetdefaultjsonconfig
- depth: 2
title: >-
Return traffic statistics for every outbound. Each outbound shows
up/down/total counters.
url: >-
#return-traffic-statistics-for-every-outbound-each-outbound-shows-updowntotal-counters
- depth: 2
title: >-
Return the most recent Xray process stdout/stderr output. Useful to
check for startup errors or runtime warnings.
url: >-
#return-the-most-recent-xray-process-stdoutstderr-output-useful-to-check-for-startup-errors-or-runtime-warnings
- depth: 2
title: >-
Save the Xray JSON config template and optionally the outbound test URL.
Both are sent as form fields.
url: >-
#save-the-xray-json-config-template-and-optionally-the-outbound-test-url-both-are-sent-as-form-fields
- depth: 2
title: >-
Manage Cloudflare Warp integration. The action parameter selects the
operation.
url: >-
#manage-cloudflare-warp-integration-the-action-parameter-selects-the-operation
- depth: 2
title: Manage NordVPN integration. The action parameter selects the operation.
url: '#manage-nordvpn-integration-the-action-parameter-selects-the-operation'
- depth: 2
title: Reset traffic counters for a specific outbound by tag.
url: '#reset-traffic-counters-for-a-specific-outbound-by-tag'
- depth: 2
title: >-
Test an outbound configuration. Sends the outbound JSON (required),
optionally all outbounds (to resolve sockopt.dialerProxy dependencies),
and a mode flag.
url: >-
#test-an-outbound-configuration-sends-the-outbound-json-required-optionally-all-outbounds-to-resolve-sockoptdialerproxy-dependencies-and-a-mode-flag
- depth: 2
title: >-
Test a batch of outbounds (max 50) through one shared temp xray
instance. Returns an array of results in input order, each with the
outbound tag, delay, HTTP status and a connect/TLS/TTFB timing
breakdown.
url: >-
#test-a-batch-of-outbounds-max-50-through-one-shared-temp-xray-instance-returns-an-array-of-results-in-input-order-each-with-the-outbound-tag-delay-http-status-and-a-connecttlsttfb-timing-breakdown
- depth: 2
title: >-
Live state of routing balancers in the running core
(RoutingService.GetBalancerInfo): current override and the targets the
strategy prefers. Returns a map keyed by balancer tag.
url: >-
#live-state-of-routing-balancers-in-the-running-core-routingservicegetbalancerinfo-current-override-and-the-targets-the-strategy-prefers-returns-a-map-keyed-by-balancer-tag
- depth: 2
title: >-
Force a balancer in the running core to always pick one outbound
(RoutingService.OverrideBalancerTarget). Applied live without a restart;
cleared automatically when Xray restarts.
url: >-
#force-a-balancer-in-the-running-core-to-always-pick-one-outbound-routingserviceoverridebalancertarget-applied-live-without-a-restart-cleared-automatically-when-xray-restarts
- depth: 2
title: >-
Ask the running core which outbound its router would pick for a
synthetic connection (RoutingService.TestRoute). No traffic is sent.
url: >-
#ask-the-running-core-which-outbound-its-router-would-pick-for-a-synthetic-connection-routingservicetestroute-no-traffic-is-sent
- depth: 2
title: >-
List all outbound subscriptions (remote URLs that supply additional
outbounds), newest first.
url: >-
#list-all-outbound-subscriptions-remote-urls-that-supply-additional-outbounds-newest-first
- depth: 2
title: >-
Create an outbound subscription. The URL is fetched, parsed into
outbounds with stable tags, and merged additively into the running Xray
config.
url: >-
#create-an-outbound-subscription-the-url-is-fetched-parsed-into-outbounds-with-stable-tags-and-merged-additively-into-the-running-xray-config
- depth: 2
title: >-
Update an existing outbound subscription by id. Accepts the same form
fields as create.
url: >-
#update-an-existing-outbound-subscription-by-id-accepts-the-same-form-fields-as-create
- depth: 2
title: Delete an outbound subscription by id.
url: '#delete-an-outbound-subscription-by-id'
- depth: 2
title: >-
Delete an outbound subscription by id (POST alias of DELETE for
axios-friendly clients).
url: >-
#delete-an-outbound-subscription-by-id-post-alias-of-delete-for-axios-friendly-clients
- depth: 2
title: >-
Force an immediate re-fetch of the subscription and return the parsed
outbounds. Signals Xray to reload.
url: >-
#force-an-immediate-re-fetch-of-the-subscription-and-return-the-parsed-outbounds-signals-xray-to-reload
- depth: 2
title: >-
Reorder a subscription one step up or down in priority (controls its
position in the merged outbounds).
url: >-
#reorder-a-subscription-one-step-up-or-down-in-priority-controls-its-position-in-the-merged-outbounds
- depth: 2
title: >-
Preview a subscription URL: fetch and parse it into outbounds without
persisting anything.
url: >-
#preview-a-subscription-url-fetch-and-parse-it-into-outbounds-without-persisting-anything
structuredData:
headings:
- content: >-
Return the Xray config template (JSON string), available inbound tags,
client reverse tags, and the configured outbound test URL in one
response.
id: >-
return-the-xray-config-template-json-string-available-inbound-tags-client-reverse-tags-and-the-configured-outbound-test-url-in-one-response
- content: >-
Return the built-in default Xray config shipped with the panel
(identical to /panel/api/setting/getDefaultJsonConfig).
id: >-
return-the-built-in-default-xray-config-shipped-with-the-panel-identical-to-panelapisettinggetdefaultjsonconfig
- content: >-
Return traffic statistics for every outbound. Each outbound shows
up/down/total counters.
id: >-
return-traffic-statistics-for-every-outbound-each-outbound-shows-updowntotal-counters
- content: >-
Return the most recent Xray process stdout/stderr output. Useful to
check for startup errors or runtime warnings.
id: >-
return-the-most-recent-xray-process-stdoutstderr-output-useful-to-check-for-startup-errors-or-runtime-warnings
- content: >-
Save the Xray JSON config template and optionally the outbound test
URL. Both are sent as form fields.
id: >-
save-the-xray-json-config-template-and-optionally-the-outbound-test-url-both-are-sent-as-form-fields
- content: >-
Manage Cloudflare Warp integration. The action parameter selects the
operation.
id: >-
manage-cloudflare-warp-integration-the-action-parameter-selects-the-operation
- content: >-
Manage NordVPN integration. The action parameter selects the
operation.
id: manage-nordvpn-integration-the-action-parameter-selects-the-operation
- content: Reset traffic counters for a specific outbound by tag.
id: reset-traffic-counters-for-a-specific-outbound-by-tag
- content: >-
Test an outbound configuration. Sends the outbound JSON (required),
optionally all outbounds (to resolve sockopt.dialerProxy
dependencies), and a mode flag.
id: >-
test-an-outbound-configuration-sends-the-outbound-json-required-optionally-all-outbounds-to-resolve-sockoptdialerproxy-dependencies-and-a-mode-flag
- content: >-
Test a batch of outbounds (max 50) through one shared temp xray
instance. Returns an array of results in input order, each with the
outbound tag, delay, HTTP status and a connect/TLS/TTFB timing
breakdown.
id: >-
test-a-batch-of-outbounds-max-50-through-one-shared-temp-xray-instance-returns-an-array-of-results-in-input-order-each-with-the-outbound-tag-delay-http-status-and-a-connecttlsttfb-timing-breakdown
- content: >-
Live state of routing balancers in the running core
(RoutingService.GetBalancerInfo): current override and the targets the
strategy prefers. Returns a map keyed by balancer tag.
id: >-
live-state-of-routing-balancers-in-the-running-core-routingservicegetbalancerinfo-current-override-and-the-targets-the-strategy-prefers-returns-a-map-keyed-by-balancer-tag
- content: >-
Force a balancer in the running core to always pick one outbound
(RoutingService.OverrideBalancerTarget). Applied live without a
restart; cleared automatically when Xray restarts.
id: >-
force-a-balancer-in-the-running-core-to-always-pick-one-outbound-routingserviceoverridebalancertarget-applied-live-without-a-restart-cleared-automatically-when-xray-restarts
- content: >-
Ask the running core which outbound its router would pick for a
synthetic connection (RoutingService.TestRoute). No traffic is sent.
id: >-
ask-the-running-core-which-outbound-its-router-would-pick-for-a-synthetic-connection-routingservicetestroute-no-traffic-is-sent
- content: >-
List all outbound subscriptions (remote URLs that supply additional
outbounds), newest first.
id: >-
list-all-outbound-subscriptions-remote-urls-that-supply-additional-outbounds-newest-first
- content: >-
Create an outbound subscription. The URL is fetched, parsed into
outbounds with stable tags, and merged additively into the running
Xray config.
id: >-
create-an-outbound-subscription-the-url-is-fetched-parsed-into-outbounds-with-stable-tags-and-merged-additively-into-the-running-xray-config
- content: >-
Update an existing outbound subscription by id. Accepts the same form
fields as create.
id: >-
update-an-existing-outbound-subscription-by-id-accepts-the-same-form-fields-as-create
- content: Delete an outbound subscription by id.
id: delete-an-outbound-subscription-by-id
- content: >-
Delete an outbound subscription by id (POST alias of DELETE for
axios-friendly clients).
id: >-
delete-an-outbound-subscription-by-id-post-alias-of-delete-for-axios-friendly-clients
- content: >-
Force an immediate re-fetch of the subscription and return the parsed
outbounds. Signals Xray to reload.
id: >-
force-an-immediate-re-fetch-of-the-subscription-and-return-the-parsed-outbounds-signals-xray-to-reload
- content: >-
Reorder a subscription one step up or down in priority (controls its
position in the merged outbounds).
id: >-
reorder-a-subscription-one-step-up-or-down-in-priority-controls-its-position-in-the-merged-outbounds
- content: >-
Preview a subscription URL: fetch and parse it into outbounds without
persisting anything.
id: >-
preview-a-subscription-url-fetch-and-parse-it-into-outbounds-without-persisting-anything
contents: []
---
{/* This file was generated by Fumadocs. Do not edit this file directly. Any changes should be made by running the generation command again. */}
export default function Layout(props) {
const { APIPage, OpenAPIPage } = props.components ?? {};
// "APIPage" is the old name from v10, this allows both for backward compatibility
const Comp = OpenAPIPage ?? APIPage;
return (
<>
{props.children}
<Comp document="./public/openapi.json" webhooks={[]} operations={[{"path":"/panel/api/xray/","method":"post"},{"path":"/panel/api/xray/getDefaultJsonConfig","method":"get"},{"path":"/panel/api/xray/getOutboundsTraffic","method":"get"},{"path":"/panel/api/xray/getXrayResult","method":"get"},{"path":"/panel/api/xray/update","method":"post"},{"path":"/panel/api/xray/warp/{action}","method":"post"},{"path":"/panel/api/xray/nord/{action}","method":"post"},{"path":"/panel/api/xray/resetOutboundsTraffic","method":"post"},{"path":"/panel/api/xray/testOutbound","method":"post"},{"path":"/panel/api/xray/testOutbounds","method":"post"},{"path":"/panel/api/xray/balancerStatus","method":"post"},{"path":"/panel/api/xray/balancerOverride","method":"post"},{"path":"/panel/api/xray/routeTest","method":"post"},{"path":"/panel/api/xray/outbound-subs","method":"get"},{"path":"/panel/api/xray/outbound-subs","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}","method":"delete"},{"path":"/panel/api/xray/outbound-subs/{id}/del","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}/refresh","method":"post"},{"path":"/panel/api/xray/outbound-subs/{id}/move","method":"post"},{"path":"/panel/api/xray/outbound-subs/parse","method":"post"}]} showTitle />
</>
);
}
@@ -0,0 +1,65 @@
---
title: پایگاه داده
description: بک‌اندهای ذخیره‌سازی 3x-ui — SQLite (پیش‌فرض) و PostgreSQL — مسیر پایگاه داده، استخر اتصال و مهاجرت از SQLite به PostgreSQL.
icon: Database
---
3x-ui همه چیز را — inboundها، کلاینت‌ها و تنظیمات — در یک پایگاه داده ذخیره می‌کند.
بک‌اند را هنگام نصب انتخاب می‌کنید؛ هر دو کاملاً پشتیبانی می‌شوند.
## SQLite (پیش‌فرض)
یک فایل واحد در مسیر `/etc/x-ui/x-ui.db`. بدون نیاز به هیچ راه‌اندازی، ایده‌آل برای
استقرارهای کوچک و متوسط. این پوشه با
[`XUI_DB_FOLDER`](/docs/reference/env-vars#database) قابل تنظیم است (در ویندوز به‌طور
پیش‌فرض کنار فایل اجرایی قرار می‌گیرد).
## PostgreSQL
برای تعداد بالای کلاینت‌ها یا راه‌اندازی‌های چندنودی توصیه می‌شود. نصب‌کننده می‌تواند
PostgreSQL را به‌صورت محلی برای شما نصب کند، یا یک DSN به سروری موجود را بپذیرد. در زمان
اجرا بک‌اند از طریق متغیرهای محیطی انتخاب می‌شود که نصب‌کننده آن‌ها را در
`/etc/default/x-ui` می‌نویسد:
```bash title="/etc/default/x-ui"
XUI_DB_TYPE=postgres
XUI_DB_DSN=postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable
```
استخر اتصال را با `XUI_DB_MAX_OPEN_CONNS` و
`XUI_DB_MAX_IDLE_CONNS` تنظیم کنید.
### Docker
دستور `docker compose up -d` همچنان از SQLite استفاده می‌کند. برای اجرا با سرویس
PostgreSQL همراه، دو خط `XUI_DB_*` را در `docker-compose.yml` از حالت کامنت خارج کنید و
با این پروفایل اجرا کنید:
```bash
docker compose --profile postgres up -d
```
## مهاجرت از SQLite به PostgreSQL
یک نصب موجود SQLite را با دستور داخلی به PostgreSQL منتقل کنید:
```bash
x-ui migrate-db --dsn "postgres://xui:password@127.0.0.1:5432/xui?sslmode=disable"
```
سپس `XUI_DB_TYPE` و `XUI_DB_DSN` را در `/etc/default/x-ui` تنظیم کرده و سرویس را مجدداً
راه‌اندازی کنید:
```bash
systemctl restart x-ui
```
<Callout type="info">
فایل مبدأ SQLite دست‌نخورده باقی می‌ماند — آن را تنها پس از اینکه از کارکرد صحیح
بک‌اند جدید مطمئن شدید، به‌صورت دستی حذف کنید.
</Callout>
## پشتیبان‌گیری
از هر بک‌اندی که استفاده می‌کنید، به‌طور منظم از آن پشتیبان بگیرید — به
[پشتیبان‌گیری و بازیابی](/docs/operations/backup-restore) مراجعه کنید.
@@ -0,0 +1,85 @@
---
title: متغیرهای محیطی
description: مرجع کامل متغیرهای محیطی ‎`XUI_*`‎ در 3x-ui — پایگاه‌داده، پنل، لاگ‌گیری، حافظه و پایشگر سلامت تونل.
icon: Variable
---
‏3x-ui پیکربندی زمان‌اجرای خود را از متغیرهای محیطی `XUI_*` می‌خواند. در نصب
اسکریپتی، نصب‌کننده آن‌ها را در فایل محیطی سرویس می‌نویسد
(`/etc/default/x-ui`، یا بسته به توزیع `/etc/conf.d/x-ui` / `/etc/sysconfig/x-ui`)؛
برای Docker آن‌ها را در `docker-compose.yml` یا `docker run -e` تنظیم می‌کنید.
مقادیر پیش‌فرض منطقی هستند — فقط آنچه را که نیاز به تغییر دارید تنظیم کنید، سپس
ری‌استارت کنید: `systemctl restart x-ui`.
## پایگاه‌داده
| Variable | Default | Description |
| ------------------------ | ----------- | -------------------------------------------------------------------- |
| `XUI_DB_TYPE` | `sqlite` | بک‌اند: `sqlite`، یا `postgres` (همچنین `postgresql` / `pg` را می‌پذیرد). |
| `XUI_DB_FOLDER` | `/etc/x-ui` | پوشه‌ی فایل پایگاه‌داده‌ی SQLite (`x-ui.db`). |
| `XUI_DB_DSN` | — | رشته‌ی اتصال PostgreSQL (وقتی `XUI_DB_TYPE=postgres` باشد استفاده می‌شود). |
| `XUI_DB_MAX_OPEN_CONNS` | — | حداکثر اتصالات باز در استخر PostgreSQL. |
| `XUI_DB_MAX_IDLE_CONNS` | — | حداکثر اتصالات بی‌کار در استخر PostgreSQL. |
مسیر پیش‌فرض پایگاه‌داده‌ی SQLite برابر `/etc/x-ui/x-ui.db` است. برای جزئیات
SQLite ↔ PostgreSQL به [پایگاه‌داده](/docs/reference/database) مراجعه کنید.
## پنل
| Variable | Default | Description |
| ------------------------ | ------- | ------------------------------------------------------------------------ |
| `XUI_PORT` | — | بازنویسی پورت پنل (۱ تا ۶۵۵۳۵). بر تنظیم ذخیره‌شده اولویت دارد. |
| `XUI_INIT_WEB_BASE_PATH` | `/` | مسیر پایه‌ی وب اولیه در **نخستین** اجرا (مثلاً `/panel`). |
| `XUI_ENABLE_FAIL2BAN` | `true` | فعال‌سازی اعمالِ محدودیت IP مبتنی بر Fail2ban. |
| `XUI_SKIP_HSTS` | `false` | رد کردن هدر HSTS — وقتی TLS توسط یک پروکسی معکوس خاتمه می‌یابد، `true` تنظیم کنید. |
## لاگ‌گیری و باینری‌ها
| Variable | Default | Description |
| ---------------- | ---------------- | ----------------------------------------------------------- |
| `XUI_LOG_LEVEL` | `info` | `debug`، `info`، `notice`، `warning`، یا `error`. |
| `XUI_DEBUG` | `false` | حالت دیباگ (سطح لاگ را به `debug` وادار می‌کند). |
| `XUI_LOG_FOLDER` | `/var/log/x-ui` | پوشه‌ی خروجی لاگ. |
| `XUI_BIN_FOLDER` | `bin` | پوشه‌ی باینری Xray-core و فایل‌های geosite/geoip. |
## حافظه و پروفایلینگ
پنل با استفاده از `GOGC` و آزادسازی‌های دوره‌ای، مصرف حافظه را پایین نگه می‌دارد.
این‌ها تنظیمات پیشرفته‌ای هستند — مگر اینکه در حال تنظیم دقیق یک میزبان با منابع
محدود باشید، آن‌ها را تنظیم‌نشده رها کنید.
| Variable | Default | Description |
| ----------------------------- | ------- | ----------------------------------------------------------------- |
| `XUI_GOGC` | — | درصد هدف GC در Go؛ کمتر = RAM کمتر، CPU اندکی بیشتر. |
| `XUI_MEMORY_RELEASE_INTERVAL` | — | فاصله‌ی زمانی فراخوانی‌های `FreeOSMemory` بر حسب دقیقه؛ مقدار `0` آن را غیرفعال می‌کند. |
| `XUI_MEMORY_LIMIT` | — | محدودیت نرم حافظه‌ی Go بر حسب **MiB**. |
| `GOMEMLIMIT` | — | محدودیت نرم با نحو Go (مثلاً `400MiB`)؛ بر مورد بالا اولویت دارد.|
| `XUI_PPROF` | `false` | در دسترس قرار دادن پروفایلینگ pprof روی `127.0.0.1:6060`. |
## Xray
| Variable | Default | Description |
| ------------------------ | ------- | --------------------- |
| `XRAY_VMESS_AEAD_FORCED` | `false` | الزامی‌کردن VMess AEAD. |
## پایشگر سلامت تونل
نگهبان اختیاری: یک URL را پروب می‌کند (به‌صورت اختیاری **از طریق** یک ورودی محلی
‏Xray) و پس از خرابی‌های مکرر، Xray را ری‌استارت می‌کند. هر ری‌استارت همه‌ی
کلاینت‌های متصل را قطع می‌کند، پس آن را آگاهانه فعال کنید.
| Variable | Default | Description |
| ----------------------------- | -------------------------------------------- | ----------------------------------------------------------------- |
| `XUI_TUNNEL_HEALTH_MONITOR` | `false` | فعال‌سازی پایشگر. |
| `XUI_TUNNEL_HEALTH_PROXY` | — | پروکسی‌ای که پروب از طریق آن ارسال می‌شود، مثلاً `socks5://127.0.0.1:1080`. خالی = فقط اتصال میزبان را بررسی می‌کند. |
| `XUI_TUNNEL_HEALTH_URL` | `https://www.cloudflare.com/cdn-cgi/trace` | URLی که پروب می‌شود. |
| `XUI_TUNNEL_HEALTH_INTERVAL` | `30s` | فاصله‌ی زمانی بین پروب‌ها. |
| `XUI_TUNNEL_HEALTH_TIMEOUT` | `10s` | مهلت زمانی هر پروب. |
| `XUI_TUNNEL_HEALTH_FAILURES` | `3` | تعداد خرابی‌های متوالی پیش از یک ری‌استارت. |
| `XUI_TUNNEL_HEALTH_COOLDOWN` | `5m` | حداقل تأخیر بین ری‌استارت‌ها. |
## نصب بدون نظارت
| Variable | Description |
| -------------------- | -------------------------------------------------------------------------------------------- |
| `XUI_NONINTERACTIVE` | روی `1` تنظیم کنید (یا بدون TTY اجرا کنید) تا نصب بدون هیچ پرسشی انجام شود؛ اطلاعات احراز هویتِ تولیدشده در `/etc/x-ui/install-result.env` نوشته می‌شوند. نگاه کنید به [نصب](/docs/guide/installation#unattended--cloud-init). |
+5
View File
@@ -0,0 +1,5 @@
{
"title": "مرجع",
"icon": "BookMarked",
"pages": ["env-vars", "database", "ports-firewall", "api"]
}
@@ -0,0 +1,36 @@
---
title: پورت‌ها و فایروال
description: پورت‌هایی که 3x-ui به‌صورت پیش‌فرض استفاده می‌کند و قواعد آماده ufw / nftables برای باز کردن آن‌ها.
icon: Network
---
فقط پورت‌هایی را باز کنید که واقعاً استفاده می‌کنید. در ادامه پورت‌های رایج و یک
سازنده برای قواعد `ufw` و `nftables` آمده است.
## پورت‌های رایج
| Port (default) | Purpose |
| -------------- | ----------------------------------------- |
| `22` | SSH (این را باز نگه دارید!). |
| `2053` | پنل (قابل پیکربندی). |
| `2096` | سرور اشتراک (اگر جداگانه باشد). |
| `443` | یک پورت ورودی رایج (TLS / REALITY). |
| `80` / `443` | پراکسی معکوس (اگر از آن استفاده کنید). |
پورت‌های ورودی واقعی شما به inboundهایی بستگی دارد که می‌سازید.
## ساخت قواعد فایروال
<FirewallRulesGenerator />
<Callout type="warn">
همیشه پیش از فعال‌سازی سیاست رد پیش‌فرض (default-deny)، اجازه SSH را باز نگه
دارید و از یک نشست دوم آزمایش کنید تا خودتان را پشت در نگذارید.
</Callout>
## مرتبط
<Cards>
<Card title="امنیت" href="/docs/operations/security" description="Fail2ban، محدودیت‌های IP و سخت‌سازی." />
<Card title="متغیرهای محیطی" href="/docs/reference/env-vars" description="XUI_PORT و موارد مشابه." />
</Cards>
+72
View File
@@ -0,0 +1,72 @@
---
title: Клиенты
description: Управление клиентами 3x-ui — учётные данные, лимиты трафика и срока действия, ограничения по IP, группы, массовые операции, внешние ссылки и статус онлайн.
icon: Users
---
**Клиент** — это отдельный пользователь, идентифицируемый по уникальному
**email**. В текущей версии панели клиенты являются полноценными записями,
которые можно одновременно привязать к **нескольким входящим подключениям**
(inbounds), с учётом трафика по каждому клиенту.
## Поля клиента
| Поле | Применяется к | Значение |
| -------------- | --------------------- | ------------------------------------------------------------------ |
| **Email** | все | Уникальный идентификатор для учёта трафика и поиска. |
| **ID (UUID)** | VLESS, VMess | Учётные данные клиента. |
| **Password** | Trojan, Shadowsocks | Учётные данные клиента. |
| **Auth** | Hysteria2 | Учётные данные клиента. |
| **Flow** | VLESS | Поток XTLS, например `xtls-rprx-vision`. |
| **Limit IP** | все | Максимум одновременных IP-адресов источника (контролируется через Fail2ban). |
| **Total (GB)** | все | Квота трафика; при исчерпании клиент отключается. |
| **Expiry** | все | Дата, после которой клиент перестаёт работать. |
| **Reset** | все | Период автопродления в **днях** (обнуляет квоту). |
| **Telegram ID**| все | Привязывает клиента к пользователю Telegram для самообслуживания/уведомлений.|
| **Sub ID** | все | Идентификатор подписки, группирующий ссылки этого клиента. |
| **Group** | все | Необязательная группа клиента для организации и массовой фильтрации.|
| **Comment** | все | Произвольная текстовая заметка. |
<Callout type="info">
Достижение лимита **трафика** или **срока действия** отключает клиента; при
автоматическом отключении клиентов панель может автоматически перезапускать
Xray (`restartXrayOnClientDisable`, включено по умолчанию).
</Callout>
## Лимиты и контроль IP
- Ограничения по **трафику / сроку действия** отключают клиента при достижении;
период **Reset** автоматически обновляет квоту.
- **Limit IP** ограничивает количество одновременных IP-адресов источника.
Контроль осуществляется с помощью Fail2ban — см.
[Безопасность](/docs/operations/security). Вы можете просмотреть недавние
IP-адреса клиента и очистить их из действий клиента.
- **Статус онлайн** и время **последнего входа** отслеживаются по каждому
клиенту (и по каждому узлу в конфигурациях с несколькими узлами).
## Ссылки для общего доступа и внешние ссылки
У каждого клиента есть ссылки для общего доступа и QR-код для его входящих
подключений, а также объединённая [подписка](/docs/config/subscription). К
клиенту также можно привязать **внешние ссылки** — дополнительные ссылки
`vless://`, `vmess://`, `trojan://`, `ss://`, `hysteria2://` или
`wireguard://`, либо удалённый URL подписки, — чтобы они отображались рядом со
сгенерированными панелью в подписке клиента.
Чтобы точно узнать, что содержит ссылка, вставьте её в
[инспектор ссылок для общего доступа](/docs/config/share-links).
## Массовые операции
Для управления множеством клиентов одновременно панель поддерживает массовые
операции **создания, включения, отключения, удаления, привязки/отвязки** (к
входящим подключениям), **сброса трафика** и **корректировки** (добавить дни /
добавить байты / задать flow). Операции обслуживания также позволяют удалять
**исчерпанных** клиентов (исчерпана квота/срок действия) и **осиротевших**
клиентов (не привязанных ни к одному входящему подключению).
<Callout type="warn">
Ссылка клиента для общего доступа содержит его учётные данные. Относитесь к
ссылкам и QR-кодам как к паролям и меняйте учётные данные, если что-то из
этого утекло.
</Callout>
+100
View File
@@ -0,0 +1,100 @@
---
title: Входящие подключения и протоколы
description: Создание входящих подключений в 3x-ui — протоколы, транспорты, сброс трафика и срок действия, а также fallback-правила, обслуживающие несколько протоколов на одном порту.
icon: ArrowDownToLine
---
**Входящее подключение** (inbound) — это слушатель, который принимает клиентские
соединения на порту, используя определённый протокол и транспорт. Большая часть
повседневной работы состоит в создании и управлении входящими подключениями и
клиентами внутри них.
## Создание входящего подключения
<Steps>
<Step>
### Добавьте входящее подключение
Откройте **Inbounds → Add**, задайте примечание, выберите **протокол**, а также
**порт** и адрес прослушивания.
</Step>
<Step>
### Выберите транспорт и безопасность
Выберите транспорт (TCP, WebSocket, gRPC, HTTPUpgrade, XHTTP, …) и уровень
безопасности (без шифрования, TLS или REALITY). См. [Транспорты](/docs/config/transports) и
[REALITY](/docs/config/reality).
</Step>
<Step>
### Добавьте клиентов
Добавьте одного или нескольких клиентов, у каждого со своими учётными данными,
ограничениями и ссылкой для подключения. См. [Клиенты](/docs/config/clients).
</Step>
<Step>
### Задайте лимит трафика, срок действия и сброс
При необходимости ограничьте общий объём трафика и установите дату истечения для
входящего подключения, а также выберите расписание периодического **сброса трафика**:
`never` (по умолчанию), `hourly`, `daily`, `weekly` или `monthly`.
</Step>
</Steps>
## Поддерживаемые протоколы
Редактор входящих подключений принимает следующие протоколы:
| Протокол | Примечания |
| ---------------------- | ------------------------------------------------------------------------ |
| **VLESS** | Лёгкий; основа для REALITY + XTLS-Vision. Рекомендуется. |
| **VMess** | Более старый, но очень широко поддерживается клиентами. |
| **Trojan** | На основе TLS; поддерживает XTLS и fallback-правила. |
| **Shadowsocks** | Включает шифры Shadowsocks-2022 (`2022-blake3-*`). |
| **WireGuard** | Современный туннель. |
| **Hysteria2** | Выбирается как `hysteria`; панель создаёт ссылки `hysteria2://`. |
| **HTTP** | HTTP-прокси. |
| **Mixed (SOCKS/HTTP)** | Совмещённый слушатель SOCKS + HTTP. |
| **Dokodemo-door / Tunnel** | Перенаправление портов / перенаправление трафика. |
| **MTProto** | Прокси Telegram MTProto, обслуживаемый встроенным процессом `mtg` (не Xray). |
<Callout type="info">
Hysteria2 внутренне не является отдельным протоколом — это протокол `hysteria`
с версией транспорта, установленной в 2, и панель генерирует для него ссылки
`hysteria2://` для подключения.
</Callout>
## Fallback-правила — несколько протоколов на одном порту
Fallback-правила позволяют одному TLS-порту (например, `443`) обслуживать более
одного протокола — например, VLESS **и** Trojan — направляя несовпавшие
рукопожатия на дочернее входящее подключение. В 3x-ui fallback-правила
управляются в панели (список **Fallbacks** у главного входящего подключения), а
не прописываются вручную в JSON.
Fallback-правила доступны только тогда, когда главное входящее подключение:
- использует **VLESS** или **Trojan**,
- работает на «сыром» транспорте **TCP**,
- с безопасностью **TLS** или **REALITY**.
Каждое fallback-правило указывает на дочернее входящее подключение и может
сопоставляться по `path`, `alpn` и `dest`. Клиентские ссылки для дочернего
fallback-подключения автоматически переписываются так, чтобы указывать адрес,
порт и TLS главного подключения.
## Не уверены, что выбрать?
Воспользуйтесь мастером, чтобы получить рекомендацию исходя из ваших целей и клиентов:
<ProtocolWizard />
<Callout type="info">
Для устойчивости к цензуре с современными клиентами **VLESS + REALITY +
XTLS-Vision** обычно является лучшим выбором — перейдите к
[REALITY](/docs/config/reality).
</Callout>
+14
View File
@@ -0,0 +1,14 @@
{
"title": "Конфигурация",
"icon": "Settings",
"pages": [
"panel",
"ssl-certificates",
"inbounds",
"reality",
"transports",
"clients",
"subscription",
"share-links"
]
}
+77
View File
@@ -0,0 +1,77 @@
---
title: Настройки панели
description: Все настройки панели 3x-ui — веб-сервер, TLS, отображение, безопасность и уведомления — со значениями по умолчанию из исходного кода.
icon: SlidersHorizontal
---
**Настройки панели** определяют, как сама панель обслуживается и защищается
(отдельно от ваших входящих подключений и клиентов). Настройки хранятся в виде
пар ключ/значение; приведённые ниже значения по умолчанию взяты напрямую из
исходного кода панели. Секреты (токены, пароли) отображаются только как индикатор
«задано / не задано» и никогда не передаются в браузер целиком.
## Веб-сервер
| Настройка | По умолчанию | Значение |
| ------------------- | ----------------------- | ----------------------------------------------------------------------- |
| `webPort` | `2053` | Порт панели (1–65535). Переменная окружения `XUI_PORT` переопределяет его во время выполнения. |
| `webListen` | _(все интерфейсы)_ | Привязка панели к конкретному IP. |
| `webBasePath` | `/` | URL-путь, по которому обслуживается панель (всегда нормализуется к `/…/`). |
| `webCertFile` / `webKeyFile` | _(нет)_ | Сертификат TLS + ключ. Когда заданы оба, панель обслуживается по **HTTPS**. |
| `sessionMaxAge` | `360` | Время жизни сессии в **минутах** (по умолчанию 6 часов). |
| `trustedProxyCIDRs` | `127.0.0.1/32,::1/128` | IP-адреса/CIDR, чьим переадресованным заголовкам (реальный IP клиента) можно доверять. |
| `panelOutbound` | _(нет)_ | Маршрутизация собственного исходящего трафика панели (проверка обновлений, Telegram, запросы geo/подписок) через именованный исходящий канал Xray. |
После изменения порта или базового пути URL панели становится
`http(s)://<server>:<port><web-base-path>`. Вы можете заранее задать базовый путь
при первом запуске с помощью [`XUI_INIT_WEB_BASE_PATH`](/docs/reference/env-vars).
### TLS
Обслуживание панели по HTTPS защищает ваши учётные данные при передаче. Либо
задайте `webCertFile` + `webKeyFile` — [меню SSL в `x-ui`](/docs/config/ssl-certificates)
может получить для вас сертификат Let's Encrypt — либо завершайте TLS на
[обратном прокси](/docs/operations/reverse-proxy).
<Callout type="warn">
Никогда не выставляйте панель по обычному HTTP в публичный интернет. Используйте
TLS, нестандартный порт и длинный случайный базовый путь.
</Callout>
## Отображение
| Настройка | По умолчанию | Значение |
| ---------------- | ------------------------------------------------ | ------------------------------------------------------------- |
| `pageSize` | `25` | Строк на странице в списках (`0` отключает разбивку на страницы). |
| `expireDiff` | `0` | За сколько дней до истечения срока начинать предупреждать. |
| `trafficDiff` | `0` | Процент оставшейся квоты, при котором начинать предупреждать. |
| `remarkTemplate` | `{{INBOUND}}-{{EMAIL}}\|📊{{TRAFFIC_LEFT}}\|⏳{{DAYS_LEFT}}D` | Шаблон примечания клиента по умолчанию (см. [Ссылки для обмена](/docs/config/share-links#remark-template-variables)). |
| `timeLocation` | `Local` | Часовой пояс для статистики и сроков истечения. |
| `datepicker` | `gregorian` | Календарь для ввода дат (григорианский или джалали/персидский). |
## Безопасность и аутентификация
Учётные данные, двухфакторная аутентификация, ограничитель перебора паролей,
сессии и LDAP описаны в разделах [Первый вход](/docs/guide/first-login) и
[Безопасность](/docs/operations/security). Вкратце:
- Пароли хранятся в виде хешей **bcrypt**; их изменение завершает все сессии.
- При входе может требоваться **2FA (TOTP)**.
- Резервный механизм **LDAP** может аутентифицировать пользователей, когда локальная проверка пароля не проходит.
- Доступ к API использует **токены API**, управляемые в разделе «Настройки панели» (см.
[справочник по API](/docs/reference/api/api-tokens)).
## Уведомления и подписка
У них есть собственные группы настроек и страницы:
<Cards>
<Card title="Бот Telegram" href="/docs/operations/telegram-bot" description="Токен, идентификаторы чатов, оповещения и отчёты." />
<Card title="Подписка" href="/docs/config/subscription" description="Сервер подписок, форматы и пути." />
<Card title="Безопасность" href="/docs/operations/security" description="2FA, ограничения по IP и усиление защиты." />
</Cards>
<Callout type="info">
Уведомления по электронной почте (SMTP) также настраиваются (хост, порт,
шифрование, получатели) с теми же типами событий, что и у бота Telegram.
</Callout>
+142
View File
@@ -0,0 +1,142 @@
---
title: REALITY
description: Настройка входящего подключения VLESS + REALITY с XTLS-Vision в 3x-ui — ключи, short ID, SNI, отпечатки и типичные ошибки.
icon: ShieldCheck
---
**REALITY** — это механизм безопасности транспорта Xray, маскирующий ваш прокси
под обычный трафик к реальному популярному сайту. В отличие от классического TLS,
вашему серверу **не нужен собственный сертификат** — он заимствует TLS-рукопожатие
целевого сайта (`dest`). В сочетании с потоком **XTLS-Vision** это работает быстро
и устойчиво к глубокому анализу пакетов.
REALITY используется с **VLESS** (а также Trojan). Рекомендуемый поток —
`xtls-rprx-vision`.
## Ключевые настройки
Когда вы выбираете **REALITY** в качестве режима безопасности для входящего
подключения VLESS, 3x-ui отображает следующие поля:
| Поле | Что это такое |
| ------------------------ | ------------------------------------------------------------------ |
| **Dest (цель)** | Реальный TLS-сайт для имитации, например `www.microsoft.com:443`. |
| **SNI / Server Names** | Имя(имена) хоста, которые отправляют клиенты; должны совпадать с сертификатом цели. |
| **Public / Private key** | Пара ключей **x25519**. Приватный ключ остаётся на сервере. |
| **Short IDs** | Шестнадцатеричные строки для аутентификации клиентов (их может быть несколько). |
| **Flow** | Установите в `xtls-rprx-vision`. |
| **Fingerprint (uTLS)** | TLS-отпечаток клиента для имитации, например `chrome`. |
Приватный ключ генерируется утилитой `x25519` из состава Xray (панель может
сгенерировать пару за вас):
```bash title="generate an x25519 keypair"
xray x25519
```
## Настройка в панели
<Steps>
<Step>
### Создайте входящее подключение VLESS
Добавьте новое входящее подключение, выберите протокол **VLESS** и установите
**Security** в **reality**.
</Step>
<Step>
### Выберите цель (dest) и SNI
Выберите авторитетный сайт, поддерживающий TLS 1.3 и HTTP/2 и доступный как с
вашего сервера, так и с устройств клиентов (например `www.microsoft.com:443`).
Задайте server names / SNI так, чтобы они совпадали с сертификатом этого сайта.
</Step>
<Step>
### Сгенерируйте ключи и short ID
Сгенерируйте пару ключей x25519 и один или несколько short ID. Держите
**приватный ключ** в секрете; клиенты получают только **публичный ключ**.
</Step>
<Step>
### Задайте поток и отпечаток
Используйте поток `xtls-rprx-vision` и распространённый отпечаток uTLS, например
`chrome`.
</Step>
<Step>
### Добавьте клиента и поделитесь ссылкой
Создайте клиента, затем используйте его ссылку для подключения или QR-код в
совместимом приложении (v2rayNG, Hiddify, Mihomo и других).
</Step>
</Steps>
## Как выглядит конфигурация
На сервере секция `streamSettings` входящего подключения REALITY выглядит
примерно так:
```json title="server inbound (excerpt)"
{
"network": "tcp",
"security": "reality",
"realitySettings": {
"dest": "www.microsoft.com:443",
"serverNames": ["www.microsoft.com"],
"privateKey": "<x25519 private key>",
"shortIds": ["<hex short id>"],
"fingerprint": "chrome"
}
}
```
Соответствующая клиентская ссылка для подключения содержит **публичные**
параметры:
```text title="vless:// (excerpt)"
vless://<uuid>@<server>:443?security=reality&pbk=<public-key>&sid=<short-id>&sni=www.microsoft.com&fp=chrome&spx=%2F&flow=xtls-rprx-vision#my-reality
```
- `pbk` — **публичный** ключ REALITY
- `sid` — short ID (совпадает с одним из заданных на сервере)
- `sni` — server name (совпадает с сертификатом цели)
- `fp` — отпечаток клиента
- `spx` — путь spiderX
- `flow` — `xtls-rprx-vision`
## Типичные ошибки
<Callout type="warn">
- **Неподходящая цель.** Значение `dest` должно указывать на реальный сайт,
который поддерживает **TLS 1.3** и **HTTP/2**, доступен и не заблокирован в
вашем регионе. Выбирайте сайт, который вам не принадлежит и на который идёт
большой трафик.
- **Несовпадение SNI.** Значения SNI / server names должны совпадать с реальным
сертификатом цели, иначе рукопожатие выдаст маскировку.
- **Утечка приватного ключа.** Клиентам всегда передавайте только **публичный**
ключ.
- **Неправильный поток.** Для REALITY + XTLS-Vision нужен `flow = xtls-rprx-vision`
как в записи клиента входящего подключения, так и в ссылке для подключения.
</Callout>
## Сгенерируйте конфигурацию
Используйте генератор ниже, чтобы создать новую пару ключей X25519, UUID и short
ID, а затем скопируйте JSON входящего подключения сервера и клиентскую ссылку для
подключения. Все вычисления выполняются **в вашем браузере** — никакие ключи и
ссылки никуда не отправляются.
<RealityConfigGenerator />
<Callout type="info">
**Приватный ключ** должен оставаться только на вашем сервере. Делитесь с
клиентами сгенерированной ссылкой `vless://` (которая содержит **публичный**
ключ).
</Callout>
@@ -0,0 +1,82 @@
---
title: Ссылки для обмена
description: Форматы ссылок для обмена в 3x-ui (vless, vmess, trojan, ss, hysteria2, mtproto), переменные шаблона примечания и инспектор ссылок в браузере.
icon: Link
---
3x-ui генерирует **ссылку для обмена** (и QR-код) для каждого клиента. Клиентские приложения,
такие как v2rayNG, Hiddify и Mihomo, импортируют эти ссылки для собственной настройки.
## Форматы ссылок
| Схема | Структура |
| -------------- | --------------------------------------------------------------- |
| `vless://` | `vless://<uuid>@<host>:<port>?<params>#<remark>` |
| `vmess://` | `vmess://<base64-json>` (JSON-объект в кодировке base64) |
| `trojan://` | `trojan://<password>@<host>:<port>?<params>#<remark>` |
| `ss://` | `ss://<userinfo>@<host>:<port>?<params>#<remark>` (SIP002; Shadowsocks-2022 использует userinfo с процентным кодированием) |
| `hysteria2://` | `hysteria2://<auth>@<host>:<port>?<params>#<remark>` |
| `tg://proxy` | `tg://proxy?server=…&port=…&secret=…` (MTProto) |
Параметры запроса несут настройки транспорта и безопасности — `security`,
`sni`, `fp`, `pbk`, `sid`, `spx`, `flow`, `type`, `path`, `host`, `alpn` и
другие.
## Разбор ссылки
Вставьте любую ссылку для обмена, чтобы декодировать каждое поле. Разбор происходит **целиком в вашем
браузере** — ссылка никогда не отправляется по сети.
<ShareLinkInspector />
<Callout type="warn">
Ссылки для обмена содержат всё необходимое для подключения в качестве клиента, включая
учётные данные клиента. Относитесь к ним как к паролям.
</Callout>
## Переменные шаблона примечания
Текст после `#` в каждой ссылке (**примечание**) генерируется из шаблона,
которым вы управляете в настройках панели (`remarkTemplate`). По умолчанию используется:
```text
{{INBOUND}}-{{EMAIL}}|📊{{TRAFFIC_LEFT}}|⏳{{DAYS_LEFT}}D
```
Токены используют синтаксис `{{UPPER_CASE}}`. Шаблон разбивается на сегменты по `|`;
сегмент, единственным значением которого является маркер безлимита `∞` (для `TRAFFIC_LEFT`,
`TRAFFIC_TOTAL`, `DAYS_LEFT` или `TIME_LEFT`), отбрасывается, чтобы у клиентов с безлимитом
не отображались пустые украшения.
### Доступные токены
| Токен | Значение |
| ----- | ----- |
| `{{EMAIL}}` / `{{USERNAME}}` | Email клиента (идентификатор) |
| `{{INBOUND}}` | Примечание входящего соединения |
| `{{HOST}}` | Примечание строки хоста (управляемые хосты) |
| `{{ID}}` / `{{SHORT_ID}}` | UUID клиента / его первые 8 символов |
| `{{TELEGRAM_ID}}` · `{{SUB_ID}}` · `{{COMMENT}}` | Telegram ID, ID подписки, комментарий |
| `{{STATUS}}` / `{{STATUS_EMOJI}}` | `active`/`expired`/`depleted`/`disabled` (или ✅⏳🚫) |
| `{{DAYS_LEFT}}` / `{{TIME_LEFT}}` | Осталось дней или `Xd Xh Xm` (`∞`, если безлимит) |
| `{{EXPIRE_DATE}}` / `{{JALALI_EXPIRE_DATE}}` / `{{EXPIRE_UNIX}}` | Срок действия в григорианской / джалали дате / секундах Unix |
| `{{CREATED_UNIX}}` | Время создания (секунды Unix) |
| `{{TRAFFIC_USED}}` / `{{TRAFFIC_LEFT}}` / `{{TRAFFIC_TOTAL}}` | Использование в читаемом виде (`∞`, если безлимит) |
| `{{TRAFFIC_USED_BYTES}}` / `{{TRAFFIC_LEFT_BYTES}}` / `{{TRAFFIC_TOTAL_BYTES}}` | То же, в байтах |
| `{{UP}}` / `{{DOWN}}` | Отправлено / получено (в читаемом виде) |
| `{{RESET_DAYS}}` · `{{USAGE_PERCENTAGE}}` | Период сброса (дни) · использованный процент |
| `{{PROTOCOL}}` / `{{TRANSPORT}}` / `{{SECURITY}}` | например `VLESS` / `ws` / `REALITY` |
<Callout type="info">
Токены использования (трафик, дни, статус) появляются в **теле** подписки, но
удаляются из отображения/QR-вида, поэтому общий QR-код не раскрывает оставшуюся
квоту клиента. Токены дат следуют настройке `datepicker` (григорианский или
джалали календарь).
</Callout>
## Связанные материалы
<Cards>
<Card title="REALITY" href="/docs/config/reality" description="Сгенерируйте конфигурацию и ссылку VLESS + REALITY." />
<Card title="Подписка" href="/docs/config/subscription" description="Отдавайте все ссылки клиента с одного URL." />
</Cards>
@@ -0,0 +1,181 @@
---
title: SSL-сертификаты
description: Получение и продление TLS-сертификатов для панели и входящих подключений 3x-ui — через меню ACME в x-ui (домен или голый IP), wildcard через Cloudflare DNS-01 или вручную с помощью Certbot.
icon: ShieldCheck
---
TLS-сертификат позволяет обслуживать **панель** по HTTPS (чтобы трафик входа и API
был зашифрован) и терминировать TLS на **входящих подключениях** (VLESS-TLS, Trojan,
Shadowsocks-TLS и им подобных). Получить его можно тремя способами:
- **Меню `x-ui`** — встроенный [ACME](https://en.wikipedia.org/wiki/Automatic_Certificate_Management_Environment)-клиент.
Проще всего для одного домена или голого IP.
- **Cloudflare DNS-01** — тоже из меню; нужен для **wildcard**-сертификатов или
когда порт 80 заблокирован / сервер находится за прокси Cloudflare.
- **Вручную через Certbot** — если вы предпочитаете управлять `acme.sh`/Certbot самостоятельно.
<Callout type="info">
Если вы размещаете панель за Nginx или Caddy, доверьте управление
сертификатом прокси-серверу — см. [Обратный прокси](/docs/operations/reverse-proxy).
Входящим подключениям [REALITY](/docs/config/reality) сертификат **не нужен вовсе**; они
заимствуют TLS реального сайта. Эта страница — про панель и про классические TLS-входящие
подключения.
</Callout>
## Меню SSL в `x-ui` (Let's Encrypt)
Запустите `x-ui` и выберите **`20` — SSL Certificate Management**. Оно управляет
[acme.sh](https://github.com/acmesh-official/acme.sh) и предлагает:
| Опция | Что делает |
| ------------------------------ | ------------------------------------------------------------------- |
| Get SSL (Domain) | Выпустить сертификат для домена через HTTP-проверку. |
| Get SSL for IP Address | Выпустить короткоживущий (6-дневный, автопродление) сертификат для **голого IP**. |
| Revoke | Отозвать существующий сертификат. |
| Force Renew | Продлить сейчас, до истечения срока. |
| Show Existing Domains | Перечислить сертификаты, уже имеющиеся на сервере. |
| Set Cert paths for the panel | Указать панели путь к выпущенному сертификату (заполняет поля за вас). |
### Выпуск сертификата для домена
<Steps>
<Step>
### Направьте домен на сервер
Создайте запись `A` (и/или `AAAA`) для вашего домена, которая указывает на
публичный IP этого сервера. Проверка не пройдёт, пока DNS не распространится.
</Step>
<Step>
### Освободите порт 80
HTTP-проверке нужен **порт 80**, доступный из интернета и ещё не занятый. На время
проверки остановите всё, что к нему привязано, и откройте его в
[файрволе](/docs/reference/ports-firewall).
</Step>
<Step>
### Запустите выпуск
`x-ui` → `20` → **Get SSL (Domain)**, затем введите домен. acme.sh запрашивает
сертификат и сохраняет его в каталоге `/root/cert/<domain>/` как `fullchain.pem`
(цепочка сертификатов) и `privkey.pem` (приватный ключ).
</Step>
<Step>
### Подключите его к панели
Выберите **Set Cert paths for the panel**, чтобы заполнить `webCertFile` и
`webKeyFile` и перезапустить панель, либо задайте их сами в разделе
[Настройки панели](/docs/config/panel#tls). Панель начинает обслуживать HTTPS, как только
заданы оба значения.
</Step>
</Steps>
### Выпуск сертификата для голого IP
Нет домена? Выберите **Get SSL for IP Address**, чтобы получить короткоживущий
сертификат (действует ~6 дней, продлевается автоматически), привязанный к IP сервера.
Полезно для доступа к панели по HTTPS до того, как вы настроите домен.
## Cloudflare (wildcard через DNS-01)
DNS-проверка подтверждает, что вы управляете доменом, путём создания TXT-записи вместо
ответа на порту 80 — поэтому она работает **за прокси Cloudflare**, на серверах,
где порт 80 заблокирован, и для **wildcard**-сертификатов (`*.example.com`).
DNS вашего домена должен управляться Cloudflare, и вам понадобится одно из:
- **ограниченный по области API-токен** с правом `Zone:DNS:Edit` (рекомендуется), либо
- **email вашей учётной записи + Global API Key**.
<Steps>
<Step>
### Создайте ограниченный API-токен
В панели Cloudflare перейдите в **My Profile → API Tokens →
[Create Token](https://dash.cloudflare.com/profile/api-tokens)**, выберите шаблон
**Edit zone DNS**, ограничьте его областью той зоны, для которой выпускаете сертификат, и создайте
токен. Скопируйте его — он показывается только один раз.
</Step>
<Step>
### Запустите выпуск через Cloudflare
`x-ui` → **`21` — Cloudflare SSL Certificate**. На запрос выберите **`t`** для
API-токена (по умолчанию) или **`g`** для Global API Key, затем введите свой
домен (а для Global API Key — ещё email учётной записи и ключ). acme.sh создаёт
TXT-запись, проходит проверку и убирает её.
</Step>
<Step>
### Направьте на него панель
Как и в случае с доменом, используйте **Set Cert paths for the panel** (меню `20`) или задайте
`webCertFile` / `webKeyFile` в разделе [Настройки панели](/docs/config/panel#tls).
</Step>
</Steps>
<Callout type="info">
Предпочитайте ограниченный токен Global API Key — он даёт право только на изменение
DNS в выбранной вами зоне, поэтому его утечка не затронет остальную часть вашей учётной записи Cloudflare.
</Callout>
## Вручную (Certbot)
Если вы предпочитаете не пользоваться меню, выпустите сертификат с помощью standalone-плагина
Certbot (это, опять же, требует свободного порта 80 и домена, указывающего на сервер):
```bash
apt-get install certbot -y
certbot certonly --standalone --agree-tos --register-unsafely-without-email -d yourdomain.com
certbot renew --dry-run
```
Certbot записывает сертификат в `/etc/letsencrypt/live/yourdomain.com/`
(`fullchain.pem` и `privkey.pem`). Укажите панели путь к этим двум файлам в разделе
[Настройки панели](/docs/config/panel#tls) и настройте продление — `certbot renew`
по умолчанию запускается через таймер systemd.
## Использование сертификата
- **Панель** — задайте `webCertFile` (полная цепочка) и `webKeyFile` (приватный
ключ) в разделе [Настройки панели](/docs/config/panel#tls). Чтобы панель переключилась
на HTTPS, должны быть заданы оба. Пункт меню **`11` — View Current Settings** выводит
пути, используемые в данный момент.
- **Входящие подключения** — когда вы включаете TLS на входящем подключении, укажите те же
файлы сертификата и ключа (или вставьте их содержимое) в настройках TLS этого подключения.
См. [Входящие подключения](/docs/config/inbounds) и
[Транспорты](/docs/config/transports).
<Callout type="warn">
Сертификаты истекают (Let's Encrypt: 90 дней; IP-сертификаты: ~6 дней). И меню, и
Certbot продлевают их автоматически, но панель продолжает читать **файлы** по их
фиксированным путям — поэтому продлевайте **на месте**, а не перемещайте файлы, и
панель подхватит новый сертификат при следующем перезапуске. **Force Renew** (меню `20`)
запускает продление по требованию.
</Callout>
## Дальнейшие шаги
<Cards>
<Card
title="Настройки панели"
href="/docs/config/panel#tls"
description="webCertFile / webKeyFile и остальные настройки веб-сервера."
/>
<Card
title="Обратный прокси"
href="/docs/operations/reverse-proxy"
description="Доверьте терминирование TLS Nginx или Caddy."
/>
<Card
title="REALITY"
href="/docs/config/reality"
description="Скрытный TLS для входящих подключений — сертификат не требуется."
/>
</Cards>
@@ -0,0 +1,90 @@
---
title: Подписка
description: Запуск сервера подписок 3x-ui — форматы base64/JSON/Clash, порты и пути, TLS, заголовки ответа и пользовательские шаблоны.
icon: Rss
---
**Подписка** — это единый URL, который возвращает все конфигурации клиента.
Клиентские приложения периодически обновляют его, поэтому при изменении
входящего соединения клиенты подхватывают изменения автоматически. Сервер
подписок работает как **отдельный** сервер от панели.
## Включение и настройка
Сервер подписок **включён по умолчанию** (`subEnable`). Настройте его в
параметрах подписки панели:
| Параметр | По умолчанию | Назначение |
| ------------- | ------- | --------------------------------------------------------------- |
| `subPort` | `2096` | Порт прослушивания (отдельный от панели). |
| `subListen` | _(все)_ | Адрес привязки. |
| `subPath` | `/sub/` | Базовый путь для необработанных URL подписок. |
| `subDomain` | _(нет)_ | Публичный хост; если задан, сервер отвечает только для этого Host. |
| `subCertFile` / `subKeyFile` | _(нет)_ | Сертификат + ключ TLS — когда заданы, сервер работает по **HTTPS**. |
| `subEncrypt` | `true` | Кодировать тело необработанной подписки в base64. |
| `subUpdates` | `12` | Рекомендуемый интервал обновления (часы), отправляемый клиентам. |
URL подписки выглядит так:
```text
https://<sub-host>:<sub-port>/sub/<sub-id>
```
где `<sub-id>` — это **Sub ID** клиента.
Один и тот же Sub ID отдаётся в нескольких форматах по разным путям — список
**Base64** по `subPath` и конфигурация **JSON** (Xray-json) по пути JSON.
Соберите URL и предпросмотрите оба тела здесь:
<SubscriptionBuilder />
## Форматы вывода
**Формат выбирается по пути**, у каждого свой переключатель включения:
| Формат | Путь | Включается | Вывод |
| --------------------- | --------- | ---------------- | --------------------------------------------------- |
| **Необработанные ссылки** | `/sub/` | всегда (если включён) | Список ссылок `vless://`, `vmess://`, … (закодированных в base64, когда включён `subEncrypt`). |
| **JSON** | `/json/` | `subJsonEnable` | Полные клиентские конфигурации Xray. |
| **Clash / Mihomo** | `/clash/` | `subClashEnable` | YAML-профиль. |
В подписке появляются только включённые входящие соединения, использующие
**VLESS, VMess, Trojan, Shadowsocks или Hysteria2**, упорядоченные по их индексу
сортировки подписки. Запрос `/sub/` с заголовком `Accept: text/html` (или
`?html=1`) возвращает удобочитаемую информационную страницу вместо
необработанного тела.
### Base64 vs JSON
Тело **Base64** — это просто ссылки для обмена, объединённые через перевод
строки и закодированные в стандартный base64 (переключается через `subEncrypt`).
Тело **JSON** оборачивает каждого клиента в полную клиентскую конфигурацию
Xray — фиксированный каркас (локальные входящие mixed/HTTP, DNS, маршрутизация,
policy) плюс исходящее соединение `proxy`, указывающее на входящее. 3x-ui
выдаёт **единый объект конфигурации для одного клиента и массив для
нескольких**, использует плоскую форму `settings` исходящего соединения
(`address`/`port`/`id`, `level: 8`) и удаляет `sockopt` из `streamSettings`.
## Заголовки ответа
Подписки возвращают стандартные заголовки, которые читают совместимые
приложения:
- **`Subscription-Userinfo`** — `upload`, `download`, `total` (байты; `total=0`
означает без ограничений) и `expire` (Unix-секунды).
- **`Profile-Update-Interval`** — интервал обновления в часах (`subUpdates`).
- **`Profile-Title`**, **`Support-Url`**, **`Profile-Web-Page-Url`**,
**`Announce`** — необязательный брендинг, отображаемый некоторыми клиентами.
## Пользовательские шаблоны страниц
Укажите в `subThemeDir` папку с пользовательским шаблоном информационной
страницы, чтобы оформить HTML-страницу подписки в фирменном стиле. Примечание
для каждого клиента на каждой ссылке полностью шаблонизируется — см.
[Ссылки для обмена → переменные примечаний](/docs/config/share-links#remark-template-variables).
<Callout type="info">
Разместите сервер подписок за TLS (задайте `subCertFile`/`subKeyFile` или
[обратный прокси](/docs/operations/reverse-proxy)), чтобы содержимое подписки
не передавалось в открытом виде.
</Callout>

Some files were not shown because too many files have changed in this diff Show More