Блог Clearway

3x-ui панель: что умеет, лимиты на клиента и чем отличается от Marzban и Remnawave

Коротко

Если коротко, что такое 3x-ui: веб-панель на Go, которая управляет Xray-core на том же сервере по схеме «одна панель = один сервер». Она даёт инбаунды всех транспортов Xray, лимит трафика, срока и числа IP на каждого клиента, встроенную страницу подписки, Telegram-бота и бэкап базы в один клик. Всё состояние — один SQLite-файл /etc/x-ui/x-ui.db: это одновременно точка бэкапа и точка переноса. Панель закрывает 1–2 сервера и сотни клиентов, ставится за 15 минут и ест десятки мегабайт RAM. Как только нужны несколько нод под одной подпиской, несколько администраторов и документированный API — это уже территория Remnawave (или Marzban).

Что такое 3x-ui: панель поверх Xray, а не протокол

3x-ui (репозиторий MHSanaei/3x-ui) — форк заброшенной панели x-ui от Vaxilu. Сама она ничего не проксирует: это веб-морда и супервизор над Xray-core. Конфигурация лежит в SQLite, при старте панель собирает из неё config.json и запускает бинарник Xray. Отсюда простое правило: что умеет ваша версия Xray — умеет и панель, чего Xray не умеет — панель не добавит.

Что оператор получает из коробки:

  • Инбаунды протоколов Xray: VLESS, VMess, Trojan, Shadowsocks, SOCKS, HTTP, Dokodemo-door, WireGuard.
  • Транспорты: TCP, WebSocket, HTTPUpgrade, gRPC, mKCP, XHTTP (бывший SplitHTTP); безопасность — TLS и Reality с генерацией ключей прямо в UI.
  • Клиенты внутри инбаунда с индивидуальным лимитом трафика, сроком, числом IP и своим subId для подписки.
  • Статистика по инбаундам и клиентам, список онлайн-клиентов, системные метрики (CPU, RAM, диск, сеть, uptime).
  • Управление ядром: переключение версии Xray из панели, просмотр логов, ручная правка шаблона конфига (routing, DNS, outbounds, sniffing).
  • Сервисное: выпуск сертификатов через acme, включение BBR, Telegram-бот, бэкап БД, fail2ban.

Ключевой архитектурный факт, который определяет всё остальное: 3x-ui управляет только тем Xray, который стоит на той же машине. Понятия «нода» в панели нет. Три сервера — это три независимые панели, три базы, три набора клиентов и три разные подписки.

Файловая раскладка после установки:

ПутьЧто это
/etc/x-ui/x-ui.dbSQLite: настройки панели, инбаунды, клиенты, счётчики трафика
/usr/local/x-ui/bin/config.jsonсгенерированный конфиг Xray — перезаписывается при каждом рестарте
/usr/local/x-ui/bin/xray-linux-amd64бинарник ядра
/usr/local/x-ui/access.log, error.logлоги Xray (путь задаётся в шаблоне конфига)
/root/cert/сертификаты, если выпускали через меню панели
/etc/systemd/system/x-ui.serviceюнит systemd

Править config.json руками бесполезно: при следующем x-ui restart он будет собран заново из базы. Кастомные routing, DNS и outbounds задаются в разделе Xray Configs — этот шаблон лежит в таблице settings и переживает рестарты.

По ресурсам 3x-ui vpn-стек нетребователен: панель и Xray спокойно живут на 1 vCPU / 512 МБ, в простое связка занимает, по наблюдениям, ~60–150 МБ RSS. Упирается не панель, а сеть и CPU на шифровании.

Установка и то, что нужно закрыть в первый же час

Штатная установка одной командой:

bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)

Есть и вариант в Docker (docker compose из репозитория) — он удобен, когда на сервере уже есть контейнерный стек, но тогда следите за прокидыванием портов инбаундов и монтированием db/ наружу.

Свежие сборки при чистой установке генерируют случайные логин, пароль, порт панели и webBasePath и печатают их в конце вывода — сохраните их сразу. При апгрейде со старого x-ui можно унаследовать admin/admin на порту 54321, это надо проверить явно.

