tgvpn

Версия: 0.20.0

Telegram-бот на Go для управления VPN через панель Remnawave: проверка панели, создание пользователей, назначение сквадов. Данные хранятся в PostgreSQL.

Содержание

Требования

Компонент Минимум
Docker 24+
Docker Compose v2 (docker compose)
PostgreSQL 16+ (в compose включён)
Токен бота @BotFather
Сеть Исходящий HTTPS к api.telegram.org (порт 443)

Для запуска без Docker: Go 1.22+.


Быстрый старт (Docker Compose)

1. Клонирование

git clone <URL-вашего-репозитория>
cd tgvpn

2. Переменные окружения

cp .env.example .env

Отредактируйте .env:

BOT_TOKEN=ваш_токен_от_BotFather
BOT_DEBUG=false
TELEGRAM_ADMIN_ID=123456789
REMNAWAVE_PANEL_NAME=Панель 1
REMNAWAVE_PANEL_URL=https://panel.example.com
REMNAWAVE_API_TOKEN=токен_из_панели
REMNAWAVE_SUBSCRIPTION_URL=https://sub.example.com
DATABASE_URL=postgres://tgvpn:tgvpn@db:5432/tgvpn?sslmode=disable
DEFAULT_USER_DAYS=30

Важно: файл .env не попадает в git и не копируется в образ. Compose передаёт переменные в контейнер при старте.

3. Сборка и запуск

Поднимаются два сервиса: PostgreSQL (db) и бот (bot). Бот стартует только после готовности БД.

docker compose up -d --build

4. Проверка

# статус (db — healthy, bot — running)
docker compose ps

# логи бота (должно быть: «postgres ok», «бот @имя запущен»)
docker compose logs --tail=30 bot

# логи PostgreSQL
docker compose logs --tail=20 db

В Telegram: /start, от админа — /admin squads, /admin user.

5. Остановка

# остановить контейнеры (данные БД сохраняются в volume pgdata)
docker compose down

# удалить и данные БД (осторожно!)
docker compose down -v

PostgreSQL

Бот не работает без PostgreSQL: при старте проверяется DATABASE_URL, применяется миграция, далее идёт работа с БД.

Роль базы данных

Таблица Назначение
telegram_users Пользователи Telegram, зашедшие в бота (/start)
vpn_users Созданные в Remnawave аккаунты: UUID, логин, сквады, срок
admin_wizard Состояние мастера админа (создание пользователя, назначение сквадов)

Миграции лежат в internal/db/migrations/ и применяются автоматически при каждом запуске бота (CREATE TABLE IF NOT EXISTS).

Схема в Docker Compose

services:
  db:    # PostgreSQL 16, volume pgdata
  bot:   # ждёт healthy у db, затем стартует

Параметры по умолчанию (см. docker-compose.yml):

Параметр Значение
Хост (внутри compose) db
Порт 5432
База tgvpn
Пользователь tgvpn
Пароль tgvpn

Строка подключения для бота:

DATABASE_URL=postgres://tgvpn:tgvpn@db:5432/tgvpn?sslmode=disable

Формат URL (общий вид):

postgres://USER:PASSWORD@HOST:PORT/DATABASE?sslmode=disable

Подключение к БД вручную

Из каталога проекта:

# интерактивная консоль psql внутри контейнера
docker compose exec db psql -U tgvpn -d tgvpn

Полезные запросы:

-- все VPN-пользователи, созданные через бота
SELECT remnawave_username, remnawave_uuid, expire_at, created_at FROM vpn_users;

-- активные мастера админа
SELECT admin_telegram_id, step, updated_at FROM admin_wizard;

\q

Продакшен: смена пароля БД

  1. Задайте сильный пароль в docker-compose.yml (секция db.environment) или вынесите в .env:
environment:
  POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change_me_strong}
  1. Обновите DATABASE_URL в .env бота с тем же паролем.

  2. Пересоздайте стек:

docker compose down
docker compose up -d --build

Если меняете пароль у уже существующего volume pgdata, может понадобиться сброс volume или ALTER USER внутри старой БД.

Внешний PostgreSQL (без контейнера db)

Если БД на отдельном сервере или managed Postgres:

  1. Создайте базу и пользователя с правами CREATE, SELECT, INSERT, UPDATE, DELETE.
  2. В .env укажите реальный URL:
