docs: rewrite README with correct Caddy proxy config and step-by-step installation guide

This commit is contained in:
Fringg
2026-02-16 01:50:50 +03:00
parent 150a1b2dba
commit bbe0fe0f04

506
README.md
View File

@@ -1,263 +1,153 @@
# Bedolaga Cabinet - Web Interface
Современный веб-интерфейс личного кабинета для VPN бота на базе [Remnawave Bedolaga Telegram Bot V3.0.0+](https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot).
Веб-интерфейс личного кабинета для VPN бота на базе [Remnawave Bedolaga Telegram Bot V3.0.0+](https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot).
## Возможности
- 🔐 Авторизация через Telegram
- 💳 Пополнение баланса (YooKassa, CryptoBot, Stars и др.)
- 📊 Управление подписками и ключами
- 🎫 Система тикетов поддержки
- 🌐 Мультиязычность (EN/RU)
- 📱 Адаптивный дизайн
- 🎨 Настраиваемый брендинг
- Админпанель для управлени ботом
- Автоматическая передача subpage конфигов приложений из Remnawave
- ⚡ Fast - React + Vite + TypeScript
React + Vite + TypeScript | Авторизация через Telegram | Мультиязычность (EN/RU) | Адаптивный дизайн
## Требования
- Node.js 18+ (для разработки)
- Docker и Docker Compose (для production)
- Docker и Docker Compose
- Запущенный backend бота с включенным Cabinet API
- Обратный прокси (Caddy / Nginx / Traefik)
## Быстрый старт
## Архитектура
### Вариант A: Готовый Docker образ
```bash
docker pull ghcr.io/bedolaga-dev/bedolaga-cabinet:latest
или
docker pull bedolaga/bedolaga-cabinet:latest
```
Браузер → Caddy/Nginx → /api/* → remnawave_bot:8080 (backend API)
→ /* → /srv/cabinet (статика frontend)
```
Затем настройте Caddy/Nginx для проксирования (см. раздел "Настройка прокси для production").
Frontend — это статические файлы (HTML, JS, CSS). Обратный прокси выполняет две задачи:
1. Раздает статику frontend
2. Проксирует `/api/*` запросы на backend бота (с удалением префикса `/api`)
### Вариант B: Сборка из исходников
## Установка
#### 1. Клонирование репозитория
### Шаг 1. Настройка backend бота
```bash
git clone https://github.com/BEDOLAGA-DEV/bedolaga-cabinet.git
cd bedolaga-cabinet
```
#### 2. Настройка окружения
**⚠️ ОБЯЗАТЕЛЬНО:** Скопируйте `.env.example` в `.env` перед запуском!
```bash
cp .env.example .env
```
Docker Compose не запустится без `.env` файла.
**Основные переменные:**
```env
# API URL - путь к backend API
# Используйте /api если прокси на том же домене
# Или полный URL если backend на другом сервере
VITE_API_URL=/api
# Telegram Bot Username (без @)
VITE_TELEGRAM_BOT_USERNAME=your_bot_username
# Брендинг (опционально)
VITE_APP_NAME=My VPN Cabinet
VITE_APP_LOGO=V
# Порт для Docker контейнера
CABINET_PORT=3020
```
#### 3. Запуск в Docker
```bash
docker compose up -d --build
```
Приложение будет доступно на `http://localhost:3020`
## Настройка backend
В `.env` файле вашего бота добавьте:
В `.env` файле бота добавьте:
```env
# Включить Cabinet API
CABINET_ENABLED=true
# JWT секрет для авторизации (сгенерируйте случайную строку)
# JWT секрет (сгенерируйте случайную строку: openssl rand -hex 32)
CABINET_JWT_SECRET=your_random_secret_key_here
# Разрешенные origins для CORS
CABINET_ALLOWED_ORIGINS=http://localhost:3020,https://cabinet.yourdomain.com
# Разрешенные origins для CORS (домен, на котором будет кабинет)
CABINET_ALLOWED_ORIGINS=https://cabinet.example.com
```
После изменений перезапустите бота.
Перезапустите бота после изменений.
## Настройка прокси для production
### Шаг 2. Получение frontend файлов
Frontend - это статические файлы (HTML, JS, CSS). Для работы нужно:
1. Раздавать статику через веб-сервер
2. Проксировать `/api/*` запросы на backend бота
> **💡 Важно:** Docker контейнер из этого репозитория содержит nginx, который слушает на **внутреннем порту 80**.
> Это НЕ хост-порт! Выберите один из вариантов ниже в зависимости от вашей инфраструктуры.
### Вариант 1: Caddy раздает статику напрямую
**✅ Рекомендуется** - без лишних слоев прокси, максимальная производительность.
Соберите frontend и примонтируйте в Caddy:
#### Вариант A: Готовый Docker образ (рекомендуется)
```bash
# Соберите образ или скопируйте dist из контейнера
docker compose build
docker create --name temp_cabinet cabinet_frontend
docker cp temp_cabinet:/usr/share/nginx/html ./cabinet-dist
docker rm temp_cabinet
docker pull ghcr.io/bedolaga-dev/bedolaga-cabinet:latest
```
Caddyfile:
Извлеките собранные файлы из образа:
```bash
# Создать временный контейнер и скопировать статику
docker create --name tmp_cabinet ghcr.io/bedolaga-dev/bedolaga-cabinet:latest
docker cp tmp_cabinet:/usr/share/nginx/html ./cabinet-dist
docker rm tmp_cabinet
```
#### Вариант B: Сборка из исходников
```bash
git clone https://github.com/BEDOLAGA-DEV/bedolaga-cabinet.git
cd bedolaga-cabinet
cp .env.example .env
```
Отредактируйте `.env`:
```env
VITE_API_URL=/api
VITE_TELEGRAM_BOT_USERNAME=your_bot_username
VITE_APP_NAME=My VPN
VITE_APP_LOGO=V
```
Соберите и извлеките:
```bash
docker compose build
docker create --name tmp_cabinet cabinet_frontend
docker cp tmp_cabinet:/usr/share/nginx/html ./cabinet-dist
docker rm tmp_cabinet
```
### Шаг 3. Размещение файлов на сервере
Скопируйте содержимое `cabinet-dist` в директорию, которую будет раздавать ваш прокси:
```bash
# Создайте директорию на сервере
sudo mkdir -p /srv/cabinet
# Скопируйте файлы (с локальной машины или напрямую на сервере)
sudo cp -r ./cabinet-dist/* /srv/cabinet/
```
### Шаг 4. Настройка обратного прокси
#### Caddy (рекомендуется)
Caddy автоматически получает и обновляет SSL сертификаты.
```caddyfile
cabinet.yourdomain.com {
root * /srv/cabinet
encode gzip
https://cabinet.example.com {
encode gzip zstd
# API запросы на backend
# API запросы backend бота (удаляет /api префикс)
handle /api/* {
uri strip_prefix /api
reverse_proxy remnawave_bot:8080
}
@websockets {
header_regexp Connection *Upgrade*
header Upgrade websocket
}
# WebSocket соединения
handle /cabinet/ws {
uri strip_prefix /api
reverse_proxy remnawave_bot:8080 {
transport http {
read_timeout 0
write_timeout 0
}
}
}
# Статические файлы
# Frontend статика
handle {
root * /srv/cabinet
try_files {path} /index.html
file_server
}
}
```
# Кэширование статических ассетов (JS, CSS, шрифты, изображения)
@static path *.js *.css *.woff *.woff2 *.ttf *.ico *.png *.jpg *.jpeg *.svg *.webp *.gif
header @static Cache-Control "public, max-age=31536000, immutable"
docker-compose.yml для Caddy:
```yaml
services:
caddy:
image: caddy:2-alpine
volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro
- ./cabinet-dist:/srv/cabinet:ro
- caddy_data:/data
ports:
- '80:80'
- '443:443'
networks:
- bot_network
```
### Вариант 2: Проксирование на frontend контейнер
Если хотите использовать готовый Docker контейнер с nginx внутри.
**⚠️ Важно:**
- Порт `80` в примерах - это **внутренний порт контейнера** (nginx внутри), не хост-порт!
- Контейнеры должны быть в одной Docker сети для связи друг с другом
- Имена контейнеров используются как DNS внутри Docker сети
#### A. Если у вас УЖЕ запущен Caddy/Nginx в Docker:
**Шаг 1:** Узнайте имя Docker сети вашего Caddy/Nginx:
```bash
# Посмотреть сети
docker network ls
# Или узнать сеть конкретного контейнера
docker inspect <имя_caddy_контейнера> | grep NetworkMode
```
**Шаг 2:** Создайте docker-compose.yml для frontend:
```yaml
services:
cabinet-frontend:
image: ghcr.io/bedolaga-dev/bedolaga-cabinet:latest
container_name: cabinet_frontend
restart: unless-stopped
# НЕ открываем порты на хосте! Только внутри Docker сети
networks:
- bot_network
networks:
bot_network:
external: true # Используем существующую сеть
name: remnawave-bedolaga-telegram-bot_bot_network # Пример для bedolaga bot
```
**Важно:** Замените имя сети на вашу:
- Если у вас bot + caddy: используйте сеть бота (обычно `<название_проекта>_bot_network`)
- Если отдельный Caddy: узнайте через `docker network ls`
- Если используете Traefik: обычно `traefik` или `web`
**Шаг 3:** Запустите frontend:
```bash
docker compose up -d
```
**Шаг 4:** Добавьте в конфигурацию Caddy/Nginx:
Caddy проксирует на контейнер:
```caddyfile
cabinet.yourdomain.com {
# API на backend
handle /api/* {
uri strip_prefix /api
reverse_proxy remnawave_bot:8080
}
# Frontend контейнер (nginx внутри на порту 80)
handle {
reverse_proxy cabinet_frontend:80
# HTML без кэша (для обновлений SPA)
@html path *.html /
header @html Cache-Control "no-cache, must-revalidate"
}
}
```
Nginx (добавьте в существующий конфиг):
> **Примечание:** `remnawave_bot:8080` — имя контейнера бота в Docker сети.
> Если Caddy запущен на хосте, а не в Docker, используйте `localhost:8080` или IP сервера.
#### Nginx
```nginx
server {
listen 443 ssl http2;
server_name cabinet.yourdomain.com;
server_name cabinet.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
# API на backend
root /srv/cabinet;
index index.html;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml image/svg+xml;
# API запросы → backend бота
location /api/ {
rewrite ^/api/(.*) /$1 break;
proxy_pass http://remnawave_bot:8080;
@@ -268,28 +158,38 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}
# Frontend контейнер (nginx внутри на порту 80)
# Кэширование статических ассетов
location ~* \.(?:js|css|woff2?|ttf|ico|png|jpe?g|svg|webp|gif)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# SPA fallback
location / {
proxy_pass http://cabinet_frontend:80;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
try_files $uri /index.html;
add_header Cache-Control "no-cache, must-revalidate";
}
}
```
**Шаг 5:** Перезагрузите Caddy/Nginx:
### Шаг 5. Запуск и проверка
```bash
# Для Caddy
# Перезагрузите Caddy
docker exec <caddy_container> caddy reload --config /etc/caddy/Caddyfile
# Для Nginx
# Или Nginx
docker exec <nginx_container> nginx -s reload
```
#### B. Если Caddy/Nginx ещё НЕ запущен:
Откройте `https://cabinet.example.com` в браузере.
docker-compose.yml:
## Альтернативная установка: Docker контейнер с nginx внутри
Если вы не хотите раздавать статику напрямую, можно проксировать запросы на Docker контейнер cabinet.
### docker-compose.yml
```yaml
services:
@@ -297,106 +197,136 @@ services:
image: ghcr.io/bedolaga-dev/bedolaga-cabinet:latest
container_name: cabinet_frontend
restart: unless-stopped
# Можно открыть порт для прямого доступа (для тестирования)
# ports:
# - "3020:80"
# Порты НЕ пробрасываем — доступ только через Docker сеть
networks:
- web
- bot_network
networks:
web:
driver: bridge
bot_network:
external: true
name: remnawave-bedolaga-telegram-bot_bot_network # Сеть вашего бота
```
Затем настройте Caddy/Nginx в той же сети `web`.
### Caddyfile
```caddyfile
https://cabinet.example.com {
encode gzip zstd
# API запросы → backend бота
handle /api/* {
uri strip_prefix /api
reverse_proxy remnawave_bot:8080
}
# Frontend → nginx контейнер (порт 80 внутри Docker сети)
handle {
reverse_proxy cabinet_frontend:80
}
}
```
> В этом варианте кэшированием статики занимается nginx внутри контейнера.
## Переменные окружения
### Build-time (используются при сборке)
### Build-time (вшиваются в JS при сборке)
| Переменная | Описание | По умолчанию |
| ---------------------------- | ---------------------------------- | ------------ |
| `VITE_API_URL` | Путь к API (`/api` или полный URL) | `/api` |
| `VITE_TELEGRAM_BOT_USERNAME` | Username Telegram бота (без @) | - |
| `VITE_APP_NAME` | Название приложения | `Cabinet` |
| `VITE_APP_LOGO` | Логотип (короткий текст) | `V` |
| Переменная | Описание | По умолчанию |
|---|---|---|
| `VITE_API_URL` | Путь к API (`/api` или полный URL) | `/api` |
| `VITE_TELEGRAM_BOT_USERNAME` | Username Telegram бота (без @) | — |
| `VITE_APP_NAME` | Название в шапке и вкладке браузера | `Cabinet` |
| `VITE_APP_LOGO` | Текст логотипа (1-2 символа) | `V` |
### Runtime (только для Docker)
### Runtime (только для Docker контейнера)
| Переменная | Описание | По умолчанию |
| -------------- | --------------- | ------------ |
| `CABINET_PORT` | Порт контейнера | `3020` |
| Переменная | Описание | По умолчанию |
|---|---|---|
| `CABINET_PORT` | Порт контейнера на хосте | `3020` |
### Backend бота (.env бота)
| Переменная | Описание | По умолчанию |
|---|---|---|
| `CABINET_ENABLED` | Включить Cabinet API | `false` |
| `CABINET_JWT_SECRET` | Секретный ключ для JWT | `BOT_TOKEN` |
| `CABINET_ALLOWED_ORIGINS` | CORS origins (через запятую) | — |
| `CABINET_ACCESS_TOKEN_EXPIRE_MINUTES` | Время жизни access token | `15` |
| `CABINET_REFRESH_TOKEN_EXPIRE_DAYS` | Время жизни refresh token | `7` |
## Устранение проблем
### CORS ошибка в консоли браузера
Домен кабинета не добавлен в `CABINET_ALLOWED_ORIGINS` в `.env` бота. Добавьте и перезапустите бота.
### API возвращает HTML вместо JSON
Прокси настроен неправильно — запросы `/api/*` попадают на frontend вместо backend. Проверьте порядок блоков `handle` в Caddyfile (API должен быть первым).
### 502 Bad Gateway
1. Backend бота не запущен — проверьте `docker ps`
2. Контейнеры в разных Docker сетях — проверьте и подключите:
```bash
# Проверить сети контейнера
docker inspect <container> --format='{{json .NetworkSettings.Networks}}' | python3 -m json.tool
# Подключить к нужной сети
docker network connect <network_name> <container_name>
```
3. Неправильное имя сервиса в прокси — проверьте через:
```bash
docker exec <caddy_container> wget -qO- http://remnawave_bot:8080/health
```
### Telegram авторизация не работает
1. `VITE_TELEGRAM_BOT_USERNAME` должен быть без `@`
2. Домен кабинета добавлен в BotFather → Bot Settings → Domain
### Белый экран / SPA не работает
Прокси не настроен на fallback к `index.html`. Убедитесь что `try_files {path} /index.html` (Caddy) или `try_files $uri /index.html` (Nginx) присутствует в конфигурации.
## Разработка
```bash
git clone https://github.com/BEDOLAGA-DEV/bedolaga-cabinet.git
cd bedolaga-cabinet
npm install
cp .env.example .env
# Отредактируйте .env
npm run dev
```
Dev-сервер запустится на `http://localhost:5173` с автоматическим проксированием `/api` на `localhost:8080`.
## Структура проекта
```
bedolaga-cabinet/
├── src/
│ ├── api/ # API клиенты
│ ├── components/ # React компоненты
│ ├── contexts/ # React контексты
│ ├── api/ # API клиенты (axios)
│ ├── components/ # React компоненты (UI kit)
│ ├── contexts/ # React контексты (auth, theme)
│ ├── hooks/ # Custom hooks
│ ├── locales/ # Переводы (i18n)
│ ├── pages/ # Страницы приложения
│ ├── types/ # TypeScript типы
│ └── utils/ # Утилиты
├── public/ # Статические файлы
├── Dockerfile # Docker образ
├── docker-compose.yml # Docker Compose конфигурация
├── Dockerfile # Multi-stage сборка (node → nginx)
├── docker-compose.yml # Docker Compose для сборки
├── nginx.conf # Nginx конфиг внутри контейнера
└── .env.example # Пример переменных окружения
```
## Устранение проблем
### Ошибка CORS
Убедитесь, что домен frontend добавлен в `CABINET_ALLOWED_ORIGINS` в настройках бота.
### API возвращает HTML вместо JSON
Проверьте настройку прокси - запросы на `/api/*` должны попадать на backend, а не на frontend.
### 502 Bad Gateway
Убедитесь что:
1. Backend бот запущен и работает
2. Контейнеры находятся в одной Docker сети
3. Имя сервиса backend в прокси конфигурации правильное
**Проверка связности контейнеров:**
```bash
# Проверить что frontend доступен из Caddy/Nginx контейнера
docker exec <caddy_container> wget -qO- http://cabinet_frontend:80
# Проверить что backend доступен
docker exec <caddy_container> wget -qO- http://remnawave_bot:8080/health
# Проверить в какой сети находятся контейнеры
docker inspect cabinet_frontend | grep -A 10 Networks
docker inspect <caddy_container> | grep -A 10 Networks
```
Если контейнеры в разных сетях, подключите их:
```bash
# Подключить frontend к сети Caddy
docker network connect <caddy_network> cabinet_frontend
# ИЛИ подключить Caddy к сети frontend
docker network connect <frontend_network> <caddy_container>
```
### Telegram авторизация не работает
1. Проверьте `VITE_TELEGRAM_BOT_USERNAME` - должен быть без `@`
2. Убедитесь что домен добавлен в Bot Settings → Domain
## Связанные проекты
- [Remnawave Bedolaga Telegram Bot](https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot) - Backend бота
- [Bedolaga Chat](https://t.me/+wTdMtSWq8YdmZmVi) - Чат поддержки
- [Remnawave Bedolaga Telegram Bot](https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot) Backend бота
- [Bedolaga Chat](https://t.me/+wTdMtSWq8YdmZmVi) Чат поддержки
## Контакты