Блог Clearway

3x-ui: установка на VPS скриптом с GitHub или в Docker

Коротко

Установить 3x-ui на чистый VPS (Debian 12 или Ubuntu 22.04/24.04, 1 GB RAM, обязательно systemd) — это одна команда: bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh). Скрипт скачивает последний релиз, кладёт панель в /usr/local/x-ui/, базу — в /etc/x-ui/x-ui.db, ставит юнит x-ui.service и CLI x-ui, а на чистой установке один раз печатает случайные логин, пароль, порт и webBasePath — сохраните их сразу, потом их видно только через x-ui settings. Альтернатива — образ ghcr.io/mhsanaei/3x-ui строго с network_mode: host, иначе каждый новый инбаунд-порт придётся публиковать руками. В тот же день: закрыть порт панели файрволом на всех, кроме своего IP, включить TLS и 2FA, настроить бэкап x-ui.db через sqlite3.backup. Установка панели не делает ноду устойчивой к блокировкам — блокируется IP ноды, а не панель.

Что вы ставите и что нужно от VPS

3x-ui — веб-панель поверх Xray-core, а не отдельный протокол и не замена Xray. Панель управляет инбаундами, клиентами, лимитами трафика и сроками, отдаёт подписку, считает статистику, умеет телеграм-бота. Трафик гоняет Xray, его бинарь лежит внутри установки — в /usr/local/x-ui/bin/.

3x-ui GitHub: какой репозиторий брать. Единственный источник скрипта и образов — MHSanaei/3x-ui. Легаси-панель vaxilu/x-ui и форк FranzKafkaYu/x-ui — другие проекты: своя схема БД, свой набор транспортов, развитие давно остановилось. Ставить «x-ui» по гайдам 2022 года в 2026-м смысла нет — свежих транспортов (XHTTP и его режимов) там просто не будет.

РесурсМинимумКомфорт (100–300 активных)Комментарий
RAM512 MB1–2 GBпанель и Xray нетребовательны к памяти
CPU1 vCPU2 vCPUупор в шифрование на пиках, не в панель
Диск8–10 GB20 GB SSDБД крошечная, место ест access.log
ОСDebian 12, Ubuntu 22.04/24.04те жеRHEL-семейство и Arch поддержаны, но грабель при установке заметно больше
Архитектураamd64 / arm64сборки под armv7/386/s390x в релизах встречаются, но набор ассетов меняется — сверяйтесь с Releases

Что подготовить до того, как установить 3x-ui:

  • root и systemd. Скрипт ставит системный юнит. В OpenVZ/LXC-контейнерах без systemd установка не заработает — это самая частая причина «скрипт отработал, сервис не стартует».
  • Домен и A-запись — для TLS на панели и на странице подписки. На Cloudflare для домена, к которому подключаются клиенты, держите DNS only (серое облако): проксирующий режим ломает Reality и прямой TLS.
  • Свободные 80/443, если планируете выпускать сертификат встроенным acme в standalone-режиме. Системный nginx/apache с этих портов уберите заранее.
  • Проверенный IP. Что подсеть не в чёрных списках и что хостер не режет исходящий трафик, дешевле выяснить до установки, чем после переноса клиентов.

Установка 3x-ui скриптом с GitHub

Штатный способ — установочный скрипт из репозитория. На чистом Debian/Ubuntu:

