← Вернуться к оглавлению

🛡️ Установка 3x-ui (VPN-панель XRay)

Версия 1.0 | 12 сентября 2026 | Панель: https://vpn.avk27.ru

📋 Исходные данные

💡 Важно: порт 443 на сервере занимает NPM. VPN-трафик (VLESS-Reality и т.п.) — это сырой TCP/UDP, NPM его проксировать не умеет, поэтому входящие подключения клиентов публикуются на отдельном диапазоне портов 20000–20100, а панель управления идёт через NPM по HTTPS.

1️⃣ Решение: контейнер или система

3x-ui можно установить официальным скриптом (bash <(curl -Ls .../install.sh), systemd-служба на хосте) или Docker-образом ghcr.io/mhsanaei/3x-ui. Для этого сервера выбран Docker-контейнер:

КритерийDocker-контейнер ✅Установка на уровне системы
Соответствие архитектуре сервераВся инфраструктура (NPM, Portainer, Dozzle, Uptime Kuma, проекты) — в DockerЕдинственный systemd-сервис рядом с Docker-инфраструктурой
Доступ к панелиПо имени контейнера 3x-ui:2053 из сети webproxy → NPM даёт HTTPS + сертификат Let's EncryptПанель слушает порт на хосте, нужен отдельный порт в ufw и проброс через IP:порт
Обновлениеdocker compose pull && up -d, образ целиком (панель + Xray согласованы)Повторный запуск скрипта, обновления Xray привязаны к релизам панели
Логи и управлениеDozzle, Portainer — как у остальных сервисовjournalctl, отдельная служба
Полное удалениеdocker compose down + удаление каталога, следов на хосте нетСкрипт uninstall + ручная чистка /usr/local/x-ui, /etc/x-ui, systemd
ИзоляцияПанель не публикуется наружу (только через NPM)Панель по умолчанию доступна с любого IP на своём порту

⚠️ Предыстория: на сервере параллельно существовали обе установки — Docker-контейнер (август) и системная установка (24.08, перезапущена 12.09). Хост vpn.avk27.ru в NPM указывал на 193.32.179.138:3571, тогда как системная панель слушала порт 3517 (переставленные цифры) — из-за этого панель по домену не открывалась. Обе установки удалены, выполнена чистая установка в Docker.

🏗️ Схема установки

Клиент (браузер, админ)
  │
  ▼  https://vpn.avk27.ru  (порт 443)
Nginx Proxy Manager ───► контейнер 3x-ui:2053   (панель, сеть webproxy)
                                │
                                ├── база: /opt/3x-ui/data/db (sqlite)
                                └── серт: /opt/3x-ui/data/cert

VPN-клиенты (v2rayNG, Streisand, ...)
  │
  ▼  vpn.avk27.ru:20000–20100 (TCP/UDP напрямую, мимо NPM)
хост:20000-20100 ──► контейнер 3x-ui (inbounds Xray)
ufw: диапазон 20000:20100/tcp и /udp разрешён
        

2️⃣ Очистка следов предыдущих установок

Проверяем и удаляем обе старые установки (данные старых подключений при этом теряются):

Поиск следов

# Системная установка
which x-ui; ls /usr/local/x-ui /etc/x-ui 2>/dev/null; systemctl status x-ui

# Docker-установка
docker ps -a | grep -i x-ui
docker images | grep -i 3x-ui
ls /opt/3x-ui 2>/dev/null
        

Удаление Docker-установки

cd /opt/3x-ui
docker compose down --remove-orphans
docker rmi ghcr.io/mhsanaei/3x-ui:latest
rm -rf /opt/3x-ui
        

Удаление системной установки

systemctl stop x-ui
systemctl disable x-ui
rm -f /etc/systemd/system/x-ui.service
systemctl daemon-reload && systemctl reset-failed
rm -rf /usr/local/x-ui /etc/x-ui /usr/bin/x-ui /etc/default/x-ui

# Проверка, что следов не осталось (cron, logrotate, процессы)
crontab -l | grep -i xui; ls /etc/logrotate.d | grep -i xui; pgrep -a xray
        

Очистка в Nginx Proxy Manager