DATABASE_URL=postgres://user:password@postgres.example.com:5432/tgvpn?sslmode=require
  1. В docker-compose.yml закомментируйте или удалите сервис db и depends_on у bot.
  2. Убедитесь, что с хоста бота есть сетевой доступ к порту 5432.

Резервное копирование

# дамп в файл (дата в имени)
docker compose exec -T db pg_dump -U tgvpn tgvpn > backup_$(date +%Y%m%d).sql

# восстановление (на пустую или новую БД)
cat backup_20260101.sql | docker compose exec -T db psql -U tgvpn -d tgvpn

Рекомендуется настроить cron на VPS для ежедневных дампов.

Проверка после деплоя

docker compose ps
# tgvpn-db   running (healthy)
# tgvpn-bot  running

docker compose logs bot | grep -i postgres
# ожидается успешный старт без «ping postgres» / «apply migration» ошибок

Ошибки PostgreSQL

Симптом Решение
DATABASE_URL не задан Добавьте переменную в .env
connect postgres / ping postgres Проверьте, что db в состоянии healthy: docker compose ps
Бот стартует раньше БД В compose уже есть depends_on: condition: service_healthy — обновите compose
password authentication failed Совпадение пароля в POSTGRES_PASSWORD и в DATABASE_URL
Пустые таблицы после создания user Смотрите логи бота и ответ Remnawave API; запись в vpn_users идёт после успешного POST /api/users

Развёртывание на VPS (Linux)

Ниже — пошаговая установка на чистый сервер (Ubuntu 22.04/24.04, Debian 12). Аналогично на других дистрибутивах с Docker.

Шаг 1. Подключение к серверу

ssh user@your-server-ip

Шаг 2. Установка Docker

sudo apt-get update
sudo apt-get install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER

Выйдите из SSH и зайдите снова, чтобы группа docker применилась:

exit
ssh user@your-server-ip
docker --version
docker compose version

Шаг 3. Клонирование проекта

sudo mkdir -p /opt/tgvpn
sudo chown $USER:$USER /opt/tgvpn
cd /opt/tgvpn
git clone <URL-вашего-репозитория> .

Шаг 4. Настройка .env

cp .env.example .env
nano .env   # или vim / vi

