Files
tgvpn cbb2133991 Add /config trial VPN generation for users (1 day default)
Users get Remnawave subscription via /config or inline button; TRIAL_USER_DAYS and panel lookup by Telegram ID.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 01:29:55 +03:00

728 lines
26 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# tgvpn
**Версия:** [0.20.0](CHANGELOG.md)
Telegram-бот на Go для управления VPN через панель [Remnawave](https://docs.rw/): проверка панели, создание пользователей, назначение сквадов. Данные хранятся в **PostgreSQL**.
## Содержание
- [Требования](#требования)
- [Установщик (рекомендуется)](#установщик-на-сервере)
- [Быстрый старт](#быстрый-старт-docker-compose)
- [PostgreSQL](#postgresql)
- [Развёртывание на VPS](#развёртывание-на-vps-linux)
- [Обновление бота](#обновление-бота)
- [Переменные окружения](#переменные-окружения)
- [Админ-меню](#админ-меню-в-боте)
- [Устранение неполадок](#устранение-неполадок)
## Требования
| Компонент | Минимум |
|-----------|---------|
| Docker | 24+ |
| Docker Compose | v2 (`docker compose`) |
| PostgreSQL | 16+ (в compose включён) |
| Токен бота | [@BotFather](https://t.me/BotFather) |
| Сеть | Исходящий HTTPS к `api.telegram.org` (порт 443) |
Для запуска **без Docker**: Go 1.22+.
---
## Установщик на сервере
Интерактивный скрипт запросит все параметры, создаст `.env` и запустит Docker.
### Требования на сервере
- Linux (Ubuntu 22.04/24.04, Debian 12)
- `curl`, `git` (для клонирования)
- Права `sudo` (для установки Docker при необходимости)
### Установка одной командой
Если репозиторий уже на сервере:
```bash
cd tgvpn
chmod +x install.sh
./install.sh
```
Или скачайте скрипт и укажите каталог `/opt/tgvpn`:
```bash
sudo mkdir -p /opt/tgvpn
cd /opt/tgvpn
git clone <URL-вашего-репозитория> .
chmod +x install.sh
./install.sh
```
### Что спрашивает установщик
| Блок | Параметры |
|------|-----------|
| Telegram | `BOT_TOKEN`, `TELEGRAM_ADMIN_ID`, `BOT_DEBUG` |
| Remnawave | URL панели, API token, Caddy token, subscription URL |
| PostgreSQL | пользователь, база, пароль (можно сгенерировать случайный) |
| VPN | срок по умолчанию, UUID сквадов (опционально) |
| Система | каталог установки, URL git (если не из текущей папки) |
После завершения: `docker compose up -d --build`, проверка `docker compose ps`.
### Переменные окружения для PostgreSQL в compose
В `.env` должны совпадать `POSTGRES_PASSWORD` и пароль в `DATABASE_URL`:
```env
POSTGRES_USER=tgvpn
POSTGRES_PASSWORD=ваш_сильный_пароль
POSTGRES_DB=tgvpn
DATABASE_URL=postgres://tgvpn:ваш_сильный_пароль@db:5432/tgvpn?sslmode=disable
```
Установщик заполняет это автоматически.
---
## Быстрый старт (Docker Compose)
### 1. Клонирование
```bash
git clone <URL-вашего-репозитория>
cd tgvpn
```
### 2. Переменные окружения
```bash
cp .env.example .env
```
Отредактируйте `.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`). Бот стартует только после готовности БД.
```bash
docker compose up -d --build
```
### 4. Проверка
```bash
# статус (db — healthy, bot — running)
docker compose ps
# логи бота (должно быть: «postgres ok», «бот @имя запущен»)
docker compose logs --tail=30 bot
# логи PostgreSQL
docker compose logs --tail=20 db
```
В Telegram: `/start` → кнопка «Получить конфиг» или `/config` (trial на `TRIAL_USER_DAYS`, по умолчанию 1 день). От админа — `/admin squads`, `/admin user`.
### 5. Остановка
```bash
# остановить контейнеры (данные БД сохраняются в 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
```yaml
services:
db: # PostgreSQL 16, volume pgdata
bot: # ждёт healthy у db, затем стартует
```
Параметры по умолчанию (см. `docker-compose.yml`):
| Параметр | Значение |
|----------|----------|
| Хост (внутри compose) | `db` |
| Порт | `5432` |
| База | `tgvpn` |
| Пользователь | `tgvpn` |
| Пароль | `tgvpn` |
Строка подключения для бота:
```env
DATABASE_URL=postgres://tgvpn:tgvpn@db:5432/tgvpn?sslmode=disable
```
Формат URL (общий вид):
```
postgres://USER:PASSWORD@HOST:PORT/DATABASE?sslmode=disable
```
### Подключение к БД вручную
Из каталога проекта:
```bash
# интерактивная консоль psql внутри контейнера
docker compose exec db psql -U tgvpn -d tgvpn
```
Полезные запросы:
```sql
-- все 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`:
```yaml
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-change_me_strong}
```
2. Обновите `DATABASE_URL` в `.env` бота с тем же паролем.
3. Пересоздайте стек:
```bash
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:
```env
DATABASE_URL=postgres://user:password@postgres.example.com:5432/tgvpn?sslmode=require
```
3. В `docker-compose.yml` закомментируйте или удалите сервис `db` и `depends_on` у `bot`.
4. Убедитесь, что с хоста бота есть сетевой доступ к порту `5432`.
### Резервное копирование
```bash
# дамп в файл (дата в имени)
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 для ежедневных дампов.
### Проверка после деплоя
```bash
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. Подключение к серверу
```bash
ssh user@your-server-ip
```
### Шаг 2. Установка Docker
```bash
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` применилась:
```bash
exit
ssh user@your-server-ip
docker --version
docker compose version
```
### Шаг 3. Клонирование проекта
```bash
sudo mkdir -p /opt/tgvpn
sudo chown $USER:$USER /opt/tgvpn
cd /opt/tgvpn
git clone <URL-вашего-репозитория> .
```
### Шаг 4. Настройка `.env`
```bash
cp .env.example .env
nano .env # или vim / vi
```
Укажите реальный `BOT_TOKEN`, `DATABASE_URL` (в compose для VPS обычно оставляют `postgres://tgvpn:...@db:5432/...`), Remnawave и при необходимости UUID сквадов (`DEFAULT_*`).
Для продакшена смените пароль PostgreSQL — см. [PostgreSQL → Продакшен](#продакшен-смена-пароля-бд).
Права на секреты:
```bash
chmod 600 .env
```
### Шаг 5. Запуск в фоне
```bash
docker compose up -d --build
```
Проверка:
```bash
docker compose ps
docker compose logs --tail=50 bot
docker compose logs --tail=20 db
```
### Шаг 6. Автозапуск после перезагрузки сервера
В `docker-compose.yml` уже указано `restart: unless-stopped`. После перезагрузки VPS контейнер поднимется сам, если Docker запущен:
```bash
sudo systemctl enable docker
sudo systemctl start docker
```
### Шаг 7. Обновление
См. раздел [Обновление бота](#обновление-бота) ниже.
---
## Обновление бота
Инструкция для уже работающей установки: подтянуть код из git, пересобрать контейнер и убедиться, что бот запустился.
### Перед обновлением
1. Убедитесь, что `.env` сохранён на сервере (он не в git).
2. Посмотрите, не появились ли новые переменные в `.env.example`:
```bash
cd /opt/tgvpn # или каталог, куда клонировали проект
git fetch origin
git diff HEAD origin/main -- .env.example
```
Если в `.env.example` есть новые строки — добавьте их в свой `.env` вручную.
### Обновление на VPS (Docker)
```bash
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)
```powershell
cd tgvpn
git pull origin main
docker compose up -d --build
docker compose logs --tail=50 bot
```
### Обновление без Docker (локально)
```bash
cd tgvpn
git pull origin main
go build -o bot .
# остановите старый процесс бота, затем:
./bot
```
### Если изменили только `.env`
Пересборка не нужна — достаточно пересоздать контейнер:
```bash
docker compose up -d --force-recreate
```
### Откат на предыдущую версию
```bash
cd /opt/tgvpn
git log --oneline -5 # найти нужный коммит
git checkout <хеш_коммита> # например: git checkout f360d53
docker compose up -d --build
```
Вернуться на актуальную ветку:
```bash
git checkout main
git pull origin main
docker compose up -d --build
```
### Очистка старых образов Docker (опционально)
После нескольких обновлений на диске копятся неиспользуемые слои:
```bash
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
1. Установите [Docker Desktop](https://www.docker.com/products/docker-desktop/).
2. В PowerShell:
```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+ (локально или только контейнер БД):
```bash
# вариант: только БД в Docker, бот на хосте
docker compose up -d db
```
В `.env` для локального бота укажите:
```env
DATABASE_URL=postgres://tgvpn:tgvpn@localhost:5432/tgvpn?sslmode=disable
```
Проброс порта в `docker-compose.yml` (если ещё нет):
```yaml
db:
ports:
- "5432:5432"
```
Запуск:
```bash
cp .env.example .env
go run .
```
или
```bash
go build -o bot .
./bot
```
---
## Переменные окружения
| Переменная | Обязательно | Описание |
|--------------|-------------|----------|
| `BOT_TOKEN` | да | Токен от @BotFather |
| `TELEGRAM_ADMIN_ID` | да | Числовой Telegram user ID администратора (например, [@userinfobot](https://t.me/userinfobot)) |
| `REMNAWAVE_PANEL_NAME` | нет | Название панели в админ-меню (по умолчанию «Панель 1») |
| `REMNAWAVE_PANEL_URL` | да | URL панели — сюда же идут запросы API (`/api/...`). Пример: `https://panel.example.com` ([док](https://docs.rw/docs/install/subscription-page/bundled)) |
| `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` |
| `TRIAL_USER_DAYS` | нет | Срок trial-конфига для `/config` (по умолчанию 1) |
| `DEFAULT_USER_DAYS` | нет | Срок при создании админом `/admin user` (по умолчанию 1) |
| `DEFAULT_EXTERNAL_SQUAD_UUID` | нет | External squad по умолчанию при быстром создании |
| `DEFAULT_INTERNAL_SQUAD_UUIDS` | нет | Internal squads через запятую |
| `BOT_DEBUG` | нет | `true` — подробные логи Telegram API (только для отладки) |
### Команды для пользователей
- `/start` — приветствие и кнопка получения конфига
- `/config` — создать пользователя в Remnawave на `TRIAL_USER_DAYS` (если активная подписка уже есть — вернёт существующую ссылку)
Нужны `DEFAULT_EXTERNAL_SQUAD_UUID` и `DEFAULT_INTERNAL_SQUAD_UUIDS` — те же сквады, что для быстрого `/admin user`.
### Админ-меню в боте
Только пользователь с `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](https://docs.rw/docs/install/subscription-page/bundled):
```env
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.*`
Пример проверки с сервера:
```bash
curl -s -o /dev/null -w "%{http_code}" \
-H "Authorization: Bearer $REMNAWAVE_API_TOKEN" \
"$REMNAWAVE_PANEL_URL/api/system/stats/recap"
```
---
## Полезные команды Docker
```bash
# пересобрать образ и перезапустить
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
```bash
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
### Контейнер постоянно перезапускается
```bash
docker compose logs --tail=200 bot
```
Чаще всего — пустой `BOT_TOKEN` или ошибка при старте.
### `DATABASE_URL не задан` / ошибки PostgreSQL
См. раздел [PostgreSQL → Ошибки](#ошибки-postgresql).
### Нет доступа к `docker` без sudo
```bash
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 сборка
├── install.sh # интерактивный установщик на сервер
├── docker-compose.yml # bot + PostgreSQL (volume pgdata)
├── .env.example # шаблон переменных
├── .dockerignore
├── go.mod / go.sum
├── CHANGELOG.md
└── README.md
```
---
## Репозиторий
Укажите URL вашего приватного git-репозитория при клонировании.