В админке NPM (Hosts → Proxy Hosts) удалите устаревшие хосты прежних попыток (например, cdn01.avk27.ru, 3x-ui.avk27.ru) вместе с их сертификатами (раздел SSL Certificates). Хост vpn.avk27.ru — исправьте согласно шагу 6.

3️⃣ Установка контейнера 3x-ui

Структура каталогов

mkdir -p /opt/3x-ui/data/db /opt/3x-ui/data/cert
cd /opt/3x-ui
        

Файл docker-compose.yml

Файл /opt/3x-ui/docker-compose.yml:

services:
  3x-ui:
    image: ghcr.io/mhsanaei/3x-ui:latest
    container_name: 3x-ui
    restart: unless-stopped
    volumes:
      - ./data/db:/etc/x-ui/        # база sqlite (настройки, inbound-ы, клиенты)
      - ./data/cert:/root/cert/     # сертификаты, если понадобятся
    environment:
      - XRAY_VMESS_AEAD_FORCED=false
    # Веб-панель — НЕ публикуем напрямую наружу, идёт через NPM (vpn.avk27.ru) по сети webproxy
    expose:
      - "2053"
    # Входящие подключения VPN-клиентов — публикуем напрямую (NPM их проксировать не умеет).
    # Диапазон подобран с запасом; в ufw уже открыт целиком.
    ports:
      - "20000-20100:20000-20100"
      - "20000-20100:20000-20100/udp"
    networks:
      - webproxy

networks:
  webproxy:
    external: true
        

Ключевые моменты:

Запуск

cd /opt/3x-ui
docker compose up -d
docker ps --filter name=3x-ui
docker logs 3x-ui --tail 20
        

4️⃣ Первичная настройка панели (CLI)

Образ стартует с логином/паролем admin/admin и корневым путём /. Сразу задайте собственные учётные данные и секретный путь (дополнительная защита: без пути панель отдаёт 404):

# Сгенерировать значения
openssl rand -hex 4    # для имени пользователя
openssl rand -base64 18 | tr -dc 'a-zA-Z0-9' | head -c 22   # пароль
openssl rand -hex 8    # секретный путь

# Применить (подставьте свои значения)
docker exec 3x-ui /app/x-ui setting -username <ЛОГИН> -password <ПАРОЛЬ> -webBasePath /<СЕКРЕТНЫЙ_ПУТЬ>/

docker restart 3x-ui

# Проверка настроек
docker exec 3x-ui /app/x-ui setting -show
# Ожидается: port: 2053, webBasePath: /xxxx/, hasDefaultCredential: false
        

Сохраните доступ в файл с правами 600 (на сервере он уже создан — /opt/3x-ui/PANEL_CREDENTIALS.txt):

cat > /opt/3x-ui/PANEL_CREDENTIALS.txt << 'EOF'
URL:      https://vpn.avk27.ru/<СЕКРЕТНЫЙ_ПУТЬ>/
Логин:    <ЛОГИН>
Пароль:   <ПАРОЛЬ>
EOF
chmod 600 /opt/3x-ui/PANEL_CREDENTIALS.txt
        

5️⃣ Настройка Nginx Proxy Manager (vpn.avk27.ru)

В админке NPM создайте (или исправьте) Proxy Host:

ПолеЗначение
Domain Namesvpn.avk27.ru
Schemehttp
Forward Hostname / IP3x-ui
Forward Port2053

Затем:

  1. Включите Websocket Support и Block Common Exploits;
  2. Вкладка SSL: запросите сертификат Let's Encrypt для vpn.avk27.ru (или выберите существующий);
  3. Включите Force SSL и HTTP/2 Support;
  4. Save.

⚠️ Если правка выполняется напрямую в базе NPM (/opt/infrastructure/npm/data/database.sqlite): после изменения не забудьте синхронизировать рендер-конфиг /opt/infrastructure/npm/data/nginx/proxy_host/<id>.conf (значения $server/$port, include force-ssl.conf) и перезагрузить nginx: docker exec nginx-proxy-manager nginx -t && docker exec nginx-proxy-manager nginx -s reload. Рестарт контейнера NPM сам конфиги не перегенерирует.