Укажите реальный BOT_TOKEN, DATABASE_URL (в compose для VPS обычно оставляют postgres://tgvpn:...@db:5432/...), Remnawave и при необходимости UUID сквадов (DEFAULT_*).

Для продакшена смените пароль PostgreSQL — см. PostgreSQL → Продакшен.

Права на секреты:

chmod 600 .env

Шаг 5. Запуск в фоне

docker compose up -d --build

Проверка:

docker compose ps
docker compose logs --tail=50 bot
docker compose logs --tail=20 db

Шаг 6. Автозапуск после перезагрузки сервера

В docker-compose.yml уже указано restart: unless-stopped. После перезагрузки VPS контейнер поднимется сам, если Docker запущен:

sudo systemctl enable docker
sudo systemctl start docker

Шаг 7. Обновление

См. раздел Обновление бота ниже.


Обновление бота

Инструкция для уже работающей установки: подтянуть код из git, пересобрать контейнер и убедиться, что бот запустился.

Перед обновлением

  1. Убедитесь, что .env сохранён на сервере (он не в git).
  2. Посмотрите, не появились ли новые переменные в .env.example:
cd /opt/tgvpn   # или каталог, куда клонировали проект
git fetch origin
git diff HEAD origin/main -- .env.example

Если в .env.example есть новые строки — добавьте их в свой .env вручную.

Обновление на VPS (Docker)

cd /opt/tgvpn

# 1. Скачать изменения
git pull origin main

# 2. Пересобрать и перезапустить (простой даунтайм ~10–30 сек)
docker compose up -d --build

# 3. Проверить логи
docker compose ps
docker compose logs --tail=50 bot

В логах должны быть строки вида: бот @имя_бота запущен и администратор ID ….

Проверка в Telegram (от аккаунта админа):

  • /start — бот отвечает
  • /admin check — проверка панели Remnawave

Обновление на Windows (Docker Desktop)

cd tgvpn
git pull origin main
docker compose up -d --build
docker compose logs --tail=50 bot

Обновление без Docker (локально)

cd tgvpn
git pull origin main
go build -o bot .
# остановите старый процесс бота, затем:
./bot

Если изменили только .env

Пересборка не нужна — достаточно пересоздать контейнер:

docker compose up -d --force-recreate

Откат на предыдущую версию

cd /opt/tgvpn
git log --oneline -5          # найти нужный коммит
git checkout <хеш_коммита>    # например: git checkout f360d53
docker compose up -d --build

Вернуться на актуальную ветку:

git checkout main
git pull origin main
docker compose up -d --build

Очистка старых образов Docker (опционально)

После нескольких обновлений на диске копятся неиспользуемые слои:

docker image prune -f

Частые проблемы при обновлении

Симптом Решение
git pull конфликтует с локальными правками git stashgit pullgit stash pop или сбросить локальные изменения: git checkout -- .
Бот не стартует после pull docker compose logs bot — часто не хватает новой переменной в .env
Старый код в контейнере Обязательно --build: docker compose up -d --build
Нет доступа к git Проверьте SSH/HTTPS-доступ к вашему git-серверу

Развёртывание на Windows

Docker Desktop

  1. Установите Docker Desktop.
  2. В PowerShell:
git clone <URL-вашего-репозитория>
cd tgvpn
Copy-Item .env.example .env
# отредактируйте .env — вставьте BOT_TOKEN
docker compose up -d --build
docker compose logs -f bot

Локальная разработка (без Docker)

Нужен запущенный PostgreSQL 16+ (локально или только контейнер БД):

# вариант: только БД в Docker, бот на хосте
docker compose up -d db

В .env для локального бота укажите:

DATABASE_URL=postgres://tgvpn:tgvpn@localhost:5432/tgvpn?sslmode=disable

Проброс порта в docker-compose.yml (если ещё нет):

db:
  ports:
    - "5432:5432"

Запуск:

cp .env.example .env
go run .

или

go build -o bot .
./bot

Переменные окружения

Переменная Обязательно Описание
BOT_TOKEN да Токен от @BotFather
TELEGRAM_ADMIN_ID да Числовой Telegram user ID администратора (например, @userinfobot)
REMNAWAVE_PANEL_NAME нет Название панели в админ-меню (по умолчанию «Панель 1»)
REMNAWAVE_PANEL_URL да URL панели — сюда же идут запросы API (/api/...). Пример: https://panel.example.com (док)
REMNAWAVE_API_TOKEN да Токен из Remnawave Settings → API Tokens, заголовок Authorization: Bearer
CADDY_AUTH_API_TOKEN нет X-Api-Key, если включён Caddy with security (как в оф. .env subscription-page)
REMNAWAVE_SUBSCRIPTION_URL нет Опционально: домен Subscription Page (sub.*), отдельная проверка
DATABASE_URL да PostgreSQL, в compose: postgres://tgvpn:tgvpn@db:5432/tgvpn?sslmode=disable
DEFAULT_USER_DAYS нет Срок подписки по умолчанию (30)
DEFAULT_EXTERNAL_SQUAD_UUID нет External squad по умолчанию при быстром создании
DEFAULT_INTERNAL_SQUAD_UUIDS нет Internal squads через запятую
BOT_DEBUG нет true — подробные логи Telegram API (только для отладки)

Админ-меню в боте

Только пользователь с TELEGRAM_ADMIN_ID:

  • /admin — админ-меню (панель 1, Remnawave)
  • /admin check — полная проверка: веб панели, API (статистика, users, nodes), подписка (settings + API), страница подписки
  • /admin config — конфиг панели в боте
  • /admin user — мастер создания пользователя в Remnawave + назначение сквадов
  • /admin user <логин> [дней] — быстрое создание (сквады из DEFAULT_* в .env)
  • /admin squads — список internal/external squads
  • /admin assign <логин> — назначить сквады существующему пользователю
  • Кнопки: «Создать пользователя», «Сквады», «Проверить панель», «Конфиг»

Remnawave API (по официальной документации)

Как в Bundled Subscription Page:

REMNAWAVE_PANEL_URL=https://panel.example.com
REMNAWAVE_API_TOKEN=API_TOKEN_FROM_REMNAWAVE
CADDY_AUTH_API_TOKEN=
  • Отдельного REMNAWAVE_API_URL нет — API всегда на том же хосте, что и панель: {REMNAWAVE_PANEL_URL}/api/...
  • Авторизация: Authorization: Bearer {REMNAWAVE_API_TOKEN}
  • Внутри Docker-сети Remnawave: REMNAWAVE_PANEL_URL=http://remnawave:3000
  • Домен sub.* — это Subscription Page, не панель; для API используйте panel.*

Пример проверки с сервера:

curl -s -o /dev/null -w "%{http_code}" \
  -H "Authorization: Bearer $REMNAWAVE_API_TOKEN" \
  "$REMNAWAVE_PANEL_URL/api/system/stats/recap"

Полезные команды Docker

# пересобрать образ и перезапустить
docker compose up -d --build

# логи в реальном времени
docker compose logs -f bot

# последние 100 строк логов
docker compose logs --tail=100 bot

# зайти в контейнер бота
docker compose exec bot sh

# консоль PostgreSQL
docker compose exec db psql -U tgvpn -d tgvpn

# дамп базы
docker compose exec -T db pg_dump -U tgvpn tgvpn > backup.sql

# удалить контейнеры (данные БД в volume сохранятся)
docker compose down

# удалить контейнер и неиспользуемые образы проекта
docker compose down --rmi local

Сеть и безопасность

  • Бот использует long polling: входящие запросы на ваш сервер не нужны, порты открывать не требуется.
  • Нужен только исходящий доступ к https://api.telegram.org.
  • Не коммитьте .env в git. Не публикуйте BOT_TOKEN и пароль БД.
  • PostgreSQL доступен только внутри docker-сети (порт наружу не проброшен по умолчанию).
  • Контейнер бота запускается от непривилегированного пользователя bot (UID 10001).

Если позже добавите webhook, понадобится reverse proxy (nginx/Caddy), TLS и открытый порт 443 — это описывается отдельно при появлении функции.


Устранение неполадок

BOT_TOKEN не задан / TELEGRAM_ADMIN_ID не задан

  • Проверьте, что файл .env лежит рядом с docker-compose.yml.
  • В .env нет пробелов вокруг =: BOT_TOKEN=123:ABC, не BOT_TOKEN = ....
  • TELEGRAM_ADMIN_ID — только цифры, без @username.
  • После правки: docker compose up -d --force-recreate.

Authentication failed / 401 Unauthorized

  • Неверный или отозванный токен. Создайте новый в @BotFather → /token → обновите .envdocker compose up -d --force-recreate.

Бот не отвечает в Telegram

docker compose ps          # State должен быть running
docker compose logs bot    # ошибки сети, токена
  • Убедитесь, что на сервере нет блокировки Telegram (firewall, провайдер).
  • Проверьте: curl -I https://api.telegram.org с хоста.

API возвращает 502, веб-панель — 200

Частая причина: в REMNAWAVE_PANEL_URL указан домен страницы подписки (sub.example.com), а не админ-панели (panel.example.com).

  1. Укажите URL панели (не sub): REMNAWAVE_PANEL_URL=https://panel.example.com
  2. Токен API: REMNAWAVE_API_TOKEN=... (Settings → API Tokens)
  3. Страницу подписки — опционально: REMNAWAVE_SUBSCRIPTION_URL=https://sub.example.com
  4. Проверьте на сервере: docker compose ps (Remnawave Panel запущен), логи reverse proxy

Контейнер постоянно перезапускается

docker compose logs --tail=200 bot

Чаще всего — пустой BOT_TOKEN или ошибка при старте.

DATABASE_URL не задан / ошибки PostgreSQL

См. раздел PostgreSQL → Ошибки.

Нет доступа к docker без sudo

sudo usermod -aG docker $USER
# перелогиньтесь

Структура проекта

tgvpn/
├── main.go
├── internal/
│   ├── bot/             # Telegram, админ-меню, создание пользователей
│   ├── config/          # переменные окружения
│   ├── db/              # PostgreSQL: подключение, миграции, репозитории
│   │   └── migrations/  # SQL-миграции (001_init.sql)
│   └── remnawave/       # API панели (users, squads)
├── Dockerfile           # multi-stage сборка
├── docker-compose.yml   # bot + PostgreSQL (volume pgdata)
├── .env.example         # шаблон переменных
├── .dockerignore
├── go.mod / go.sum
├── CHANGELOG.md
└── README.md

Репозиторий

Укажите URL вашего приватного git-репозитория при клонировании.

S
Description
No description provided
Readme 189 KiB
v0.20.0 Latest
2026-05-20 22:02:12 +00:00
Languages
Go 84.8%
Shell 14.6%
Dockerfile 0.6%