Expand README with PostgreSQL documentation and updated setup guide
This commit is contained in:
@@ -2,7 +2,18 @@
|
|||||||
|
|
||||||
**Версия:** [0.20.0](CHANGELOG.md)
|
**Версия:** [0.20.0](CHANGELOG.md)
|
||||||
|
|
||||||
Telegram-бот на Go (базовое приветствие; далее — VPN-функции).
|
Telegram-бот на Go для управления VPN через панель [Remnawave](https://docs.rw/): проверка панели, создание пользователей, назначение сквадов. Данные хранятся в **PostgreSQL**.
|
||||||
|
|
||||||
|
## Содержание
|
||||||
|
|
||||||
|
- [Требования](#требования)
|
||||||
|
- [Быстрый старт](#быстрый-старт-docker-compose)
|
||||||
|
- [PostgreSQL](#postgresql)
|
||||||
|
- [Развёртывание на VPS](#развёртывание-на-vps-linux)
|
||||||
|
- [Обновление бота](#обновление-бота)
|
||||||
|
- [Переменные окружения](#переменные-окружения)
|
||||||
|
- [Админ-меню](#админ-меню-в-боте)
|
||||||
|
- [Устранение неполадок](#устранение-неполадок)
|
||||||
|
|
||||||
## Требования
|
## Требования
|
||||||
|
|
||||||
@@ -43,12 +54,16 @@ REMNAWAVE_PANEL_NAME=Панель 1
|
|||||||
REMNAWAVE_PANEL_URL=https://panel.example.com
|
REMNAWAVE_PANEL_URL=https://panel.example.com
|
||||||
REMNAWAVE_API_TOKEN=токен_из_панели
|
REMNAWAVE_API_TOKEN=токен_из_панели
|
||||||
REMNAWAVE_SUBSCRIPTION_URL=https://sub.example.com
|
REMNAWAVE_SUBSCRIPTION_URL=https://sub.example.com
|
||||||
|
DATABASE_URL=postgres://tgvpn:tgvpn@db:5432/tgvpn?sslmode=disable
|
||||||
|
DEFAULT_USER_DAYS=30
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Важно:** файл `.env` не попадает в git и не копируется в образ. Compose передаёт переменные в контейнер при старте.
|
> **Важно:** файл `.env` не попадает в git и не копируется в образ. Compose передаёт переменные в контейнер при старте.
|
||||||
|
|
||||||
### 3. Сборка и запуск
|
### 3. Сборка и запуск
|
||||||
|
|
||||||
|
Поднимаются два сервиса: **PostgreSQL** (`db`) и **бот** (`bot`). Бот стартует только после готовности БД.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
@@ -56,23 +71,164 @@ docker compose up -d --build
|
|||||||
### 4. Проверка
|
### 4. Проверка
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# логи (должно быть: «бот @имя_бота запущен»)
|
# статус (db — healthy, bot — running)
|
||||||
docker compose logs -f bot
|
|
||||||
|
|
||||||
# статус контейнера
|
|
||||||
docker compose ps
|
docker compose ps
|
||||||
|
|
||||||
|
# логи бота (должно быть: «postgres ok», «бот @имя запущен»)
|
||||||
|
docker compose logs --tail=30 bot
|
||||||
|
|
||||||
|
# логи PostgreSQL
|
||||||
|
docker compose logs --tail=20 db
|
||||||
```
|
```
|
||||||
|
|
||||||
В Telegram откройте бота и отправьте `/start`.
|
В Telegram: `/start`, от админа — `/admin squads`, `/admin user`.
|
||||||
|
|
||||||
### 5. Остановка
|
### 5. Остановка
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# остановить контейнеры (данные БД сохраняются в volume pgdata)
|
||||||
docker compose down
|
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)
|
## Развёртывание на VPS (Linux)
|
||||||
|
|
||||||
Ниже — пошаговая установка на чистый сервер (Ubuntu 22.04/24.04, Debian 12). Аналогично на других дистрибутивах с Docker.
|
Ниже — пошаговая установка на чистый сервер (Ubuntu 22.04/24.04, Debian 12). Аналогично на других дистрибутивах с Docker.
|
||||||
@@ -126,7 +282,9 @@ cp .env.example .env
|
|||||||
nano .env # или vim / vi
|
nano .env # или vim / vi
|
||||||
```
|
```
|
||||||
|
|
||||||
Укажите реальный `BOT_TOKEN`. Для продакшена оставьте `BOT_DEBUG=false`.
|
Укажите реальный `BOT_TOKEN`, `DATABASE_URL` (в compose для VPS обычно оставляют `postgres://tgvpn:...@db:5432/...`), Remnawave и при необходимости UUID сквадов (`DEFAULT_*`).
|
||||||
|
|
||||||
|
Для продакшена смените пароль PostgreSQL — см. [PostgreSQL → Продакшен](#продакшен-смена-пароля-бд).
|
||||||
|
|
||||||
Права на секреты:
|
Права на секреты:
|
||||||
|
|
||||||
@@ -145,6 +303,7 @@ docker compose up -d --build
|
|||||||
```bash
|
```bash
|
||||||
docker compose ps
|
docker compose ps
|
||||||
docker compose logs --tail=50 bot
|
docker compose logs --tail=50 bot
|
||||||
|
docker compose logs --tail=20 db
|
||||||
```
|
```
|
||||||
|
|
||||||
### Шаг 6. Автозапуск после перезагрузки сервера
|
### Шаг 6. Автозапуск после перезагрузки сервера
|
||||||
@@ -285,9 +444,31 @@ docker compose logs -f bot
|
|||||||
|
|
||||||
## Локальная разработка (без Docker)
|
## Локальная разработка (без 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
|
```bash
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
# укажите BOT_TOKEN в .env
|
|
||||||
go run .
|
go run .
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -369,10 +550,16 @@ docker compose logs -f bot
|
|||||||
# последние 100 строк логов
|
# последние 100 строк логов
|
||||||
docker compose logs --tail=100 bot
|
docker compose logs --tail=100 bot
|
||||||
|
|
||||||
# зайти в контейнер (обычно не нужно)
|
# зайти в контейнер бота
|
||||||
docker compose exec bot sh
|
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
|
||||||
|
|
||||||
# удалить контейнер и неиспользуемые образы проекта
|
# удалить контейнер и неиспользуемые образы проекта
|
||||||
@@ -385,8 +572,9 @@ docker compose down --rmi local
|
|||||||
|
|
||||||
- Бот использует **long polling**: входящие запросы на ваш сервер **не нужны**, порты открывать не требуется.
|
- Бот использует **long polling**: входящие запросы на ваш сервер **не нужны**, порты открывать не требуется.
|
||||||
- Нужен только **исходящий** доступ к `https://api.telegram.org`.
|
- Нужен только **исходящий** доступ к `https://api.telegram.org`.
|
||||||
- Не коммитьте `.env` в git. Не публикуйте `BOT_TOKEN`.
|
- Не коммитьте `.env` в git. Не публикуйте `BOT_TOKEN` и пароль БД.
|
||||||
- Контейнер запускается от непривилегированного пользователя `bot` (UID 10001).
|
- PostgreSQL доступен **только внутри docker-сети** (порт наружу не проброшен по умолчанию).
|
||||||
|
- Контейнер бота запускается от непривилегированного пользователя `bot` (UID 10001).
|
||||||
|
|
||||||
Если позже добавите **webhook**, понадобится reverse proxy (nginx/Caddy), TLS и открытый порт 443 — это описывается отдельно при появлении функции.
|
Если позже добавите **webhook**, понадобится reverse proxy (nginx/Caddy), TLS и открытый порт 443 — это описывается отдельно при появлении функции.
|
||||||
|
|
||||||
@@ -432,6 +620,10 @@ docker compose logs --tail=200 bot
|
|||||||
|
|
||||||
Чаще всего — пустой `BOT_TOKEN` или ошибка при старте.
|
Чаще всего — пустой `BOT_TOKEN` или ошибка при старте.
|
||||||
|
|
||||||
|
### `DATABASE_URL не задан` / ошибки PostgreSQL
|
||||||
|
|
||||||
|
См. раздел [PostgreSQL → Ошибки](#ошибки-postgresql).
|
||||||
|
|
||||||
### Нет доступа к `docker` без sudo
|
### Нет доступа к `docker` без sudo
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -449,10 +641,11 @@ tgvpn/
|
|||||||
├── internal/
|
├── internal/
|
||||||
│ ├── bot/ # Telegram, админ-меню, создание пользователей
|
│ ├── bot/ # Telegram, админ-меню, создание пользователей
|
||||||
│ ├── config/ # переменные окружения
|
│ ├── config/ # переменные окружения
|
||||||
│ ├── db/ # PostgreSQL, миграции, мастер админа
|
│ ├── db/ # PostgreSQL: подключение, миграции, репозитории
|
||||||
|
│ │ └── migrations/ # SQL-миграции (001_init.sql)
|
||||||
│ └── remnawave/ # API панели (users, squads)
|
│ └── remnawave/ # API панели (users, squads)
|
||||||
├── Dockerfile # multi-stage сборка
|
├── Dockerfile # multi-stage сборка
|
||||||
├── docker-compose.yml # оркестрация
|
├── docker-compose.yml # bot + PostgreSQL (volume pgdata)
|
||||||
├── .env.example # шаблон переменных
|
├── .env.example # шаблон переменных
|
||||||
├── .dockerignore
|
├── .dockerignore
|
||||||
├── go.mod / go.sum
|
├── go.mod / go.sum
|
||||||
|
|||||||
Reference in New Issue
Block a user