Внутренняя документация

Gandhara VPN Ops

Живая шпаргалка по нашим панелям, контейнерам, базам, ботам, Remnawave API, бэкапам и типовым эксплуатационным действиям.

Карта проекта

Что здесь живёт

Gandhara VPN

Remnawave backend, PostgreSQL, Valkey, subscription page и Remnanode. Основная панель: panelka.404.mn.

Бухгалтерия

Express и SQLite. Тянет клиентов из Remnawave API, считает оплату, напоминания, рефералов и маржу.

Support panel

Операторская панель, PostgreSQL, Telegram bot и Discord bot. Тикеты обновляются онлайн.

Skiff

Self-hosted SSH vault с командным доступом через браузер и общей командной базой хостов.

DNS и Caddy

Домены

ДоменНазначениеUpstream
panelka.404.mnГлавная Remnawave панельremnawave:3000
subscription.gandhara.404.mnСтраница подпискиremnawave-subscription-page:3010
gandhara.404.mnБухгалтерияgandhara-site:1328
support.gandhara.404.mnSupport panelweb + api route
skiff.gandhara.404.mnSkiff SSH vaultskiff:8080
docs.gandhara.404.mnЭта документацияCaddy file_server
DNS запись для docs: subdomain docs.gandhara, type A, destination 13.140.10.142, TTL можно оставить пустым или стандартным.

Docker

Контейнеры и состояние

Remnawave

remnawave, remnawave-db, remnawave-redis, remnawave-subscription-page, remnanode.

Support

support-panel-api, support-panel-web, support-panel-postgres-1, support-panel-telegram-bot-1, support-panel-discord-bot-1.

Прочее

gandhara-site, skiff, caddy, amnezia-awg2.

sudo docker ps
sudo docker volume ls
sudo docker network ls

Runbook

Рестарты и логи

Основная панель

cd /opt/remnawave
sudo docker compose up -d remnawave
sudo docker compose ps remnawave
sudo docker logs --tail 80 remnawave

Subscription page

docker restart remnawave-subscription-page
sudo docker logs --tail 80 remnawave-subscription-page

Support panel

cd /opt/support-panel
sudo docker compose -f docker-compose.prod.yml up -d --build
sudo docker compose -f docker-compose.prod.yml ps

Только боты

cd /opt/support-panel
sudo docker compose -f docker-compose.prod.yml restart telegram-bot discord-bot
sudo docker logs --tail 80 support-panel-telegram-bot-1
sudo docker logs --tail 80 support-panel-discord-bot-1

VPN core

Remnawave

  • Compose: /opt/remnawave/docker-compose.yml.
  • База: PostgreSQL volume remnawave-db-data.
  • Valkey socket volume: valkey-socket.
  • Кастомный фронт: /opt/remnawave/frontend-custom смонтирован read-only в /opt/app/frontend.
  • В Utilities добавлены ссылки на Учёт, SSH, Support и Docs.
  • Иконки кастомных пунктов патчатся скриптом /tmp/patch-remna-custom-icons.py.
cd /opt/remnawave
sudo docker compose up -d remnawave
curl -fsSkI https://panelka.404.mn

Учёт

Бухгалтерия

Хранение

Проект: /opt/gandhara-site. Контейнер: gandhara-site. SQLite хранится в volume gandhara-site_gandhara-site-data как /data/gandhara.db.

Интеграция

Синхронизация пользователей идёт через Remnawave API. Ручное обновление вызывает /api/users?sync=force.

Ключевые env поля

ADMIN_EMAIL=operator
ADMIN_PASSWORD=strong-password
AUTH_SECRET=at-least-32-random-characters
REMNAWAVE_API_BASE=http://remnawave:3000
REMNAWAVE_API_TOKEN=secret-token
REMNAWAVE_PROXY_HOST=panelka.404.mn
REMNAWAVE_SYNC_INTERVAL_MS=60000
  • Логин работает по имени оператора, не только по email.
  • Пользователи автоматически добавляются из Remnawave и удаляются из бухгалтерии, если удалены в Remnawave.
  • Истечение подписки не удаляет клиента, а меняет расчётный статус.
  • Флаг Не учитывать в оплате подписки считает клиента оплаченным, но не включает его в маржу и денежный отчёт.
  • Панель Маржа показывает сумму, которую реально имеем после исключений и реферальных скидок.