После установки доступна утилита x-ui:

x-ui # интерактивное меню: обновление, сертификаты, fail2ban, BBR
x-ui status
x-ui restart
x-ui settings # текущие логин, порт, webBasePath
x-ui log # логи панели
x-ui banlog # кого забанил лимит IP
x-ui setting -username op -password 'длинный-пароль' -port 8443 -webBasePath /a7Kd93Ls8Q

Минимум, который делается до того, как на панель попадёт первый платящий клиент:

  1. Свой webBasePath. Панель на / по дефолтному порту (2053 в новых сборках) находится сканерами за часы. Длинный случайный путь — самая дешёвая защита.
  2. Не выставлять панель в интернет вообще. Чистый вариант: Listen IP 127.0.0.1 и доступ через SSH-туннель.

``bash ssh -L 2053:127.0.0.1:2053 root@ВАШ_СЕРВЕР # затем http://127.0.0.1:2053/ваш_путь/ ` Если панель должна быть снаружи — только TLS на своём домене и ограничение по источнику: `bash ufw allow from 203.0.113.10 to any port 8443 proto tcp ufw deny 8443/tcp ` Учтите: если на сервере крутится Docker, правила ufw не действуют на проброшенные контейнерами порты — их закрывают в цепочке DOCKER-USER`.

  1. TLS отдельно на порт панели и отдельно на порт подписки. Сертификат выпускается из меню x-ui (acme, DNS- или HTTP-валидация) и указывается в Panel Settings двумя разными полями.
  2. 2FA и Secret Token. Для панели, торчащей наружу, — обязательно. Честная оговорка: после включения 2FA скриптовый логин в API ломается (нужен код в форме входа), поэтому ботам обычно оставляют отдельный вариант доступа или ходят к панели по localhost.
  3. fail2ban. Ставится пунктом меню; фильтр 3x-ipl, логи /var/log/3xipl.log и /var/log/3xipl-banned.log. Тот же механизм обслуживает лимит IP на клиента — см. следующий раздел.

Лимиты трафика, срока и IP на клиента: как устроено внутри

Ради этого панель обычно и берут. У каждого клиента внутри инбаунда свой набор ограничений:

Поле в UIЧто делаетКак хранится
Total Flow (GB)лимит суммарного трафика up+downв БД — байты, 0 = без лимита
Expire Dateдата отключенияunix-время в миллисекундах
IP Limitмаксимум одновременных IPцелое, 0 = без лимита
Reset (days)автосброс счётчика трафика раз в N днейцелое, 0 = не сбрасывать
Emailуникальный идентификатор клиента в статистикестрока, менять больно
Subscription (subId)связывает клиента со ссылкой-подпискойстрока
Telegram IDадресат уведомлений ботастрока

Логика отключения простая: как только up+down >= total либо now > expiry_time, клиент помечается исчерпанным и Xray перестаёт его пускать. Считаются трафик и срок независимо — сгорает то, что наступит раньше. Исчерпанные собираются в отдельный список, откуда их массово удаляют или продлевают. Автопродления срока нет: продление — руками, ботом или через API.

Полезная деталь: отсчёт срока с первого подключения. Если задать срок в днях, а не датой, панель кладёт в expiry_time отрицательное значение, и таймер стартует в момент первого коннекта. Удобно для триалов и заранее нарезанных ключей — ключ не сгорает, пока лежит непроданным. Побочный эффект: любые ваши SQL-отчёты должны отдельно обрабатывать expiry_time < 0, иначе такие клиенты выглядят «просроченными в 1970 году».

Главная ловушка — IP Limit. Он реализован не в ядре, а разбором access-лога Xray: панель считает уникальные IP на email и через fail2ban банит лишние. Следствия:

  • если в Xray Configs → log параметр access выставлен в none, лимит IP не работает вообще, и список онлайн-клиентов будет пустым;
  • это лимит по IP, а не по устройствам: телефон, переключившийся с Wi-Fi на LTE, какое-то время выглядит как два подключения, поэтому 1 почти всегда больно — рабочий минимум 2–3;
  • за NAT несколько разных людей с одного адреса считаются как один клиент;
  • бан отрабатывает с задержкой в десятки секунд и снимается по таймеру fail2ban, а не мгновенно.

