Сервисные шаблоны и пути на серверах

Эталонные файлы лежат в репозитории в /root/bot/service/. Установщик копирует systemd-юниты как есть; nginx для бота генерирует из шаблона с вашим доменом и секретным путём.

💡
После правки юнита: systemctl daemon-reload && systemctl restart ИМЯ. После правки nginx: nginx -t && systemctl reload nginx.
Systemd — сервер бота
Шаблон в репозиторииПуть на сервереКак появляется
service/vpn-bot.service /etc/systemd/system/vpn-bot.service install_bot.sh копирует
service/vpn-webadmin.service /etc/systemd/system/vpn-webadmin.service install_bot.sh копирует
service/xuiweb.service /etc/systemd/system/xuiweb.service install_bot.sh копирует
нет в service/ — текст в Личный кабинет /etc/systemd/system/website.service создаёте вручную на сервере бота
нет в service/ — пишет SUBPAGE install.sh /etc/systemd/system/subpage.service на сервере бота или отдельном SUBPAGE
Nginx
Шаблон в репозиторииПуть на сервереГде
service/xuiweb.conf (пример) /etc/nginx/conf.d/xuiweb.conf Сервер бота. install_bot.sh пишет готовый конфиг (домен + секретный путь). Шаблон — образец location’ов.
service/remnawave.conf (пример) /etc/nginx/conf.d/remnawave.conf Сервер панели Remnawave (или тот же VPS, если панель «под ботом»). Обычно ставит install_nginx.sh.
Зависимости pip
ФайлКуда ставитсяСервис
service/requirements.txt /root/bot/venv и /root/bot/web_admin/venv vpn-bot, vpn-webadmin
service/xuiweb.txt /root/bot/xuiweb/venv xuiweb
service/website.txt /root/bot/website/venv website — см. кабинет
Порты (localhost)
СервисСлушаетКто проксирует
vpn-bot127.0.0.1:8081 (вебхуки оплат и Remnawave)nginx xuiweb.conf
vpn-webadmin127.0.0.1:8181nginx /СЕКРЕТНЫЙ_ПУТЬ/
xuiweb127.0.0.1:8282nginx /api/
subpage127.0.0.1:3004 (типично)nginx / на домене бота или свой домен
Remnawave127.0.0.1:3000nginx remnawave.conf
website0.0.0.0:3012nginx на проксирующем сервере кабинета

Тексты юнитов и nginx из service/ — ниже. Домен в примерах условный.

vpn-bot.service → /etc/systemd/system/vpn-bot.service
ini
[Unit]
Description=VPN Telegram Bot
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/root/bot
ExecStart=/root/bot/venv/bin/python3 /root/bot/main.py
Restart=always

[Install]
WantedBy=multi-user.target
vpn-webadmin.service → /etc/systemd/system/vpn-webadmin.service
ini
[Unit]
Description=VPN Web Admin
After=network.target

[Service]
Type=simple
User=root
WorkingDirectory=/root/bot
Environment="PATH=/root/bot/web_admin/venv/bin:/usr/local/bin:/usr/bin:/bin"
Environment="PYTHONPATH=/root/bot"
ExecStart=/root/bot/web_admin/venv/bin/hypercorn web_admin.run:app -w 1 --bind 127.0.0.1:8181 --keep-alive 30
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal
LimitNOFILE=65536
MemoryMax=1.5G

[Install]
WantedBy=multi-user.target
xuiweb.service → /etc/systemd/system/xuiweb.service
ini
[Unit]
Description=XUIWEBFASTAPI
After=network.target

[Service]
User=root
Group=www-data
WorkingDirectory=/root/bot/xuiweb
Environment="PATH=/root/bot/xuiweb/venv/bin"

ExecStart=/root/bot/xuiweb/venv/bin/gunicorn --workers 2 --worker-class uvicorn.workers.UvicornWorker --bind 127.0.0.1:8282 run:app
Restart=always
RestartSec=5s