Ticket Hub

Support panel

Статусы

OPEN Открытые, ANSWERED Отвеченные, CLOSED Закрытые.

Операторы

Назначение внутри открытого тикета: Amnezis, xAikq, Natsunagi, Citation. На закрытых тикетах исполнитель не отображается.

Live

Список, сообщения, статусы и исполнитель подтягиваются онлайн, чтобы несколько операторов видели одно состояние.

API маршруты

GET    /health
POST   /auth/login
GET    /tickets
GET    /tickets/:id
PATCH  /tickets/:id/assignee
POST   /tickets/:id/reply
PATCH  /tickets/:id/status
GET    /bot/tickets/active
POST   /bot/tickets
POST   /bot/tickets/by-channel/:channelId/messages
GET    /bot/users/:source/:externalUserId/preferences
PUT    /bot/users/:source/:externalUserId/preferences

Env

JWT_SECRET=secret
BOT_API_SECRET=secret
ADMIN_EMAIL=login
ADMIN_PASSWORD=strong-password
TELEGRAM_BOT_TOKEN=token
DISCORD_BOT_TOKEN=token
DISCORD_CLIENT_ID=id
DISCORD_TICKET_CATEGORY_ID=optional
DISCORD_SUPPORT_ROLE_ID=optional
CORS_ORIGIN=https://support.gandhara.404.mn

Интеграции

Telegram и Discord

Telegram

  • /start и /menu показывают меню.
  • /ticket открывает поддержку без повторного приветственного экрана.
  • Если активный тикет уже есть, обычные сообщения добавляются в него.
  • Язык пользователя хранится через bot preferences API.

Discord

  • /setup-tickets публикует панель создания тикетов.
  • /ticket открывает форму тикета.
  • Бот создаёт приватный канал и пишет входящие сообщения в API.
  • После закрытия тикета канал удаляется с задержкой.

SSH vault

Skiff

Skiff хранит SSH-хосты и открывает терминал в браузере. Проект расположен в /opt/skiff, контейнер skiff, данные в /opt/skiff/data.

cd /opt/skiff
sudo docker compose -f docker-compose.prod.yml up -d --build
sudo docker logs --tail 80 skiff
Для серверов лучше использовать отдельного пользователя и отдельный SSH key под Skiff. Полный root выдаём только если реально нужна админская консоль, и лучше через понятный runbook.

Данные

Бэкапы

Общий механизм живёт в /opt/gandhara-backups, запускается cron каждый день в 03:20 UTC, хранит данные в /home/amnezis/backups/databases, retention по умолчанию 30 дней.

BACKUP_ROOT=/home/amnezis/backups/databases RETENTION_DAYS=30 bash /opt/gandhara-backups/scripts/backup-databases.sh
crontab -l
tail -n 80 /home/amnezis/backups/databases/backup.log
ЧтоГдеФормат
Remnawave PostgreSQLremnawave-postgrespg_dumpall sql.gz
Support PostgreSQLsupport-panel-postgrespg_dumpall sql.gz
Remnawave Valkeyremnawave-valkeyrdb.gz
Skiff dataskiff-datatar.gz
Бухгалтерия SQLite volumegandhara-site-datatar.gz

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

Что уже настроено

  • Caddy добавляет HSTS, nosniff, frame guard, Referrer-Policy и Permissions-Policy.
  • Support API отключает x-powered-by, использует JWT, bcrypt и rate limit для логина.
  • Bot API закрыт заголовком x-bot-api-secret.
  • Бухгалтерия использует httpOnly cookie, AUTH_SECRET и rate limit для логина.
  • Секреты должны жить только в .env, не в git и не в документации.

Проверки

Быстрые диагностики

Health

curl -fsSkI https://panelka.404.mn
curl -fsSk https://gandhara.404.mn/healthz
curl -fsSk https://support.gandhara.404.mn/api/health
curl -fsSk https://skiff.gandhara.404.mn/api/health
curl -fsSkI https://docs.gandhara.404.mn

Логи

sudo docker logs --tail 100 remnawave
sudo docker logs --tail 100 gandhara-site
sudo docker logs --tail 100 support-panel-api
sudo docker logs --tail 100 support-panel-telegram-bot-1
sudo docker logs --tail 100 support-panel-discord-bot-1
sudo docker logs --tail 100 caddy