Включение лога в шаблоне конфига:

"log": {
 "access": "/usr/local/x-ui/access.log",
 "error": "/usr/local/x-ui/error.log",
 "loglevel": "warning"
}

Ротация обязательна — на нескольких сотнях активных клиентов access.log растёт быстро и способен забить диск за неделю. Xray не переоткрывает файл по сигналу, поэтому только copytruncate:

cat >/etc/logrotate.d/xray <<'EOF'
/usr/local/x-ui/*.log {
 daily
 rotate 3
 missingok
 notifempty
 copytruncate
 compress
}
EOF

Статистика, подписка и Telegram-бот: что реально закрывает панель

Статистика. Счётчики берутся из stats API Xray и пишутся в базу: трафик по инбаунду, по клиенту, признак онлайна. Сброс — точечно по клиенту, по инбаунду или целиком. Исторических графиков «по дням» нет: панель показывает накопленный итог с момента последнего сброса. Ответить «сколько клиент выкачал в мае» без внешнего сборщика невозможно — если нужны графики и алерты, данные снимают снаружи (из БД или API) и складывают в свой Prometheus/Grafana.

Подписка. Встроенный subscription-сервис поднимается отдельным слушателем (по умолчанию порт 2096) со своим путём, доменом и сертификатом. Клиент получает https://sub.example.com:2096/sub/<subId> — base64-список ссылок; по параллельному пути /json/<subId> отдаётся JSON-формат для клиентов, которые его понимают. Настраиваются Update Interval, заголовки профиля и имя.

Ограничение по сравнению с Marzban/Remnawave: шаблонизации подписки в 3x-ui практически нет. Профиль с кастомным routing, набором правил и отдельными remarks под каждое приложение вы на ней не соберёте — отдаётся то, что панель сгенерировала из инбаундов. Обходной путь один: свой прокси перед подпиской, который переписывает выдачу (заодно там же удобно ставить Cache-Control: no-store — часть мобильных клиентов агрессивно кэширует старую подписку).

Telegram-бот. Токен, admin chat ID и cron-расписание задаются в Panel Settings. Что реально полезно оператору:

  • отчёт по трафику и клиентам в чат по расписанию;
  • уведомления, когда у клиента заканчивается трафик или срок;
  • поиск клиента по email/UUID и выдача ссылки прямо в чате;
  • автоматическая отправка x-ui.db в чат по расписанию — самый дешёвый оффсайт-бэкап из существующих (и одновременно утечка всех ключей, если чат не приватный);
  • рестарт панели командой.

Биллинга и продажи подписок бот не делает — это админский пульт, а не магазин. Для продаж всё равно понадобится свой бот, который ходит в API.

База, бэкап, перенос и прямые запросы

Вся жизнь панели — в одном файле, и относиться к нему надо как к связке ключей: в нём и UUID клиентов, и приватные ключи Reality, и хеш пароля админа.

Бэкап из UI — кнопка, отдающая x-ui.db. На сервере правильнее делать консистентную копию средствами SQLite, а не cp на живой базе:

cat >/usr/local/bin/xui-backup.sh <<'EOF'
#!/bin/bash
set -e
DST=/root/xui-backup
mkdir -p "$DST"
TS=$(date +%F_%H%M)
sqlite3 /etc/x-ui/x-ui.db ".backup '$DST/x-ui-$TS.db'"
tar czf "$DST/cert-$TS.tgz" /root/cert 2>/dev/null || true
find "$DST" -type f -mtime +14 -delete
EOF
chmod +x /usr/local/bin/xui-backup.sh
( crontab -l 2>/dev/null; echo "17 4 * * * /usr/local/bin/xui-backup.sh" ) | crontab -

Восстановление и переезд на другой сервер — одна и та же процедура:

# на новом сервере: та же или более свежая версия панели
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)
systemctl stop x-ui
cp /root/x-ui-2026-07-20_0417.db /etc/x-ui/x-ui.db
chown root:root /etc/x-ui/x-ui.db && chmod 600 /etc/x-ui/x-ui.db
systemctl start x-ui && x-ui status

Довниз (положить базу от новой версии в старую панель) не делайте — миграции схемы в одну сторону. После переезда меняются IP и, возможно, домен: инбаунды переедут как есть, но ссылки клиентов будут указывать на старый адрес. Если адрес входа зашит в подписку, а не в сами ключи, миграция для пользователей проходит незаметно — ещё один аргумент отдавать клиентам ссылку-подписку, а не голый vless://.

Прямые запросы к базе экономят много времени, счётчики лежат в client_traffics:

apt install -y sqlite3

# топ-20 по расходу
sqlite3 -header -column /etc/x-ui/x-ui.db \
"select email,
 round((up+down)/1073741824.0,2) as gb,
 round(total/1073741824.0,2) as limit_gb,
 case when expiry_time>0 then datetime(expiry_time/1000,'unixepoch')
 when expiry_time<0 then 'не активирован'
 else 'бессрочно' end as expires,
 enable
 from client_traffics order by up+down desc limit 20;"

# у кого срок истекает в ближайшие 3 суток
sqlite3 /etc/x-ui/x-ui.db \
"select email, datetime(expiry_time/1000,'unixepoch')
 from client_traffics
 where expiry_time > strftime('%s','now')*1000
 and expiry_time < (strftime('%s','now')+259200)*1000;"

Писать в базу на живой панели не стоит: сами клиенты хранятся ещё и в JSON-поле settings таблицы inbounds, и рассинхрон двух мест ловится потом долго. Для изменений — API:

BASE=https://panel.example.com:8443/ВАШ_ПУТЬ
curl -s -c /tmp/c.txt -X POST $BASE/login -d 'username=op&password=ПАРОЛЬ'
curl -s -b /tmp/c.txt $BASE/panel/api/inbounds/list | jq '.obj[].remark'

# добавить клиента: 100 ГБ, без срока, 3 IP
curl -s -b /tmp/c.txt -X POST $BASE/panel/api/inbounds/addClient \
 --data-urlencode 'id=1' \
 --data-urlencode "settings={\"clients\":[{\"id\":\"$(cat /proc/sys/kernel/random/uuid)\",\"email\":\"user42\",\"totalGB\":107374182400,\"expiryTime\":0,\"enable\":true,\"limitIp\":3,\"subId\":\"sub42\",\"flow\":\"\"}]}"

curl -s -b /tmp/c.txt -X POST $BASE/panel/api/inbounds/resetClientTraffic/1/user42

Обратите внимание на totalGB: имя поля обманывает, значение задаётся в байтах. Есть также updateClient, delClient, getClientTraffics/{email}, onlines. Но API здесь — надстройка над сессией панели: авторизация по cookie, часть параметров передаётся строкой с вложенным JSON, поля меняются между версиями. Для бота-продажника хватает, для серьёзной интеграции — заметно менее приятно, чем документированные REST API соседей.

3x-ui vs Marzban vs Remnawave: чем отличаются и кому что

Сравнение по осям, которые реально меняют жизнь оператора:

3x-uiMarzbanRemnawave
СтекGo, один бинарник + SQLitePython/FastAPI + SQLite/MySQLTypeScript/NestJS + PostgreSQL, Docker
Модельпанель = один серверпанель + marzban-nodeпанель + ноды как сущность первого класса
Один юзер на N серверовнет: свой клиент на каждой панелида, один юзер → все нодыда, юзер → squad из нод
Подпискавстроенная, почти без шаблоновшаблонизируемая (Jinja)шаблоны + правила выдачи, HWID-привязка
APIHTTP поверх сессии панелиREST + JWT, документированREST + API-ключи, документирован
Админы и ролиодин аккаунтsudo + дополнительные админынесколько администраторов
Лимит устройствпо IP из access.log, грубопо IP, аналогичнолимит по HWID устройств
Ресурсы под панельдесятки МБ RAMумеренноощутимо больше (Postgres + сервисы)
Порог входанизкий: 15 минут до первого ключасреднийсредний, ставится по инструкции
Развитиеактивноепо наблюдениям, замедлилось; часть сообщества ушла на форкиактивное

Кому 3x-ui. Один-два сервера, до нескольких сотен клиентов, продажи через своего бота или руками. Нужна панель, которая ставится за вечер, ест копейки ресурсов и не тащит Docker-стек. Отдельный сильный сценарий — «сервер у нового хостера на пробу»: подняли, проверили доступность подсети у операторов, снесли.

Кому Marzban. Уже есть работающий сервис и интеграции — мигрировать без причины смысла нет. Для нового проекта выбирать его стоит осознанно, зная про темп развития.

Кому Remnawave. Несколько локаций, один пользователь должен видеть все серверы в одной подписке, нужны роли, API-ключи под биллинг, HWID-лимиты и внятное добавление/вывод ноды.

Практическое правило: пока сервер один — разницы почти нет, и 3x-ui выигрывает простотой. На третьем сервере схема «три панели» начинает стоить дороже, чем переезд на панель с нодами. Третья панель — это ещё один набор клиентов, ещё одна база для бэкапа и ручная синхронизация продлений в трёх местах.

Где 3x-ui упирается: ограничения, о которых узнают поздно

Честный список того, что всплывает после нескольких месяцев эксплуатации:

  • Один администратор. Ролей, аккаунтов для поддержки, разграничения прав и журнала действий нет. Дать доступ саппорту = отдать полный доступ к панели и ко всем ключам.
  • Нет истории трафика. Только накопленный счётчик — «сколько было в мае» отвечает внешний сборщик, не панель.
  • API привязан к сессии и меняется между версиями. Обновление панели вполне способно сломать самописного бота: тестируйте апдейт на копии базы, а не в проде.
  • Ручные правки config.json теряются при первом же рестарте. Всё кастомное — только через шаблон в Xray Configs.
  • SQLite — не бесплатная магия. На тысячах клиентов и частой записи счётчиков появляются подтормаживания и database is locked; лечится это не тюнингом, а переездом на панель с нормальной СУБД.
  • Мультисервер отсутствует как концепция: ни общей базы клиентов, ни единой подписки, ни автоматического исключения упавшей ноды.
  • Переключение версии Xray из панели удобно, но опасно. Смена мажорной версии меняет поведение транспортов; на проде переключайте только после проверки на тестовой машине и держите наготове предыдущую.

И отдельная категория — то, что панель в принципе не решает. Когда IP ноды попадает под блокировку у оператора, ни 3x-ui, ни Marzban, ни Remnawave тут ни при чём: проблема на уровне адреса и маршрута, а не панели. Лечится это слоем перед нодой — вход через whitelist-CDN, где клиент идёт на «белый» домен и адрес из разрешённого пула, а сама нода закрыта origin-файрволом и перестаёт быть мишенью. Практика подключения разобрана отдельно, в материале про 3x-ui за CDN; общая логика белых списков — в обзоре обхода белых списков.

Два технических факта, на которых чаще всего спотыкаются при такой связке, стоит держать в голове заранее:

  1. У Yandex CDN нет POST, поэтому аплинк XHTTP уходит GET-ом, а GET допустим только при явно заданном "mode": "packet-up". Убрать режим «чтобы было как в документации» — сломать вход. Подробности — в разборе packet-up и XHTTP.
  2. Блок extrapath) на ноде и в клиентской ссылке должен совпадать символ в символ. Экзотические поля обфускации ломают совместимость между версиями Xray: клиент на другом ядре просто не поднимет соединение, а в логах будет невнятная ошибка рукопожатия.

Вывод по панели: 3x-ui хороша ровно в своей нише «один сервер, минимум обвязки, максимум скорости запуска». Переоценивать её не надо, но и менять на тяжёлую панель до появления второй-третьей локации смысла нет.

Частые вопросы

Что такое 3x-ui и чем она отличается от старого x-ui?

3x-ui — веб-панель на Go для управления Xray-core: инбаунды, клиенты, лимиты, подписка, статистика. Она выросла как форк заброшенной панели x-ui от Vaxilu и ушла далеко вперёд: Reality и XHTTP, лимиты по трафику/сроку/IP на каждого клиента, встроенная подписка, Telegram-бот, 2FA, переключение версий Xray из UI. Оригинальный x-ui сегодня ставить не стоит — там нет ни современных транспортов, ни части защит панели.

Можно ли на 3x-ui собрать мультисерверный VPN-сервис?

Полноценно — нет. Понятия ноды в панели не существует: каждая копия управляет только локальным Xray, своей базой и своими клиентами. Технически сервис на нескольких серверах собрать можно — поднять по панели на каждом и склеить выдачу своим прокси подписки, который отдаёт клиенту список всех входов. Но добавление клиента, продление и сброс трафика придётся делать через API на каждой панели отдельно, и любая рассинхронизация — ваша. С третьего сервера дешевле переехать на панель с нодами (Remnawave, Marzban), чем поддерживать этот зоопарк.

Почему не работает IP Limit и пустой список онлайн-клиентов?

Почти всегда — отключён access-лог Xray. Лимит по IP и определение онлайна построены на разборе этого лога, и при "access": "none" считать просто нечего. Пропишите в Xray Configs путь (/usr/local/x-ui/access.log), перезапустите панель, убедитесь что файл растёт, настройте logrotate с copytruncate и проверьте, что fail2ban установлен из меню x-ui. Кого банит лимит, видно в x-ui banlog и /var/log/3xipl-banned.log. И не ставьте лимит 1: переключение с Wi-Fi на мобильную сеть на время даёт два разных IP.

Что происходит с клиентом, когда кончается трафик или срок?

Он перестаёт пускаться и помечается в панели как исчерпанный. Срок и трафик считаются независимо: сгорает то, что наступит раньше. Автопродления срока нет, а автосброс трафика есть — поле Reset обнуляет счётчик раз в N дней, это удобно для тарифов «X ГБ в месяц». Отдельный приём: если задать срок в днях вместо конкретной даты, отсчёт начнётся с первого подключения — ключ не протухает, пока лежит непроданным (в базе такой срок хранится отрицательным числом).

Как перенести 3x-ui на другой сервер без потери клиентов?

Скопировать базу. Ставите панель той же или более свежей версии на новом сервере, systemctl stop x-ui, кладёте бэкап в /etc/x-ui/x-ui.db с правами 600, systemctl start x-ui — инбаунды, клиенты и счётчики на месте. Отдельно перенесите /root/cert и поправьте адрес входа в инбаундах и настройках подписки. Базу от новой версии в старую панель не кладите: миграции схемы идут только вперёд. Если клиенты сидят на ссылке-подписке, а не на голых vless://, миграция для них пройдёт незаметно.

Стоит ли мигрировать с 3x-ui на Remnawave?

Смотрите на количество локаций и на то, кто трогает панель. Один сервер, один админ, продажи через бота — 3x-ui закрывает задачу полностью, и миграция даст только рост потребления ресурсов. Появились вторая-третья нода, нужны единая подписка на все входы, несколько администраторов, API-ключи под биллинг, лимит по устройствам вместо грубого счёта IP — тогда переезд окупается быстро, потому что вы перестаёте вручную синхронизировать несколько независимых баз клиентов.

3x-ui спасёт, если IP сервера заблокировали?

Нет, и никакая другая панель тоже. Панель управляет клиентами и конфигом Xray, а блокировка происходит на уровне адреса и маршрута до него. Варианты — менять IP (временно и дорого), уходить в подсети хостеров, которые попадают в белые списки, либо ставить перед нодой слой распространения: whitelist-CDN, где пользователь подключается к «белому» домену и адресу, а origin закрыт файрволом и виден только фронту. Панель при этом остаётся любой — меняется только инбаунд на ноде: XHTTP с mode: packet-up и совпадающими path/extra на сервере и в клиенте.

Whitelisted-вход для вашего VPN-сервиса

Clearway даёт «белый» CDN-вход перед вашей нодой — устойчивый к троттлингу операторов. Первые 10 ГБ бесплатно, без карты.

Попробовать →