[Install]
WantedBy=multi-user.target
xuiweb.conf пример → /etc/nginx/conf.d/xuiweb.conf
nginx
server {
    listen 80;
    listen [::]:80;
    server_name bot.domain.ru;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name bot.domain.ru;
    ssl_certificate     /etc/letsencrypt/live/bot.domain.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/bot.domain.ru/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;
    ssl_session_cache   shared:SSL:10m;
    ssl_session_timeout 1d;

    client_max_body_size 50M;

    location /admin123/ {
        proxy_pass http://127.0.0.1:8181/admin123/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Connection "";
        proxy_buffering off;
        client_max_body_size 50M;
        proxy_connect_timeout 300s;
        proxy_send_timeout 300s;
        proxy_read_timeout 300s;
        send_timeout 300s;
    }

    location /api/ {
        proxy_pass http://127.0.0.1:8282/api/;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location / {
        proxy_pass http://127.0.0.1:3004;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /yoomoney/ {
        proxy_pass http://127.0.0.1:8081/yoomoney/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 30s;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
    }

    location /platega/ {
        proxy_pass http://127.0.0.1:8081/platega/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 30s;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
    }

    location /yookassa/ {
        proxy_pass http://127.0.0.1:8081/yookassa/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 30s;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
    }

    location /cryptobot/ {
        proxy_pass http://127.0.0.1:8081/cryptobot/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 30s;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
    }

    location /wata/ {
        proxy_pass http://127.0.0.1:8081/wata/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 90s;
        proxy_connect_timeout 30s;
        proxy_send_timeout 90s;
    }

    location /remnawave/webhook {
        client_max_body_size 64M;
        proxy_pass http://127.0.0.1:8081/remnawave/webhook;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 30s;
        proxy_connect_timeout 30s;
        proxy_send_timeout 30s;
    }
}

/admin123/ на сервере заменяется на ваш admin_secret_path. Домен — на реальный.

remnawave.conf пример → /etc/nginx/conf.d/remnawave.conf
nginx
server {
    listen 80;
    listen [::]:80;
    server_name panel.domain.ru;
    return 301 https://$host$request_uri;
}

server {
    server_name panel.domain.ru;
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ssl_certificate /etc/letsencrypt/live/panel.domain.ru/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/panel.domain.ru/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/panel.domain.ru/fullchain.pem;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;

    ssl_session_timeout 1d;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 1.1.1.1 1.0.0.1 valid=60s;
    resolver_timeout 2s;
    client_max_body_size 50M;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }

    gzip on;
    gzip_vary on;
    gzip_proxied any;
    gzip_comp_level 6;
    gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
}

Сервисные команды

Отладка systemd на сервере. Действия: restart, start, enable, stop, disable, status.

💡
В общих командах есть website и subpage. Если юнит не установлен, systemctl напишет ошибку по нему — остальные сервисы всё равно выполнятся. Журнал: поток в реальном времени (-f), выход — Ctrl+C.

Общие команды для всех сервисов

bash · перезапуск всех
systemctl restart vpn-bot.service vpn-webadmin.service xuiweb.service website.service subpage.service
bash · запуск всех
systemctl start vpn-bot.service vpn-webadmin.service xuiweb.service website.service subpage.service
bash · статус всех
systemctl status vpn-bot.service vpn-webadmin.service xuiweb.service website.service subpage.service
bash · автозапуск всех
systemctl enable vpn-bot.service vpn-webadmin.service xuiweb.service website.service subpage.service
bash · остановка всех
systemctl stop vpn-bot.service vpn-webadmin.service xuiweb.service website.service subpage.service
bash · выключить автозапуск всех
systemctl disable vpn-bot.service vpn-webadmin.service xuiweb.service website.service subpage.service

journalctl — журнал в реальном времени

Показывает последние строки и дальше пишет новые, как только они появляются. Выход: Ctrl+C.

bash · общий журнал всех сервисов
journalctl -u vpn-bot.service -u vpn-webadmin.service -u xuiweb.service -u website.service -u subpage.service -n 100 -f
bash · vpn-bot
journalctl -u vpn-bot.service -n 100 -f
bash · vpn-webadmin
journalctl -u vpn-webadmin.service -n 100 -f
bash · xuiweb
journalctl -u xuiweb.service -n 100 -f
bash · website
journalctl -u website.service -n 100 -f
bash · subpage
journalctl -u subpage.service -n 100 -f

Команды по каждому сервису