6️⃣ Firewall (ufw)

Диапазон для VPN-клиентов уже открыт (сделано ранее); панель и подписка наружу не публикуются:

ufw status | grep 20000
# 20000:20100/tcp  ALLOW IN  Anywhere
# 20000:20100/udp  ALLOW IN  Anywhere

# Если правил нет — добавить:
ufw allow 20000:20100/tcp
ufw allow 20000:20100/udp
        

7️⃣ Создание первого подключения (inbound)

  1. Откройте https://vpn.avk27.ru/<СЕКРЕТНЫЙ_ПУТЬ>/ и войдите;
  2. Inbounds → Add inbound;
  3. Рекомендуемая конфигурация (VLESS + Reality — маскировка под TLS-трафик):
    • Remark: произвольное имя подключения;
    • Protocol: VLESS, порт — из диапазона, например 20031;
    • Security: Reality; uTLS/Fingerprint: chrome; Dest (SNI): www.microsoft.com:443 (или другой крупный сайт); serverNames — тот же домен;
    • Пароль (private key) панель сгенерирует сама кнопкой Get New Cert;
    • Flow: xtls-rprx-vision;
  4. В разделе клиентов добавьте пользователя (email/имем — метка устройства);
  5. Save. Скопируйте ссылку подключения (QR/URL) в клиент: v2rayNG, Streisand, v2box и т.п.
💡 Подписка: сервис подписки внутри контейнера слушает порт 2096 наружу не публикуется. Для личного использования достаточно прямых ссылок из панели. Адрес для клиентов: vpn.avk27.ru:порт (диапазон 20000–20100).

8️⃣ Проверка

# 1. Панель отвечает по HTTPS (ожидается 200)
curl -s -o /dev/null -w "%{http_code}\n" https://vpn.avk27.ru/<СЕКРЕТНЫЙ_ПУТЬ>/

# 2. HTTP принудительно редиректит на HTTPS (ожидается 301)
curl -s -o /dev/null -w "%{http_code} -> %{redirect_url}\n" http://vpn.avk27.ru/<СЕКРЕТНЫЙ_ПУТЬ>/

# 3. Без секретного пути панель скрыта (ожидается 404)
curl -s -o /dev/null -w "%{http_code}\n" https://vpn.avk27.ru/

# 4. Внутри сети webproxy (из контейнера NPM)
docker exec nginx-proxy-manager curl -s -o /dev/null -w "%{http_code}\n" http://3x-ui:2053/<СЕКРЕТНЫЙ_ПУТЬ>/

# 5. Порт inbound-а доступен снаружи (с локальной машины)
nc -zv vpn.avk27.ru 20031
        

🔧 Обслуживание

# Обновление (панель + Xray одной командой)
cd /opt/3x-ui && docker compose pull && docker compose up -d

# Логи
docker logs -f 3x-ui

# Перезапуск
docker restart 3x-ui

# Бэкап: /opt/3x-ui/include в backup.sh (см. заметку ниже)
tar -czf /opt/backups/3x-ui-$(date +%F).tar.gz /opt/3x-ui/data /opt/3x-ui/docker-compose.yml
        

Скрипт /opt/scripts/backup.sh бэкапит NPM и /opt/projects; каталог /opt/3x-ui в него уже добавлен отдельным tar-архивом.

🆘 Решение проблем

СимптомПричина / решение
Панель по vpn.avk27.ru отдаёт 502Контейнер 3x-ui не запущен или не в сети webproxy: docker ps, docker network inspect webproxy; forward-хост в NPM должен быть 3x-ui:2053
404 на верном путиОпечатка в webBasePath — проверьте docker exec 3x-ui /app/x-ui setting -show
Клиент не подключается к inboundПорт должен быть из опубликованного диапазона 20000–20100 и открыт в ufw; Reality dest должен быть доступен с сервера
Забыли пароль панелиdocker exec 3x-ui /app/x-ui setting -username <новый> -password <новый> и docker restart 3x-ui
Сброс всех настроек панелиdocker exec 3x-ui /app/x-ui setting -reset (клиенты и inbound-ы сохранятся в БД)

🔐 Безопасность