Сначала локализуйте слой, потом чините
Главная ошибка при разборе «3x ui не работает» — начинать с перезапуска панели и пересоздания инбаунда. В 3x-ui два независимых процесса: панель (Go-приложение, systemd-юнит x-ui) и ядро Xray, которое панель запускает дочерним процессом с собранным конфигом /usr/local/x-ui/bin/config.json. Панель может прекрасно открываться, пока ядро лежит, и наоборот.
Первые команды на сервере:
systemctl status x-ui --no-pager
journalctl -u x-ui -n 200 --no-pager
ss -ltnp | grep -E 'x-ui|xray' # видно сразу: слушает панель, слушают ли инбаунды
ls -la /usr/local/x-ui/bin/ # xray-бинарь, config.json, geo-файлы, логи
Если панель в Docker:
docker ps -a | grep 3x-ui
docker logs --tail 200 3x-ui
3x-ui пишет stderr ядра в свой systemd-журнал, поэтому реальная причина отказа инбаунда почти всегда там же, а не в UI. Строки failed to parse json config, address already in use, failed to load geoip — это ядро, а не панель.
| Что видит оператор | Слой | Куда смотреть |
|---|---|---|
| Браузер не открывает панель | Сервис x-ui / сеть | systemctl status x-ui, ss -ltnp, файрвол |
| Панель открыта, Xray «not running» | Ядро Xray | journalctl -u x-ui, run -test |
| Инбаунд зелёный, клиент не коннектится | Параметры транспорта | сверка инбаунда и клиентской ссылки |
| Коннект есть, через 10–60 сек обрыв | Лимиты, рестарты, фронт | limitIp, access.log, буферизация |
| Локально работает, у абонентов нет | Блокировка IP | проверка ноды из мобильной сети |
Идите по таблице сверху вниз: правка extra не поможет, если ядро вообще не стартует. И до любых экспериментов сделайте бэкап базы — в ней все инбаунды, клиенты и настройки панели:
cp /etc/x-ui/x-ui.db /root/x-ui.db.$(date +%F).bak
# откат: systemctl stop x-ui && cp /root/x-ui.db.ДАТА.bak /etc/x-ui/x-ui.db && systemctl start x-ui
Панель 3x-ui не открывается
Текст ошибки в браузере почти однозначно указывает на причину — не игнорируйте его.
| Ошибка браузера | Наиболее вероятная причина |
|---|---|
ERR_CONNECTION_REFUSED | Сервис лежит или слушает другой порт |
| Бесконечная загрузка / таймаут | Порт закрыт: ufw, iptables, security group хостера |
404 page not found | Неверный webBasePath — в сборках 2.x он генерируется случайным |
ERR_SSL_PROTOCOL_ERROR / «сайт не отправил данные» | Заходите по https на панель без сертификата или по http на панель с TLS |
| Панель грузится, логин не принимает | Сброшенные креды, реже — повреждённая SQLite-база |
Посмотреть, что панель реально о себе думает:
/usr/local/x-ui/x-ui setting -show true
Набор флагов CLI отличается между сборками — если команда ругается, сверьтесь с /usr/local/x-ui/x-ui help или зайдите в интерактивное меню командой x-ui (пункты «показать настройки», «сбросить логин/пароль», «сбросить web base path»; нумерация пунктов от версии к версии меняется, ориентируйтесь по названиям).
URL собирайте строго по выводу: http(s)://IP:PORT/<webBasePath>/. Завершающий слэш обязателен — без него часть сборок отдаёт 404.
Восстановление доступа без переустановки:
/usr/local/x-ui/x-ui setting -port 2053
/usr/local/x-ui/x-ui setting -username admin -password 'НовыйПароль'
/usr/local/x-ui/x-ui setting -webBasePath /panel/
systemctl restart x-ui
Проверка изнутри сервера отделяет «панель мертва» от «сеть не пускает»:
curl -sI http://127.0.0.1:2053/panel/ | head -1
Локально 200/307, а снаружи таймаут — дело в файрволе. Открывать порт панели всему интернету не нужно: ограничьте его своим адресом или ходите через SSH-туннель, а наружу оставьте только порты инбаундов.
ufw allow from ВАШ_IP to any port 2053 proto tcp
# либо туннель, панель вообще не торчит наружу:
ssh -L 2053:127.0.0.1:2053 root@SERVER
Частые прикладные случаи: истёк сертификат панели (Let's Encrypt не продлился — панель по https не открывается, по http на том же порту тоже, пока не снимете TLS в настройках); контейнер в состоянии Restarting — почти всегда не примонтирован том с базой (./db/:/etc/x-ui/) или каталог создан с чужими правами. Если подозреваете битую базу: sqlite3 /etc/x-ui/x-ui.db 'PRAGMA integrity_check;'.
Инбаунд не стартует: один битый инбаунд роняет все
Ключевой факт про 3x-ui, который экономит часы: панель собирает из всех инбаундов один config.json и запускает одно ядро. Один невалидный инбаунд роняет процесс целиком — вместе с ним отваливаются все остальные инбаунды и все клиенты. Поэтому «у половины юзеров пропал доступ после того, как я добавил новый инбаунд» — это не совпадение.
Валидация конфига руками (имя бинаря — под вашу архитектуру):
cd /usr/local/x-ui/bin
./xray-linux-amd64 version
./xray-linux-amd64 run -test -config./config.json
jq../config.json > /dev/null # покажет строку с ошибкой JSON
| Что в логе | Причина | Фикс | |
|---|---|---|---|
failed to parse json config | Битый JSON после ручной правки в режиме </> | jq. — почти всегда лишняя запятая | |
address already in use | Порт занят nginx/caddy/другим инбаундом | `ss -ltnp \ | grep:PORT`, сменить или освободить |
unknown network type / инбаунд игнорируется | Ядро не знает транспорт (xhttp на старой сборке) | Обновить Xray в Panel Settings → Xray Configs | |
failed to load geoip / open geoip.dat | Geo-файлы не докачались после обновления | Пункт меню x-ui с обновлением geo, затем рестарт | |
| Ядро стартует и падает в цикле | OOM или переполненный диск | `dmesg -T \ | grep -i oom, df -h /` |
exec format error | Скачан бинарь не под ту архитектуру | uname -m, file./xray-linux-* |
Про версии честно: транспорт xhttp появился в Xray-core ветки 24.11 (переименование splithttp), там же — режимы auto / packet-up / stream-up / stream-one. На ядре 1.8.x инбаунд с "network": "xhttp" не поднимется в принципе, и правки полей в GUI это не изменят. Поэтому version — раньше всего остального.
Вторая частая ловушка — поле flow. xtls-rprx-vision живёт только на raw/tcp с TLS или Reality. Проставили его на инбаунд с ws, grpc или xhttp (или потянули из старой клиентской ссылки) — соединение не установится. Для xhttp flow должен быть пустым.
И отдельно: если инбаунд создавали в JSON-режиме, храните эталонный streamSettings вне панели. При повторном сохранении через обычную форму 3x-ui нормализует структуру и, по наблюдениям, может потерять поля, которых в форме нет — в первую очередь содержимое xhttpSettings.extra. Общий разбор ошибок самого Xray-core (400/404, handshake, версии клиентов) у нас есть отдельной статьёй — здесь только то, что специфично для 3x-ui.
3x ui не подключается: рассинхрон инбаунда и ссылки
Панель зелёная, ядро живое, порт слушает — клиент висит на «connecting». По наблюдениям это почти всегда не ошибка 3x-ui, а расхождение параметров между инбаундом и ссылкой: Xray на ноде просто не узнаёт запрос и молчит, внятной ошибки пользователь не увидит.
| Параметр | На ноде (инбаунд) | В клиентской ссылке | Комментарий |
|---|---|---|---|
| UUID | settings.clients[].id | часть до @ | опечатка = тихий отказ |
| Порт | port | после : (за фронтом — 443) | за CDN клиент всегда идёт на 443 |
| Транспорт | network | type= | xhttp ↔ xhttp, без вариантов |
| Путь | xhttpSettings.path | path= в URL-кодировке | слэши, регистр, завершающий / |
| Режим | xhttpSettings.mode | mode= | при аплинке через GET обязателен packet-up |
extra | xhttpSettings.extra | одноимённые поля клиента | должны совпадать полностью |
| Хост/SNI | зависит от фронта | host=, sni= | за CDN — домен фронта, не IP |
| TLS | security | security= | на origin за CDN — none, у клиента — tls |
Про режим отдельно, потому что это самая дорогая по времени ошибка. Yandex CDN не пропускает POST, поэтому XHTTP-аплинк уходит методом GET, а GET у Xray разрешён только при явно указанном mode: packet-up. Не указали режим или оставили автоопределение — в одном приложении конфиг «работает», в другом молча нет, и выглядит это как плавающая ошибка 3x-ui. Так же критично совпадение extra: значения на ноде и в клиенте должны быть идентичны, а экзотические поля обфускации лучше не использовать вовсе — они ломают совместимость между версиями Xray и между клиентами.
Ловушка именно 3x-ui: панель исходит из того, что клиент подключается туда же, где стоит сервер, и генерирует ссылку/QR прямо на IP ноды. Если вход организован через CDN или reverse-proxy, эта ссылка не годится — она ведёт мимо фронта. Шаблон клиентского URL с доменом фронта собирается вручную один раз на инбаунд, дальше меняется только UUID.
Проверка живости инбаунда снаружи, до всяких клиентов:
curl -sv -o /dev/null --max-time 5 http://IP_НОДЫ:ПОРТ/ваш/путь/ 2>&1 | tail -5
Любой HTTP-ответ (400, 404) означает: порт открыт, ядро слушает. Connection refused — ядро не поднялось или порт закрыт. Таймаут — пакеты не доходят: security group хостера, DROP в iptables или фильтрация на пути.
Два частных случая, которые не про транспорт вообще:
- Не подключается ровно один клиент. Смотрите его карточку в панели: исчерпанный лимит трафика или истёкший срок отключают клиента, ссылка при этом остаётся внешне валидной.
- Не открывается подписка. Sub-сервис 3x-ui слушает свой порт (по умолчанию 2096) и включается отдельно от панели. Если у клиента «пустая подписка», проверьте
ss -ltnp | grep 2096, открыт ли порт наружу и совпадает ли публичный URL подписки с тем, что раздаёте. Транспорт тут ни при чём.
Соединение поднимается и тут же рвётся
Отдельный класс отказов — диагностируется не там, где предыдущие.
- Рестарт ядра при каждом сохранении. 3x-ui пересобирает
config.jsonи перезапускает Xray на любое изменение — добавили клиента, поправили инбаунд, и текущие сессии оборвались. Клиенты переподключаются сами за секунды, но десять правок подряд в час пик дают вал жалоб. Копите изменения и сохраняйте пачкой. - Лимит по IP у клиента.
limitIpсчитает адреса по access-логу Xray: если access-лог выключен, лимит либо не работает, либо ведёт себя непредсказуемо; если включён — пользователь с телефоном и ноутбуком одновременно отваливается. Симптом характерный: 30–60 секунд коннекта, отвал, потом снова работает. Проверяется обнулением лимита у конкретного клиента. - Буферизация и idle-таймауты на фронте. Для xhttp это главный источник обрывов: промежуточный прокси копит поток вместо того, чтобы отдавать его сразу. На nginx нужны
proxy_buffering off;,proxy_request_buffering off;и увеличенныеproxy_read_timeout/proxy_send_timeout(300s и выше); на CDN-фронте — соответствующие параметры вextra, включая поведение SSE-заголовка. - Диск, забитый логами.
access.logXray на нагруженной ноде растёт гигабайтами и лежит рядом с бинарём в/usr/local/x-ui/bin/. ПриNo space left on deviceпадает и ядро, и панель. Лечится logrotate либо уровнемwarningи отключённым access-логом в Panel Settings → Xray Configs. - OOM. VPS на 512–1024 МБ с сотней клиентов: ядро убивает процесс, systemd поднимает заново, у всех обрыв.
df -h /
du -sh /usr/local/x-ui/bin/*.log
dmesg -T | grep -i -E 'oom|killed process' | tail -10
journalctl -u x-ui --since '30 min ago' --no-pager | grep -iE 'restart|killed|panic'
Если в журнале ядро стартует каждые несколько минут без ваших действий — проблема в ресурсах или в падении процесса, а не в клиентах и не в транспорте. Лечить конфигом бесполезно.
Когда дело не в 3x-ui, а в блокировке IP
Последний по порядку, но не по частоте сценарий. Все проверки выше зелёные: панель открывается, ядро работает, curl снаружи отдаёт ответ, с домашнего Wi-Fi клиент подключается. А у части пользователей — глухо, чаще всего у тех, кто сидит с мобильного интернета или в регионе с ограничениями.
Это не ошибка 3x-ui. Пакеты до вашего IP не доходят, ядро о них не узнаёт — в логах Xray будет не «reject», а полное отсутствие соединений от этих пользователей. Отличительный признак именно асимметрия: одни сети работают, другие нет, при одном и том же конфиге.
# на ноде: приходят ли вообще входящие
journalctl -u x-ui -f | grep -i accepted
# со стороны клиента (мобильный интернет, режим модема)
curl -sv --max-time 5 http://IP_НОДЫ:ПОРТ/ 2>&1 | tail -3
Если из «здоровой» сети ответ есть, а с мобильной — таймаут, менять протокол, порт, SNI или пересоздавать ключи на том же адресе бесполезно: фильтруется IP, а не сигнатура. Вариантов два: переехать в подсеть, которая проходит фильтрацию (проверять каждую /24 отдельно — whitelist привязан к подсети, а не к хостеру целиком), либо поставить перед нодой вход на «белом» домене. Whitelist-CDN закрывает второй сценарий: нода остаётся на месте, клиенты идут на домен CDN-фронта, IP origin перестаёт быть точкой отказа. Настройку такого входа именно под 3x-ui — XHTTP-инбаунд, ручная сборка ссылки, файрвол на origin — мы разбирали отдельно.
Сводный чек-лист под руку:
| Симптом | Одна команда для проверки | Куда копать | |
|---|---|---|---|
| Панель не открывается | systemctl status x-ui | сервис, порт, webBasePath, файрвол, сертификат | |
| Xray «not running» | ./xray-linux-amd64 run -test -config config.json | JSON, порт, версия ядра, geo-файлы | |
| Не подключается один клиент | карточка клиента в панели | лимит трафика, срок, limitIp | |
| Не подключаются все | curl на порт инбаунда снаружи | транспорт, path, mode, extra, TLS | |
| Пустая подписка | `ss -ltnp \ | grep 2096` | sub-сервис, порт, публичный URL |
| Обрывы через минуту | journalctl -u x-ui --since '30 min ago' | рестарты, OOM, диск, буферизация | |
| Работает не во всех сетях | curl с мобильного интернета | блокировка IP, /24, вход через CDN |