vpn-bot.service
restart
systemctl restart vpn-bot.service
start
systemctl start vpn-bot.service
stop
systemctl stop vpn-bot.service
status
systemctl status vpn-bot.service
enable
systemctl enable vpn-bot.service
disable
systemctl disable vpn-bot.service
vpn-webadmin.service
restart
systemctl restart vpn-webadmin.service
start
systemctl start vpn-webadmin.service
stop
systemctl stop vpn-webadmin.service
status
systemctl status vpn-webadmin.service
enable
systemctl enable vpn-webadmin.service
disable
systemctl disable vpn-webadmin.service
xuiweb.service
restart
systemctl restart xuiweb.service
start
systemctl start xuiweb.service
stop
systemctl stop xuiweb.service
status
systemctl status xuiweb.service
enable
systemctl enable xuiweb.service
disable
systemctl disable xuiweb.service
website.service
restart
systemctl restart website.service
start
systemctl start website.service
stop
systemctl stop website.service
status
systemctl status website.service
enable
systemctl enable website.service
disable
systemctl disable website.service
subpage.service
restart
systemctl restart subpage.service
start
systemctl start subpage.service
stop
systemctl stop subpage.service
status
systemctl status subpage.service
enable
systemctl enable subpage.service
disable
systemctl disable subpage.service

Смена секретного пути в админку

💡
Секретный путь — это URL-префикс для входа в веб-админку. Например: https://ваш-домен.ru/admin123/. Важно менять его строго в правильном порядке, иначе потеряете доступ.
⚠️
Строго соблюдайте порядок шагов. Если сначала изменить Nginx и перезапустить — не попадёте в веб-админку для сохранения нового пути. Всегда начинайте с веб-админки.
  • 1 Откройте веб-админку → Настройки → Основные и найдите параметр admin_secret_path. Задайте новое значение, например: MySecretPanel
    Используйте только латинские буквы и цифры, без слэшей и пробелов.
  • 2 Нажмите Сохранить. После этого старый адрес веб-админки ещё работает — сессия активна.
  • 3 Подключитесь к серверу по SSH и откройте конфиг Nginx:
    bash
    nano /etc/nginx/conf.d/xuiweb.conf
  • 4 Найдите строки со старым путём и замените на новый (два места — в location и в proxy_pass):
    nginx — было
    location /admin123/ {
        proxy_pass http://127.0.0.1:8181/admin123/;
        ...
    }
    nginx — стало
    location /MySecretPanel/ {
        proxy_pass http://127.0.0.1:8181/MySecretPanel/;
        ...
    }
    Сохраните файл: Ctrl+O → Enter → Ctrl+X
  • 5 Проверьте синтаксис Nginx и перезапустите:
    bash
    nginx -t && systemctl reload nginx
  • 6 Перезапустите сервисы веб-админки:
    bash
    systemctl restart vpn-webadmin
  • 7 Откройте веб-админку по новому адресу:
    Новый URL
    https://ваш-домен.ru/MySecretPanel/
✅
Готово. Старый путь больше не работает — веб-админка доступна только по новому адресу.

Обновление SSL-сертификата бота

💡
Nginx бота читает сертификаты из /root/cert/fullchain.pem и /root/cert/privkey.pem (см. /etc/nginx/conf.d/xuiweb.conf). Let's Encrypt хранит оригиналы в /etc/letsencrypt/live/ваш-домен.ru/ — после продления их нужно скопировать в /root/cert/, иначе nginx продолжит отдавать старый сертификат.
⚠️
Перед запуском убедитесь, что DNS A-запись домена указывает на IP этого сервера. Скрипт updomain.sh на время выпуска сертификата останавливает nginx (certbot standalone на порту 80).

Способ 1 — скрипт updomain.sh (рекомендуется)

Подходит и для смены домена, и для продления сертификата на текущем домене. При продлении введите тот же домен, что уже в nginx.

bash
cd /root/bot
bash updomain.sh

Скрипт выполняет:

  • 1Открывает порт 80 в UFW (если UFW активен)
  • 2Останавливает nginx
  • 3Запрашивает сертификат: certbot certonly --standalone -d ДОМЕН --force-renewal
  • 4Копирует fullchain.pem и privkey.pem в /root/cert/
  • 5Обновляет server_name в /etc/nginx/conf.d/xuiweb.conf (если введён новый домен)
  • 6Перезапускает nginx, xuiweb, vpn-webadmin