apt update && apt install -y curl socat tzdata sqlite3
bash <(curl -Ls https://raw.githubusercontent.com/mhsanaei/3x-ui/master/install.sh)

Скрипт определяет ОС и архитектуру, тянет архив последнего релиза (не код из master), разворачивает панель, ставит systemd-юнит и CLI. В прод полезнее ставить конкретную версию — тогда обновление становится осознанным действием, а не побочным эффектом переустановки:

VERSION=v2.6.6 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION

Актуальный тег смотрите в Releases на GitHub: версии здесь меняются часто, и копировать номер из статьи (в том числе из этой) не надо — он приведён как формат команды, а не как рекомендация.

Что оказалось на диске:

ПутьЧто это
/usr/local/x-ui/бинарь панели; в bin/ — Xray и geo-файлы
/etc/x-ui/x-ui.dbSQLite: инбаунды, клиенты, настройки панели. Главный объект бэкапа
/usr/bin/x-uiCLI-меню управления
/etc/systemd/system/x-ui.serviceюнит автозапуска
/usr/local/x-ui/bin/config.jsonконфиг Xray, который генерирует панель; править руками бессмысленно — перезапишется при следующем сохранении инбаунда

Критичный момент первого запуска. На чистой установке скрипт генерирует случайные логин, пароль, порт панели и webBasePath и печатает их один раз в конце вывода. Скопируйте в менеджер паролей сразу. Если ваша версия повела себя иначе и пустила по admin/admin — меняйте креды немедленно: такие панели находят сканерами за часы.

Проверка после установки:

systemctl status x-ui --no-pager
ss -tlnp | grep -E 'x-ui|xray'
x-ui settings # текущий порт, webBasePath, логин
/usr/local/x-ui/bin/xray-linux-amd64 -version # для arm64 — xray-linux-arm64

Версию Xray стоит посмотреть сразу: именно она, а не версия панели, определяет, какие транспорты и поля вам доступны. Меню управления открывается командой x-ui (старт/стоп, обновление, сброс учётных данных, сертификаты, geo-файлы). Нумерация пунктов между релизами меняется — ориентируйтесь на названия, а не на номер.

Установка 3x-ui в Docker

Docker выбирают ради изоляции от системы и предсказуемого отката по тегу образа. Функционально панель та же.

mkdir -p /opt/3x-ui && cd /opt/3x-ui

docker-compose.yml:

services:
 3x-ui:
 image: ghcr.io/mhsanaei/3x-ui:latest
 container_name: 3x-ui
 hostname: node1
 volumes:
 - $PWD/db/:/etc/x-ui/
 - $PWD/cert/:/root/cert/
 environment:
 XRAY_VMESS_AEAD_FORCED: "false"
 XUI_ENABLE_FAIL2BAN: "true"
 tty: true
 network_mode: host
 restart: unless-stopped
docker compose up -d && docker compose logs -f

Ловушка №1 — сеть. network_mode: host здесь не прихоть: инбаунды в 3x-ui создаются динамически, и при bridge-сети каждый новый порт пришлось бы дописывать в ports: и пересоздавать контейнер. Симптом типовой: панель открывается, инбаунд создан, клиенты не подключаются. Если host-режим недоступен, порты публикуются явно и диапазон лучше зарезервировать заранее:

 ports:
 - "2053:2053" # панель
 - "443:443" # инбаунд
 - "25454:25454" # запасной инбаунд

Ловушка №2 — файрвол. С network_mode: host контейнер живёт в сетевом стеке хоста, и правила ufw работают как обычно. А вот при публикации через ports: Docker пишет свои правила в цепочку DOCKER до пользовательских, и «закрытый» в ufw порт остаётся доступен из интернета. Ограничивать такие порты нужно через DOCKER-USER:

iptables -I DOCKER-USER -p tcp --dport 2053 '!' -s 203.0.113.7 -j DROP

Правило не переживёт перезагрузку без iptables-persistent — либо ставьте пакет, либо возвращайтесь к host-режиму.

Отличия в эксплуатации:

  • CLI живёт внутри контейнера: docker exec -it 3x-ui x-ui;
  • обновление — docker compose pull && docker compose up -d --force-recreate (данные в ./db/ не трогаются), откат — фиксацией тега вместо latest;
  • бэкап — файл ./db/x-ui.db на хосте;
  • XUI_ENABLE_FAIL2BAN: "true" поднимает fail2ban внутри контейнера; он нужен для IP-лимитов на клиента, а те, в свою очередь, требуют включённого access.log у Xray.

Первый вход и минимальная настройка

Адрес панели: http://<IP>:<PORT>/<webBasePath>/. Без базового пути будет 404 — это не поломка, а штатное поведение: панель намеренно не отвечает на корень, чтобы не отдаваться массовым сканерам.

  1. Panel Settings. Нестандартный порт, свой длинный webBasePath. После сохранения панель перезапускается — заходить уже по новому адресу.
  2. Первый инбаунд. Inbounds → Add Inbound: VLESS, транспорт по вашей стратегии — Reality для прямых подключений, XHTTP, если вход будет за CDN. Порт инбаунда откройте и в файрволе ОС, и в security group хостера: это два независимых слоя.
  3. Подписка. Panel Settings → Subscription: включить, задать порт (по умолчанию 2096), путь и домен. Клиент получает ссылку вида https://sub.example.com:2096/sub/<subId> — это удобнее раздачи сырых vless://: при смене хоста конфиг обновится у всех разом.
  4. Логи Xray. access.log нужен для IP-лимитов и разбора инцидентов, но растёт быстро. Включаете — сразу ставьте ротацию (путь берите тот, что указан в Xray Settings → Log):
cat >/etc/logrotate.d/xray <<'EOF'
/usr/local/x-ui/bin/access.log {
 daily
 rotate 3
 compress
 copytruncate
 missingok
 notifempty
}
EOF

copytruncate здесь обязателен: Xray не переоткрывает файл по сигналу, и после обычного rotate продолжит писать в удалённый inode — место не освободится.

  1. Проверка на живом клиенте. Создайте тестового пользователя, импортируйте подписку в Happ / v2rayN / Streisand и параллельно смотрите journalctl -u x-ui -f — там видно и панель, и вывод Xray.

Мелочь, которая иногда даёт больше, чем тюнинг конфига, — BBR на длинных RTT:

printf 'net.core.default_qdisc=fq\nnet.ipv4.tcp_congestion_control=bbr\n' >>/etc/sysctl.conf && sysctl -p

По наблюдениям, заметный эффект даёт на дальних маршрутах и потерях; на коротком плече разница в пределах погрешности.

Защита панели: чек-лист того же дня

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

1. Логин, пароль, секрет-токен. В меню x-ui есть сброс учётных данных. Пароль — длинный, из менеджера, не переиспользованный.

2. Свой порт и длинный webBasePath. Путь в 24–32 случайных символа — самая дешёвая защита от массовых сканеров:

head -c 24 /dev/urandom | base64 | tr -d '/+='

3. TLS на панель. Без него пароль и токены ходят открытым текстом. В меню x-ui есть выпуск сертификата через acme.sh: файлы кладутся в /root/cert/<domain>/, дальше в Panel Settings указываются пути к fullchain.pem и privkey.pem, затем systemctl restart x-ui.

4. Файрвол — важнее всего остального. Порт панели не должен быть доступен всему интернету:

ufw default deny incoming
ufw allow 22/tcp
ufw allow from 203.0.113.7 to any port 2053 proto tcp # панель — только с вашего IP
ufw allow 443/tcp # порт инбаунда для клиентов
ufw enable

Правила ufw не отменяют облачный security group у хостера — настраивайте оба слоя. И помните про DOCKER-USER, если панель в контейнере с опубликованными портами.

5. Лучший вариант — панель вообще не наружу. В Panel Settings можно задать listen IP 127.0.0.1 и ходить через SSH-туннель:

ssh -L 2053:127.0.0.1:2053 root@node1
# затем http://127.0.0.1:2053/<webBasePath>/ в браузере

6. 2FA и телеграм-бот. Двухфакторка (TOTP) в свежих версиях включается в настройках панели. У бота ограничьте admin-id своим chat id — иначе он отвечает командами кому угодно.

7. Бэкап БД по cron. Копировать живой SQLite через cp рискованно — можно поймать несогласованный снимок. Корректно:

cat >/usr/local/bin/xui-backup.sh <<'EOF'
#!/bin/bash
set -e
install -d /root/xui-backup
sqlite3 /etc/x-ui/x-ui.db ".backup '/root/xui-backup/x-ui-$(date +%F).db'"
find /root/xui-backup -name 'x-ui-*.db' -mtime +14 -delete
EOF
chmod +x /usr/local/bin/xui-backup.sh

В cron: 0 4 * * * /usr/local/bin/xui-backup.sh. Хранение — вне этого же сервера. В x-ui.db лежат все клиенты; потерять её — значит перевыпускать конфиги всей базе.

8. SSH. Вход по ключам, PermitRootLogin prohibit-password, парольная аутентификация выключена.

Типичные ошибки установки и как их чинить

СимптомВероятная причинаЧто делать
Панель не открывается, connection refusedсервис не поднялся или порт закрытsystemctl status x-ui, `ss -tlnp \grep x-ui`, проверить ufw и SG хостера
404 по http://IP:PORT/забыт webBasePathx-ui settings — подставить путь в URL
Скрипт отработал, x-ui.service не стартуетконтейнер без systemd (OpenVZ/LXC)сменить тип VPS на KVM либо ставить docker-вариант
Панель отвалилась сразу после включения TLSневерные пути к сертификатуобнулить пути в БД (см. ниже) и перезапустить
Забыты логин/пароль/портслучайные креды из установки не сохраненыменю x-ui → сброс учётных данных; порт и путь — x-ui settings
Failed to start x-uiпорт занят nginx/apache`ss -tlnp \grep -E ':80\:443'`, остановить сервис или сменить порт панели
Инбаунды «красные», Xray не стартуетбитый geo-файл или невалидный конфиг`journalctl -u x-ui -n 200 --no-pager \grep -i xray, обновить geo из меню x-ui`
В Docker клиенты не подключаются к новому инбаундуbridge-сеть вместо hostnetwork_mode: host либо явная публикация портов
VMess не работает, VLESS работаетрасхождение системного времени (окно AEAD узкое)timedatectl set-ntp true, проверить timedatectl status
Панель тормозит, «database is locked»распухший access.log и статистикаротация логов, отключить лишнее логирование
После обновления панель не подняласьнесовместимость релизаоткат: установка предыдущего тега скриптом либо фиксированный docker-тег

Сброс путей к сертификату, когда панель после включения TLS перестала отвечать (частый способ закрыть себе дверь снаружи):

systemctl stop x-ui
sqlite3 /etc/x-ui/x-ui.db "update settings set value='' where key in ('webCertFile','webKeyFile');"
sqlite3 /etc/x-ui/x-ui.db "select key,value from settings;" # проверить, что строки существуют
systemctl start x-ui

Оговорка: update меняет только существующие строки. Если ключей в таблице нет, вывод select это покажет — значит, TLS был задан иначе и панель падает по другой причине, ищите её в journalctl -u x-ui.

Правило отладки: разделяйте слои. «Панель не открывается», «Xray не стартует» и «клиент не подключается» — три разные проблемы. Первая лечится в systemd и файрволе, вторая — в логах Xray, третья — в параметрах инбаунда и клиентской ссылке. Смешивать их — верный способ потратить вечер.

Чего установка не решает: IP ноды под белыми списками

Панель поднята, инбаунд работает — устойчивостью это ещё не стало. Слабое место не в 3x-ui, а в IP ноды: статичный адрес из хостинг-диапазона. Когда мобильный оператор переводит сеть в режим белого списка, наружу выпускается трафик только к разрешённым ресурсам, и ДЦ-подсети отваливаются целыми /24 — независимо от того, насколько аккуратно настроен Reality.

Архитектурный ответ — не менять панель, а вынести вход за whitelisted CDN: клиент идёт на «белый» домен edge, edge проксирует до вашей origin-ноды с 3x-ui. Что важно знать до того, как начнёте это строить:

  • Рабочий транспорт через CDN — XHTTP в режиме packet-up; Reality и Hysteria2 edge не пропускает.
  • У Yandex CDN нет POST, поэтому XHTTP-аплинк уходит методом GET, а GET разрешён только при mode packet-up. Это не настройка по вкусу, а жёсткое условие: с другим режимом соединение через такой edge не поднимется.
  • path и блок extra на ноде и в клиенте должны совпадать точь-в-точь. Экзотические obfuscation-поля лучше не трогать вовсе: они ломают совместимость между версиями Xray, и клиент на другой сборке молча перестаёт подключаться.
  • Whitelist привязан к конкретной /24, а не к хостеру целиком, и статус меняется.

Детали XHTTP-инбаунда и ручной сборки клиентской ссылки для 3x-ui за CDN разобраны в отдельном материале. Здесь важен вывод для этапа установки: закладывайте архитектуру так, чтобы наружу смотрел заменяемый слой, а не единственный сервер с вашей базой клиентов. Если поднимать и держать собственный whitelisted edge не хочется, Clearway даёт такой «белый» вход как сервис: нода с 3x-ui остаётся вашей, меняется только то, куда ходит клиент.

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

Чем 3x-ui отличается от x-ui и какой репозиторий брать?

Брать MHSanaei/3x-ui — это активно развиваемая панель со свежими транспортами Xray, включая XHTTP и его режимы. Исходный vaxilu/x-ui и форки вроде FranzKafkaYu/x-ui — другие проекты со своей схемой БД, они давно не обновляются, и гайды 2022 года к 3x-ui неприменимы. В меню x-ui есть пункт миграции со старой панели, но перенос односторонний — снимайте бэкап БД до него.

Хватит ли VPS с 1 GB RAM, чтобы установить 3x-ui?

Да. Для нескольких сотен клиентов достаточно 1 GB RAM и 1–2 vCPU: панель почти не ест ресурсы, нагрузка приходится на Xray и упирается в CPU при шифровании на пиках. Реальный потолок обычно задаёт не сервер, а сетевой канал и лимит трафика хостера. Место на диске съедает не БД (она крошечная), а access.log, если включить его без ротации.

Что выбрать — установочный скрипт или Docker?

Скрипт проще: одна команда, CLI x-ui под рукой, systemd-юнит, привычные пути. Docker даёт изоляцию и предсказуемый откат по тегу образа — полезно, если на сервере есть что-то ещё. Условие docker-варианта — network_mode: host, иначе каждый новый инбаунд-порт придётся публиковать вручную и пересоздавать контейнер; типовой симптом ошибки — панель открывается, а клиенты не подключаются. И учтите, что при публикации портов через ports: ufw их не закрывает — нужна цепочка DOCKER-USER.

Забыл порт и пароль от панели — как войти?

С доступом по SSH всё восстанавливается: x-ui settings показывает текущий порт, webBasePath и логин, а в меню x-ui есть сброс имени пользователя, пароля и секрет-токена. В Docker те же команды выполняются внутри контейнера: docker exec -it 3x-ui x-ui. Если панель перестала отвечать после включения TLS, обнулите webCertFile и webKeyFile в /etc/x-ui/x-ui.db через sqlite3 и перезапустите сервис.

Как поставить конкретную версию 3x-ui и откатиться назад?

Скрипт принимает тег: VERSION=v2.6.6 && bash <(curl -Ls "https://raw.githubusercontent.com/mhsanaei/3x-ui/$VERSION/install.sh") $VERSION. Тем же способом делается откат — указываете предыдущий тег из Releases (номер в примере — иллюстрация формата, актуальный смотрите на GitHub). В Docker роль версии играет тег образа: закрепите его вместо latest, тогда docker compose pull не принесёт неожиданный релиз в прод. Перед любым обновлением снимайте копию x-ui.db.

Что бэкапить и как переехать на другой сервер?

Всё состояние лежит в /etc/x-ui/x-ui.db: инбаунды, клиенты, настройки панели. Переезд — остановить сервис на обоих серверах, скопировать файл, запустить: systemctl stop x-ui, scp /etc/x-ui/x-ui.db root@new:/etc/x-ui/x-ui.db, systemctl start x-ui. Порт панели, webBasePath и учётные данные переедут вместе с базой; поправить придётся то, что завязано на конкретный сервер, — пути к сертификатам и listen-адреса инбаундов. Версии панели на обоих серверах лучше держать одинаковыми: схема БД между релизами мигрирует вперёд, но не назад.

Достаточно ли установить 3x-ui, чтобы сервис работал под блокировками операторов?

Нет. Панель — это управление, а блокируется IP ноды: под режимом белых списков ДЦ-подсети отваливаются целыми /24, и настройки внутри 3x-ui на это не влияют. Устойчивость даёт архитектура входа — XHTTP в режиме packet-up через whitelisted CDN-edge перед нодой, причём path и extra на ноде и в клиенте должны совпадать точь-в-точь. Планируйте это до продакшена, а не после первого шатдауна.

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

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

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