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
+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>
+205
View File
@@ -0,0 +1,205 @@
---
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. Каждый
network записывает свой собственный ключ настроек на проводе (`tcpSettings`,
`kcpSettings`, …).
| Транспорт | Ключ настроек | Когда использовать |
| --------------- | --------------------- | ---------------------------------------------------------------------- |
| **TCP (Raw)** | `tcpSettings` | Минимальные накладные расходы. Основа для REALITY + XTLS-Vision и фолбэков; опциональная HTTP/1.1-камуфляжная маскировка заголовка. |
| **mKCP** | `kcpSettings` | Надёжный протокол поверх **UDP** — обменивает пропускную способность на меньшую задержку на каналах с потерями. Не несёт TLS/REALITY. |
| **WebSocket** | `wsSettings` | Работает через CDN и HTTP-реверс-прокси; очень совместимый. |
| **gRPC** | `grpcSettings` | На базе HTTP/2; хорошо мультиплексируется и чисто проксируется через Nginx. |
| **HTTPUpgrade** | `httpupgradeSettings` | Дружественный к CDN апгрейд HTTP/1.1 `Upgrade`; легче полноценного 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` | Бюджет пропускной способности на отдачу, в **МБ/с**. |
| `downlinkCapacity` | `20` | Бюджет пропускной способности на приём, в **МБ/с**. |
| `cwndMultiplier` | `1` | Множитель окна перегрузки; повышайте, чтобы сильнее нагружать хорошие каналы. |
| `maxSendingWindow` | `2097152` | Верхний предел числа пакетов «в пути». |
<Callout type="info">
mKCP не может нести TLS или REALITY. Чтобы замаскировать его, добавьте
UDP-маску **FinalMask** — маска `mkcp-legacy` воспроизводит классическую
обфускацию заголовка, которую старые версии Xray хранили в
`kcpSettings.header`/`seed` (этих полей здесь больше нет).
</Callout>
### WebSocket — `wsSettings`
| Поле | По умолчанию | Значение |
| --------------------- | ------- | ---------------------------------------------------------------- |
| `path` | `/` | Путь запроса — маршрутизируйте по нему, когда несколько сервисов делят один хост. |
| `host` | _(нет)_ | Переопределение заголовка `Host` (полезно за CDN). |
| `headers` | `{}` | Дополнительные заголовки запроса. |
| `heartbeatPeriod` | `0` | Секунды между keepalive-пингами; `0` отключает их. |
| `acceptProxyProtocol` | `false` | Принимать PROXY-протокол от вышестоящего прокси. |
### gRPC — `grpcSettings`
| Поле | По умолчанию | Значение |
| ------------- | ------- | --------------------------------------------------------- |
| `serviceName` | _(нет)_ | Путь gRPC-сервиса; работает как секретный маршрут. |
| `authority` | _(нет)_ | Переопределение псевдозаголовка `:authority`. |
| `multiMode` | `false` | Мультиплексировать несколько потоков по одному соединению. |
### HTTPUpgrade — `httpupgradeSettings`
| Поле | По умолчанию | Значение |
| --------------------- | ------- | --------------------------------------------- |
| `path` | `/` | Путь запроса. |
| `host` | _(нет)_ | Переопределение заголовка `Host`. |
| `headers` | `{}` | Дополнительные заголовки запроса. |
| `acceptProxyProtocol` | `false` | Принимать PROXY-протокол от вышестоящего прокси. |
HTTPUpgrade — это одноразовый HTTP/1.1 `Upgrade` без фреймирования WebSocket,
поэтому поля heartbeat нет.
### XHTTP — `xhttpSettings`
У XHTTP (SplitHTTP) большой набор полей; панель заполняет разумные значения по
умолчанию. Те, что вы обычно будете трогать:
| Поле | По умолчанию | Значение |
| ---------------------- | ----------- | ---------------------------------------------------------------------- |
| `path` | `/` | Путь запроса. |
| `host` | _(нет)_ | Переопределение заголовка `Host`. |
| `mode` | `auto` | `auto`, `packet-up`, `stream-up` или `stream-one`. `packet-up` наиболее совместим с CDN; `stream-*` имеют меньшую задержку. |
| `xPaddingBytes` | `100-1000` | Диапазон случайного паддинга, размывающего размеры пакетов. |
| `scMaxBufferedPosts` | `30` | Серверный буфер для загружаемых POST-запросов. |
| `scStreamUpServerSecs` | `20-80` | Окно сервера в режиме stream-up (диапазон через дефис). |
| `xmux` (`enableXmux`) | _(выкл.)_ | Мультиплексирование соединений — `maxConcurrency` `16-32`, `maxConnections` `6`, … Включайте при высокой конкурентности. |
Поля Session-ID (`sessionIDPlacement`, `sessionIDKey`, `sessionIDTable`,
`sessionIDLength`) и параметры `scMin/MaxEachPostBytes` — продвинутые; оставьте
их пустыми, если только вы не подстраиваетесь под конкретный upstream.
### Hysteria — `hysteriaSettings`
Допустимо, только когда протокол — **Hysteria2**.
| Поле | По умолчанию | Значение |
| ---------------- | ------- | ----------------------------------------------------------------------- |
| `version` | `2` | Версия протокола Hysteria. |
| `auth` | _(нет)_ | Общая строка аутентификации. |
| `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` | _(нет)_ | Пропускать набор этого outbound через другой outbound по тегу. |
| `interface` | _(нет)_ | Привязка к конкретному сетевому интерфейсу. |
| `mark` | `0` | SO_MARK для policy routing (`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>
+130
View File
@@ -0,0 +1,130 @@
---
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` (панель предупреждает об этом), смените их немедленно — прежде чем
создавать какие-либо входящие подключения.
</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** — после
включения страница входа будет запрашивать 6-значный код в дополнение к паролю,
а её активация заставит всех войти заново. Отключить 2FA можно через пункт меню
**Reset Username & Password** или командой `x-ui setting -resetTwoFactor`.
## Встроенная защита входа
- **Ограничение перебора:** после **5** неудачных попыток входа с одного и того
же IP/имени пользователя в течение 5 минут эта комбинация блокируется на
**15 минут**.
- **Обобщённые ошибки:** страница входа сообщает «wrong username or password»
как при неверных учётных данных, так и при неверных кодах 2FA, поэтому ничего
не раскрывает.
- **Сессии** действуют `sessionMaxAge` минут (по умолчанию **360** = 6 часов) и
аннулируются при смене учётных данных.
- **LDAP** можно включить как резервный способ аутентификации в разделе Panel
Settings.
## Базовый чек-лист по защите
<Steps>
<Step>
### Задайте надёжные уникальные учётные данные
Замените сгенерированные (или `admin/admin`) имя пользователя и пароль на
надёжные значения.
</Step>
<Step>
### Используйте нестандартный порт и случайный базовый путь
Перенесите панель с порта `2053` и разместите её по длинному случайному пути.
</Step>
<Step>
### Включите двухфакторную аутентификацию
Включите 2FA, чтобы одной лишь утечки пароля было недостаточно для доступа.
</Step>
<Step>
### Разместите панель за TLS
Используйте действительный сертификат (через управление SSL в меню `x-ui` или
обратный прокси), чтобы панель была доступна только по HTTPS.
</Step>
<Step>
### Ограничьте доступ с помощью брандмауэра
Открывайте только действительно необходимые порты и рассмотрите возможность
ограничения доступа к панели по IP.
</Step>
</Steps>
<Callout type="info">
Хотите разместить панель на отдельном домене с автоматическим HTTPS? См.
[Обратный прокси](/docs/operations/reverse-proxy). Для более глубокой защиты см.
[Безопасность](/docs/operations/security).
</Callout>
+71
View File
@@ -0,0 +1,71 @@
---
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).
+151
View File
@@ -0,0 +1,151 @@
---
title: Установка
description: Установите 3x-ui с помощью официального скрипта (стабильная, фиксированная или dev-сборка), в автоматическом режиме / через 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` (а для IPv6 — ещё и
`NET_RAW`); в противном случае блокировки логируются, но никогда не применяются:
```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">
Опытные пользователи могут скачать архив релиза для своей архитектуры со
[страницы релизов](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)
репозитория есть готовые **cloud-init** user-data для автоматической установки в
любом облаке (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,101 @@
---
title: Обновление и удаление
description: Управляйте 3x-ui через меню и CLI 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 | Показать имя пользователя, порт, базовый веб-путь, пути к сертификатам |
| 12–14 | Start / Stop / Restart | Управление службой панели |
| 15 | Restart Xray | Перезапустить только Xray-core |
| 16 | Check Status | Статус службы |
| 17 | Logs Management | Просмотр отладочных логов / очистка логов |
| 18–19 | 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)
(пункты 20–21), [Безопасность](/docs/operations/security) (ограничения по IP, фаервол),
[Обратный прокси](/docs/operations/reverse-proxy) и [Настройки панели](/docs/config/panel)
(TLS), а также [База данных](/docs/reference/database) (PostgreSQL).
## Подкоманды CLI
Для скриптов и быстрых действий `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` | Установка / удаление |
## Обновление
- **Стабильная версия:** пункт меню **2** или `x-ui update`. Повторный запуск
установочного скрипта также обновляет панель на месте.
- **Dev-канал:** пункт меню **3** или `x-ui update-dev` — скользящая сборка
`dev-latest` по каждому коммиту (не стабильный релиз).
- **Конкретная старая версия:** пункт меню **5** (Legacy Version).
Обновление сохраняет вашу базу данных и настройки. Перед переходом на новую
мажорную версию сделайте [резервную копию](/docs/operations/backup-restore).
<Callout type="info">
Пользователи Docker обновляются иначе — нужно скачать новый образ и пересоздать
контейнер (`docker compose pull && docker compose up -d`), а не использовать
команды обновления `x-ui`.
</Callout>
## Удаление
Пункт меню **6** или `x-ui uninstall`. Команда останавливает и отключает службу,
удаляет юнит службы, а также каталоги `/etc/x-ui/` и папку установки. Если панель
использовала локально установленный PostgreSQL, она предложит удалить и его
(отдельное необратимое подтверждение).
<Callout type="warn">
Удаление стирает базу данных (`/etc/x-ui/x-ui.db`) и вашу конфигурацию.
Сначала сделайте [резервную копию](/docs/operations/backup-restore), если она
может вам понадобиться.
</Callout>
@@ -0,0 +1,69 @@
---
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>
### Переводите только текст
Переводите тело страницы и поля frontmatter `title`/`description`. **Не**
переводите код, команды, имена переменных окружения, названия протоколов и
ссылки для подключения.
</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. Он добавляет более широкую поддержку
протоколов, повышенную стабильность, поклиентский учёт трафика, управление несколькими
узлами, интерфейс на 13 языках и множество улучшений для удобства работы.
## Как мне обновиться?
Запустите скрипт установки повторно (он обновляет панель на месте) или загрузите новый Docker-образ.
См. [Установку](/docs/guide/installation) и
[страницу релизов](https://github.com/MHSanaei/3x-ui/releases).
## Где я могу получить помощь?
Присоединяйтесь к официальному Telegram-каналу [@XrayUI](https://t.me/XrayUI), чтобы получать
анонсы и поддержку сообщества, или откройте issue на
[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"]
}
+52
View File
@@ -0,0 +1,52 @@
---
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
В рамках одного и того же бэкенда обновление обычно сводится к повторному запуску
установщика или загрузке нового образа — панель сама мигрирует свою базу данных.
При переходе между **мажорными** версиями сначала прочитайте
[заметки о релизе](https://github.com/MHSanaei/3x-ui/releases) и сделайте резервную копию.
## С x-ui
Прямой импорт базы данных старой панели x-ui в 3x-ui **не поддерживается** —
схемы различаются. Установите 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 / панель недоступна за прокси
- Убедитесь, что панель действительно слушает на восходящем порту (например, `2053`).
- Убедитесь, что ваш [обратный прокси](/docs/operations/reverse-proxy) передаёт заголовки
обновления WebSocket и указывает на правильный порт и **базовый веб-путь**.
- Проверьте, что брандмауэр не блокирует соединение прокси → панель.
## Проблемы с сертификатами
- DNS домена должен указывать на сервер до выпуска сертификата.
- Порты 80/443 должны быть доступны для проверки HTTP/TLS (либо используйте проверку через DNS).
- Помните, что для REALITY сертификат **не нужен** — обычно проблема в неверном
`dest`/SNI (см. [подводные камни REALITY](/docs/config/reality)).
## Клиент не может подключиться
- Декодируйте ссылку клиента с помощью
[инспектора ссылок](/docs/config/share-links) и проверьте каждый параметр.
- Убедитесь, что **транспорт и безопасность совпадают** на обоих концах.
- Убедитесь, что клиент не достиг своего **лимита трафика, срока действия или лимита IP**.
- Проверьте, что входящий порт открыт в брандмауэре.
<Callout type="info">
Всё ещё не получается? Поищите в
[GitHub issues](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,61 @@
---
title: Резервное копирование и восстановление
description: Создавайте резервные копии базы данных и сертификатов 3x-ui и восстанавливайте их вручную или через Telegram-бота.
icon: DatabaseBackup
---
Вся ваша конфигурация — входящие подключения, клиенты, настройки — хранится в
базе данных панели. Регулярно создавайте резервные копии, чтобы иметь возможность
восстановления или переноса.
## Что копировать
- **База данных** — по умолчанию SQLite в `/etc/x-ui/x-ui.db` (или ваша база
данных PostgreSQL, если вы используете этот бэкенд).
- **Сертификаты** — всё, что находится в `/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">
По возможности восстанавливайте резервную копию на **той же мажорной версии**, с
которой она была создана. При переходе между мажорными версиями дайте панели
выполнить миграции, а не навязывайте старую схему.
</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,102 @@
---
title: Несколько узлов и управляемые хосты
description: Управляйте несколькими панелями 3x-ui из одной главной панели — с доверием на основе API-токена или mTLS, heartbeat-сигналами и переопределением хостов для отдельных inbound-соединений в подписках.
icon: Boxes
---
3x-ui может управлять **несколькими серверами** из одной главной панели и
переопределять то, как каждое inbound-соединение объявляется в подписках, с
помощью **управляемых хостов**.
## Узлы
**Узел** — это другая панель 3x-ui, которой ваша главная панель управляет через
API этого узла. Главная панель опрашивает каждый узел и в одном месте показывает
его статус, версии, загрузку CPU/памяти, время работы и трафик.
### Добавление узла
Укажите данные подключения к узлу:
| Поле | Примечания |
| ----------------- | --------------------------------------------------------------------- |
| **Имя** | Уникальная метка (например, `de-fra-1`). |
| **Схема** | `https` (по умолчанию) или `http`. |
| **Адрес / Порт** | Хост и порт панели узла. |
| **Базовый путь** | Веб-базовый путь узла. |
| **API-токен** | Bearer-токен, созданный на узле (не нужен в режиме mTLS). |
| **Проверка TLS** | `verify` (по умолчанию), `skip`, `pin` (закрепить SHA-256 сертификата) или `mtls`. |
| **Синхронизация inbound** | `all` (все) inbound-соединения или `selected` (выбранные) по тегу. |
| **Тег исходящего**| При необходимости обращаться к узлу **через** именованное исходящее соединение (мост исходящего трафика). |
Главная панель проверяет доступность при добавлении или тестировании узла. Затем
она каждые несколько секунд отправляет **heartbeat**, обновляя статус узла
(`online` / `offline`) и генерируя события `node.up` / `node.down` (см.
[Telegram-бот](/docs/operations/telegram-bot)).
<Callout type="info">
Узлы идентифицируются по стабильному GUID, уникальному для каждой панели,
поэтому узел сохраняет свою идентичность между перезапусками. Узел сам может
управлять другими узлами — главная панель отображает их как доступные только
для чтения **транзитивные** подузлы (Узел 1 → Узел 2 → Узел 3).
</Callout>
### Взаимный TLS (mTLS) между главной панелью и узлом
Для максимально надёжного доверия используйте `tlsVerifyMode = mtls` (требуется
`https`):
<Steps>
<Step>
### Получите CA главной панели
На главной панели получите её CA-сертификат для аутентификации узлов (приватный
ключ CA никогда не покидает панель).
</Step>
<Step>
### Доверьте ему на узле
Вставьте этот CA в настройку «доверенный CA» на узле. Изменения вступят в силу
при следующем перезапуске узла.
</Step>
<Step>
### Переключите узел на mTLS
Задайте на узле режим проверки TLS `mtls`. Теперь главная панель предъявляет
клиентский сертификат вместо API-токена.
</Step>
</Steps>
## Управляемые хосты
**Управляемый хост** — это переопределяющая конечная точка, привязанная к
inbound-соединению. Во время формирования подписки каждый включённый хост
добавляет дополнительную ссылку-share / прокси со своим адресом, портом, TLS,
SNI, заголовком host, путём и другими параметрами — заменяя устаревший список
«внешних прокси». Используйте их, чтобы:
- проксировать inbound через **CDN** (Cloudflare) с другим адресом/SNI,
- объявлять для одного inbound **несколько доменов** или конечные точки для
разных регионов,
- настраивать ALPN, fingerprint, ECH или mux для каждой конечной точки.
У каждого хоста есть примечание (которое поддерживает те же
[шаблонные переменные](/docs/config/share-links#remark-template-variables)),
переключатель включения, порядок сортировки, и он может быть **исключён из
определённых форматов подписки** или **ограничен конкретными узлами**.
<Callout type="info">
Хосты, чей адрес/порт указывают на CDN, позволяют держать реальный адрес
сервера в секрете, пока клиенты подключаются через граничные узлы CDN.
</Callout>
## Связанное
<Cards>
<Card title="Исходящие соединения и маршрутизация" href="/docs/operations/outbounds-routing" description="WARP, NordVPN, подписки на исходящие соединения и маршрутизация." />
<Card title="Подписка" href="/docs/config/subscription" description="Как хосты формируют вывод подписки." />
</Cards>
@@ -0,0 +1,169 @@
---
title: Исходящие соединения и маршрутизация
description: Управляйте исходящим трафиком в 3x-ui — outbound-соединения WARP и NordVPN, подписки на исходящие соединения (пулы серверов), правила маршрутизации и балансировщики нагрузки.
icon: Route
---
Inbound-соединения принимают клиентов; **outbound-соединения** определяют, куда
дальше пойдёт их трафик. 3x-ui может направлять трафик через Cloudflare WARP,
NordVPN или произвольные пулы исходящих соединений, импортированные из подписки,
а также выбирать между ними с помощью правил маршрутизации и балансировщиков.
## Редактирование исходящих соединений и маршрутизации
Outbound-соединения, правила маршрутизации, балансировщики, DNS и логирование —
всё это находится в **конфигурации Xray** (шаблоне конфигурации, который вы
редактируете в разделе Xray Settings). Отдельного интерфейса для каждого правила
нет — вы редактируете JSON, а панель перезагружает Xray. Панель также предлагает
**тест связности исходящего соединения** и **тест маршрута** (запрос к
работающему ядру о том, какое исходящее соединение будет использовано для
заданного назначения).
## Построение исходящего соединения
Каждое исходящее соединение — это JSON-объект, состоящий не более чем из четырёх
частей: **`tag`** (на него ссылаются правила маршрутизации и балансировщики),
**`protocol`**, специфичные для протокола **`settings`** и — для прокси-протоколов —
**`streamSettings`**, которые должны совпадать с транспортом и безопасностью
удалённого inbound-соединения. Почти всегда присутствуют два исходящих соединения:
- **`freedom`** отправляет трафик напрямую к его назначению — исходящее соединение
по умолчанию. При необходимости задайте `domainStrategy` (например, `UseIP`),
чтобы управлять разрешением имён хостов.
- **`blackhole`** отбрасывает трафик. Направляйте сюда нежелательные назначения
(реклама, торренты).
```json title="freedom + blackhole"
{
"outbounds": [
{ "tag": "direct", "protocol": "freedom", "settings": {} },
{ "tag": "block", "protocol": "blackhole", "settings": {} }
]
}
```
Прокси-исходящее соединение (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 автоматически
заполнит ключи соединения, адреса, зарезервированные байты и конечную точку пира.
</Step>
<Step>
### (Опционально) автоматическая ротация IP
Задайте интервал обновления WARP (в **днях**) для периодической ротации IP-адреса
WARP. Также можно применить бесплатную лицензию.
</Step>
</Steps>
Направьте нужный трафик (например, определённые домены) на исходящее соединение
`warp` с помощью правила маршрутизации.
## NordVPN
3x-ui может получать учётные данные NordVPN (NordLynx/WireGuard) из токена доступа
(или принимать приватный ключ напрямую) и выводить список стран/серверов, чтобы вы
могли построить outbound-соединение NordVPN.
## Подписки на исходящие соединения (пулы серверов)
**Подписка на исходящие соединения** импортирует удалённую подписку со
ссылками-share и внедряет её серверы в качестве **исходящих соединений** в
работающую конфигурацию Xray — не затрагивая ваш сохранённый шаблон. Это
рекомендуемый способ подписаться на *пул* серверов.
| Поле | По умолчанию | Значение |
| ---------------- | ------------ | -------------------------------------------------------------- |
| `url` | — | URL удалённой подписки (с защитой от SSRF). |
| `tagPrefix` | auto | Префикс для генерируемых тегов исходящих соединений (например, `hk-`); пусто = `subN-`. |
| `updateInterval` | `600` | Интервал обновления в **секундах**. |
| `prepend` | `false` | Размещать эти исходящие соединения перед вашими ручными. |
| `priority` | `0` | Порядок слияния (меньшие значения первыми). |
Импортированные исходящие соединения получают **стабильные теги**: один и тот же
сервер сохраняет один и тот же тег между обновлениями, поэтому селекторы
маршрутизации/балансировщиков по точному тегу остаются привязанными — в то время
как селекторы по префиксу/шаблону (например, `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,52 @@
---
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,66 @@
---
title: Безопасность
description: Усиление защиты 3x-ui — аутентификация панели и 2FA, ограничение IP через Fail2ban, правила брандмауэра, BBR и поддержание актуальности.
icon: ShieldCheck
---
Прокси-панель — ценная цель для атак. Несколько уровней защиты дают большой эффект.
## Усиление защиты панели
- Надёжные, уникальные учётные данные и **двухфакторная аутентификация** (TOTP).
- Нестандартный порт панели и длинный случайный базовый веб-путь.
- TLS на панели (напрямую или через [обратный прокси](/docs/operations/reverse-proxy)).
- Встроенный **ограничитель входа** блокирует IP/имя пользователя после 5 неудачных попыток
за 5 минут (на 15 минут), а панель может направлять собственный исходящий трафик через
outbound.
Полный чек-лист см. в разделе [Первый вход](/docs/guide/first-login).
## Fail2ban и ограничения IP
Задайте **ограничение IP** для каждого клиента (см. [Клиенты](/docs/config/clients)), чтобы
ограничить число одновременных исходных IP. Применением правил занимается **Fail2ban**, который
3x-ui устанавливает и настраивает за вас (включён по умолчанию при установке через скрипт, а
в Docker — через `XUI_ENABLE_FAIL2BAN=true`).
Управляйте им из меню `x-ui` (**22 — IP Limit Management**): установка/настройка,
изменение длительности блокировки (по умолчанию **30 минут**), блокировка/разблокировка 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, порт панели, порт
подписки и ваши входящие порты. Меню `x-ui` (**23 — Firewall Management**) служит обёрткой над
`ufw`, либо сгенерируйте правила здесь:
<FirewallRulesGenerator />
<Callout type="warn">
Убедитесь, что SSH остаётся разрешён, прежде чем включать брандмауэр с политикой запрета по умолчанию, иначе вы можете
заблокировать себе доступ. Проверяйте, держа открытой вторую сессию.
</Callout>
## Настройка сети (BBR)
Меню `x-ui` (**26 — Enable BBR**) переключает алгоритм управления перегрузкой BBR от Google
(`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,120 @@
---
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`). Это ваш **админский** ID.
</Step>
<Step>
### Настройте панель
В настройках панели включите Telegram-бота и задайте **токен** и **админские
chat ID** (через запятую). Сохраните, затем напишите своему боту.
</Step>
</Steps>
Проверьте свой токен, админские ID и расписание отчётов, прежде чем вставлять их
в панель:
<TelegramSetupHelper />
## Команды
Эти команды отображаются в меню команд Telegram: `/start`, `/help`, `/status`, `/id`.
Дополнительные команды:
| Команда | Кому | Действие |
| ------------------ | ------ | ------------------------------------------------------------ |
| `/start`, `/help` | всем | Приветствие и меню встроенных кнопок |
| `/status` | всем | Подтверждает, что бот работает |
| `/id` | всем | Показывает ваш числовой Telegram ID |
| `/usage <arg>` | обоим | Администраторы ищут клиентов; пользователи смотрят свой расход |
| `/inbound <remark>`| админ | Показывает сведения о входящем подключении |
| `/restart` | админ | Перезапускает Xray |
Администраторам также доступны сценарии со встроенными кнопками: использование
сервера, отсортированные отчёты по трафику, сброс трафика, резервные копии БД,
журналы блокировок, список входящих подключений/клиентов, онлайн-клиенты,
«скоро исчерпают» и полноценный мастер **добавления клиента**. Обычным
пользователям доступны кнопки для своего расхода, ссылок на подписку, отдельных
ссылок и QR-кодов.
## Отчёты и оповещения
- **Периодический отчёт** — по расписанию `tgRunTime` (по умолчанию `@daily`) бот
отправляет администраторам сведения об использовании сервера (хост, версии,
время работы, нагрузка, память, онлайн-клиенты, трафик), список
исчерпанных/истекающих клиентов и — если включён `tgBotBackup` — резервную
копию базы данных и конфигурации Xray. Клиенты, привязанные по Telegram ID,
получают собственные предупреждения об истечении срока/исчерпании квоты.
- **Оповещения о событиях** — выбираются параметром `tgEnabledEvents` (по умолчанию `login.attempt,cpu.high`):
| Событие | Когда |
| --------------- | ------------------------------------------------------- |
| `login.attempt` | Вход в панель удался или не удался (с IP и именем пользователя) |
| `cpu.high` | Загрузка CPU превышает `tgCpu` процентов (по умолчанию 80) |
| `memory.high` | Использование памяти превышает `tgMemory` процентов (по умолчанию 80) |
| `xray.crash` | Аварийное завершение Xray-core |
| `outbound.down` / `outbound.up` | Исходящее подключение упало / восстановилось |
| `node.down` / `node.up` | Узел ушёл в офлайн / вернулся в строй |
Время предупреждения определяется параметрами `expireDiff` (дней до истечения
срока) и `trafficDiff` (ГБ оставшейся квоты); оба по умолчанию равны `0`
(отключено).
## Параметры
| Параметр | По умолчанию | Значение |
| -------------- | -------------------------- | ---------------------------------------------- |
| `tgBotEnable` | `false` | Главный переключатель вкл./выкл. |
| `tgBotToken` | _(секрет)_ | Токен Bot API. |
| `tgBotChatId` | _(нет)_ | **Админские** Telegram ID через запятую. |
| `tgBotProxy` | _(нет)_ | Прокси `socks5://`, `http://` или `https://`. |
| `tgBotAPIServer` | _(по умолчанию)_ | Пользовательский сервер Telegram Bot API. |
| `tgRunTime` | `@daily` | Расписание отчётов (cron / `@daily` / `@every …`).|
| `tgBotBackup` | `false` | Прикладывать резервную копию БД к периодическому отчёту. |
| `tgCpu` / `tgMemory` | `80` / `80` | Пороги оповещений по CPU / памяти (в процентах). |
| `tgLang` | `en-US` | Язык бота. |
| `tgEnabledEvents` | `login.attempt,cpu.high`| Какие события доставлять. |
<Callout type="warn">
Токен бота управляет вашим ботом — храните его в секрете и добавляйте только
**доверенные** админские chat ID. Оповещения о входе никогда не содержат
паролей.
</Callout>
<Callout type="info">
Уведомления по электронной почте (SMTP) дублируют те же события
(`smtpEnabledEvents`), если вы предпочитаете получать оповещения на почту —
настройте SMTP в настройках панели.
</Callout>
@@ -0,0 +1,80 @@
---
title: Токены API
description: >-
Управление токенами Bearer для программной аутентификации (боты, центральные
панели, действующие от имени этого узла, CI). У каждого токена есть уникальное
имя и флаг активности — отключите токен, чтобы отозвать его без удаления, либо
удалите, чтобы отозвать окончательно. Токены хранятся в виде хешей SHA-256, а
открытый текст возвращается лишь один раз, в ответе на создание — впоследствии
получить его нельзя, поэтому скопируйте его сразу. Передавайте токен как
<code>Authorization: Bearer &lt;token&gt;</code> в любом запросе /panel/api/* —
такой токен даёт полные права администратора.
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: >-
Поддерживаются два режима аутентификации. Сессии веб-интерфейса используют
cookie, устанавливаемый эндпоинтом входа. Программные клиенты (боты, скрипты,
удалённые панели) аутентифицируются с помощью Bearer-токена, взятого из
Settings → Security → API Token. Оба способа работают для всех эндпоинтов под
/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: Резервное копирование
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: >-
Управление клиентами как самостоятельными сущностями, которые можно привязать к
одному или нескольким входящим подключениям. Одна запись клиента формирует
элемент settings.clients в каждом входящем подключении, к которому он
привязан. Эндпоинты находятся в /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 client’s 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 client’s 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 client’s 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 client’s 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 client’s 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 client’s
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,109 @@
---
title: Хосты
description: >-
Эндпоинты переопределений на уровне отдельного входящего подключения. Каждый
включённый хост добавляет одну дополнительную ссылку подписки/прокси с
собственными адресом/портом/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 host’s 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 host’s 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: >-
Управление конфигурациями входящих подключений и их клиентами. Все эндпоинты
находятся в /panel/api/inbounds и требуют активной сессии входа или Bearer-токена.
Эндпоинты, генерирующие ссылки, учитывают перенаправленные заголовки только тогда,
когда запрос приходит от настроенного доверенного прокси.
full: true
_openapi:
preload:
- ./public/openapi.json
toc:
- depth: 2
title: >-
List every inbound owned by the authenticated user, including each
inbound’s 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 user’s 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 inbound’s 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
inbound’s 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 user’s 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 inbound’s 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 — аутентификация, входящие подключения, клиенты, статистика сервера и многое другое, сгенерировано из спецификации OpenAPI.
icon: Webhook
---
Панель 3x-ui предоставляет REST API для автоматизации. Эти страницы сгенерированы
из спецификации OpenAPI самой панели, поэтому они всегда соответствуют документированной схеме.
## Аутентификация
Запросы аутентифицируются либо с помощью **сессионной cookie** (полученной через `POST /login`), либо
с помощью **Bearer-токена**:
```text
Authorization: Bearer <token>
```
Создавайте API-токены в панели; они дают права полного администратора, поэтому храните их
в безопасности. См. [API-токены](/docs/reference/api/api-tokens).
Сформируйте аутентифицированный запрос для любого из приведённых ниже эндпоинтов:
<ApiRequestBuilder />
## Просмотр по разделам
<Cards>
<Card title="Аутентификация" href="/docs/reference/api/authentication" />
<Card title="Входящие подключения" 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">
Этот справочник повторно генерируется из `public/openapi.json` командой `pnpm gen:api`.
Не редактируйте сгенерированные страницы тегов вручную.
</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 node’s 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 node’s 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,382 @@
---
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 that’s 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 panel’s 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 that’s 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 panel’s 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>, чтобы получать поток JSON-сообщений без
опроса. Требуется аутентифицированный сессионный cookie (авторизация по токену
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,258 @@
---
title: Настройки Xray
description: >-
Шаблон конфигурации Xray, управление исходящими подключениями, интеграция с
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,64 @@
---
title: База данных
description: Хранилища данных 3x-ui — SQLite (по умолчанию) и PostgreSQL — путь к базе данных, пул соединений и миграция с SQLite на PostgreSQL.
icon: Database
---
3x-ui хранит всё — входящие подключения, клиентов, настройки — в базе данных.
Бэкенд выбирается во время установки; оба являются полноценными.
## SQLite (по умолчанию)
Один файл по пути `/etc/x-ui/x-ui.db`. Никакой настройки не требуется, идеально
подходит для небольших и средних развёртываний. Папку можно изменить с помощью
[`XUI_DB_FOLDER`](/docs/reference/env-vars#database) (в Windows по умолчанию она
располагается рядом с бинарным файлом).
## 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,86 @@
---
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` | — | Переопределение порта панели (1–65535). Имеет приоритет над сохранённой настройкой. |
| `XUI_INIT_WEB_BASE_PATH` | `/` | Начальный базовый веб-путь при **первом** запуске (например, `/panel`). |
| `XUI_ENABLE_FAIL2BAN` | `true` | Включить ограничение по IP на основе Fail2ban. |
| `XUI_SKIP_HSTS` | `false` | Не отправлять заголовок HSTS — установите `true`, когда TLS терминируется обратным прокси. |
## Логирование и бинарные файлы
| 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` | — | Целевой процент сборщика мусора 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`.
## Распространённые порты
| Порт (по умолчанию) | Назначение |
| ------------------- | ------------------------------------------- |
| `22` | SSH (держите его открытым!). |
| `2053` | Панель (настраивается). |
| `2096` | Сервер подписок (если он отдельный). |
| `443` | Распространённый входящий порт (TLS / REALITY). |
| `80` / `443` | Обратный прокси (если вы его используете). |
Фактические входящие порты зависят от создаваемых вами входящих подключений.
## Генерация правил брандмауэра
<FirewallRulesGenerator />
<Callout type="warn">
Всегда разрешайте SSH до включения политики запрета по умолчанию и проверяйте из
второй сессии, чтобы случайно не заблокировать себе доступ.
</Callout>
## Смотрите также
<Cards>
<Card title="Безопасность" href="/docs/operations/security" description="Fail2ban, ограничения по IP и усиление защиты." />
<Card title="Переменные окружения" href="/docs/reference/env-vars" description="XUI_PORT и другие." />
</Cards>