23 KiB
tgvpn
Версия: 0.20.0
Telegram-бот на Go для управления VPN через панель Remnawave: проверка панели, создание пользователей, назначение сквадов. Данные хранятся в PostgreSQL.
Содержание
- Требования
- Быстрый старт
- PostgreSQL
- Развёртывание на VPS
- Обновление бота
- Переменные окружения
- Админ-меню
- Устранение неполадок
Требования
| Компонент | Минимум |
|---|---|
| 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
Продакшен: смена пароля БД
- Задайте сильный пароль в
docker-compose.yml(секцияdb.environment) или вынесите в.env:
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change_me_strong}
-
Обновите
DATABASE_URLв.envбота с тем же паролем. -
Пересоздайте стек:
docker compose down
docker compose up -d --build
Если меняете пароль у уже существующего volume
pgdata, может понадобиться сброс volume илиALTER USERвнутри старой БД.
Внешний PostgreSQL (без контейнера db)
Если БД на отдельном сервере или managed Postgres:
- Создайте базу и пользователя с правами
CREATE,SELECT,INSERT,UPDATE,DELETE. - В
.envукажите реальный URL:
DATABASE_URL=postgres://user:password@postgres.example.com:5432/tgvpn?sslmode=require
- В
docker-compose.ymlзакомментируйте или удалите сервисdbиdepends_onуbot. - Убедитесь, что с хоста бота есть сетевой доступ к порту
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, пересобрать контейнер и убедиться, что бот запустился.
Перед обновлением
- Убедитесь, что
.envсохранён на сервере (он не в git). - Посмотрите, не появились ли новые переменные в
.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 stash → git pull → git stash pop или сбросить локальные изменения: git checkout -- . |
| Бот не стартует после pull | docker compose logs bot — часто не хватает новой переменной в .env |
| Старый код в контейнере | Обязательно --build: docker compose up -d --build |
| Нет доступа к git | Проверьте SSH/HTTPS-доступ к вашему git-серверу |
Развёртывание на Windows
Docker Desktop
- Установите Docker Desktop.
- В 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→ обновите.env→docker 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).
- Укажите URL панели (не sub):
REMNAWAVE_PANEL_URL=https://panel.example.com - Токен API:
REMNAWAVE_API_TOKEN=...(Settings → API Tokens) - Страницу подписки — опционально:
REMNAWAVE_SUBSCRIPTION_URL=https://sub.example.com - Проверьте на сервере:
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-репозитория при клонировании.