Способ 2 — вручную (копирование в /root/cert/)

Если certbot уже продлил сертификат (cron/timer) или вы получили его отдельной командой — достаточно скопировать файлы и перезагрузить nginx. Замените ваш-домен.ru на ваш домен бота.

bash
cp /etc/letsencrypt/live/ваш-домен.ru/fullchain.pem /root/cert/fullchain.pem
cp /etc/letsencrypt/live/ваш-домен.ru/privkey.pem /root/cert/privkey.pem
nginx -t && systemctl reload nginx

Если сертификат ещё не продлён — сначала получите его (nginx нужно остановить, порт 80 должен быть свободен):

bash
systemctl stop nginx
certbot certonly --standalone -d ваш-домен.ru --force-renewal
cp /etc/letsencrypt/live/ваш-домен.ru/fullchain.pem /root/cert/fullchain.pem
cp /etc/letsencrypt/live/ваш-домен.ru/privkey.pem /root/cert/privkey.pem
nginx -t && systemctl start nginx
systemctl restart xuiweb vpn-webadmin
✅
Проверка: откройте сайт бота в браузере → замок SSL → срок действия сертификата должен обновиться. Иногда браузер показывает старую дату (кэш/закреплённое соединение) — проверьте в другом браузере или в режиме инкognito. Или в терминале: openssl s_client -connect ваш-домен.ru:443 -servername ваш-домен.ru — смотрите notAfter (это надёжнее, чем UI браузера).

Обновление SSL — SUBPAGE

💡
Только для внешнего сервера SUBPAGE со своим доменом. Если SUBPAGE крутится под ботом — отдельный сертификат не нужен, используется SSL бота (блок выше). Nginx SUBPAGE читает файлы напрямую из /etc/letsencrypt/live/ДОМЕН/ — копировать в /root/cert/ не нужно.
⚠️
A-запись домена SUBPAGE должна смотреть на IP этого сервера. Standalone на время выпуска останавливает nginx (порт 80 должен быть свободен).

Способ 1 — standalone

Как при первой установке SUBPAGE: certbot сам поднимает временный веб-сервер на порту 80. Замените sub.example.com на домен SUBPAGE.

bash
systemctl stop nginx
certbot certonly --standalone -d sub.example.com --force-renewal
nginx -t && systemctl start nginx

Через CLI SUBPAGE тот же standalone: sudo subpage → Управление Nginx → обновление SSL.

Способ 2 — как обычно (плагин nginx)

Nginx не останавливаем. Certbot проходит проверку Let's Encrypt через уже работающий nginx. Нужен пакет python3-certbot-nginx и рабочий server_name на этот домен.

bash
certbot certonly --nginx -d sub.example.com --force-renewal
nginx -t && systemctl reload nginx

Обновление SSL — WEBSITE (личный кабинет)

💡
Команды выполняются на проксирующем сервере, где nginx терминирует HTTPS кабинета (см. Личный кабинет). Сертификат лежит в /etc/letsencrypt/live/cabinet.ваш-домен.ru/ — nginx читает его оттуда напрямую.
⚠️
A-запись домена кабинета должна смотреть на IP проксирующего сервера. Standalone на время выпуска останавливает nginx.

Способ 1 — standalone

Если плагин nginx не срабатывает или порт 80 занят самим nginx — остановите его, выпустите сертификат, запустите обратно. Замените cabinet.ваш-домен.ru на домен кабинета.

bash
systemctl stop nginx
certbot certonly --standalone -d cabinet.ваш-домен.ru --force-renewal
nginx -t && systemctl start nginx

Способ 2 — как обычно (плагин nginx)

Как при установке кабинета: nginx не останавливаем. Нужен python3-certbot-nginx.

bash
certbot certonly --nginx -d cabinet.ваш-домен.ru --force-renewal
nginx -t && systemctl reload nginx
✅
Проверка срока: openssl s_client -connect cabinet.ваш-домен.ru:443 -servername cabinet.ваш-домен.ru — смотрите notAfter. Список сертификатов на сервере: certbot certificates.