Update Docker documentation and README for SQLite storage and environment variables
Publish Docker image / build-and-push (push) Successful in 2m13s
Publish Docker image / build-and-push (push) Successful in 2m13s
- Enhanced Docker.md with detailed instructions on building and running Docker images, including environment variable requirements and tag usage. - Updated README.md to reflect the current architecture using SQLite for data storage and clarified environment variable settings for backend and frontend operations. - Removed references to AWS S3, emphasizing local storage for MikroTik backups and SQLite database management. Made-with: Cursor
This commit is contained in:
@@ -1,118 +1,142 @@
|
||||
# Docker Images
|
||||
|
||||
Этот проект предоставляет Docker образы для RouterOS Manager с двумя различными версиями интерфейса.
|
||||
Образ собирается из [`Dockerfile.fast`](Dockerfile.fast) (многостадийная сборка: Vite frontend + `npm ci` backend, рантайм **distroless** Node 20). В Gitea Actions используется тот же файл (см. [`.gitea/workflows/docker-publish.yml`](.gitea/workflows/docker-publish.yml)).
|
||||
|
||||
## 🏷️ Доступные теги
|
||||
## Теги в реестре `git.shts.su`
|
||||
|
||||
### Основная версия (main branch)
|
||||
- `git.shts.su/[repository]:latest` - Стабильная версия с базовым интерфейсом
|
||||
- `git.shts.su/[repository]:[commit-sha]` - Версия с конкретным коммитом
|
||||
Замените `[repository]` на путь репозитория в Gitea (например `denozord/router-lists-ui`).
|
||||
|
||||
### Tabler версия (tabler branch)
|
||||
- `git.shts.su/[repository]:tabler` - Версия с современным Tabler UI
|
||||
- `git.shts.su/[repository]:tabler-[commit-sha]` - Tabler версия с конкретным коммитом
|
||||
| Ветка (триггер push) | Образы в реестре |
|
||||
|----------------------|-------------------|
|
||||
| **main** (и v4, v3 и т.д. из workflow) | `git.shts.su/[repository]:latest` и `git.shts.su/[repository]:<полный-sha>` |
|
||||
| **v5** | **только** `git.shts.su/[repository]:v5` и `git.shts.su/[repository]:v5-<полный-sha>` — тег **`latest` с ветки v5 не публикуется** |
|
||||
| **tabler** | см. отдельный workflow `docker-publish-tabler.yml`, если включён |
|
||||
|
||||
## 🚀 Запуск
|
||||
Пин на коммит: используйте тег с суффиксом `-<sha>`; «плавающий» тег ветки (`:v5` или `:latest`) всегда указывает на последнюю успешную сборку.
|
||||
|
||||
## Запуск (production)
|
||||
|
||||
### Общие рекомендации
|
||||
|
||||
1. **Данные на хосте** — смонтируйте том для SQLite и каталог бэкапов MikroTik, иначе при удалении контейнера пропадут БД и `.rsc`.
|
||||
2. **Переменные** — минимум `ENCRYPTION_KEY`; для справочников и UI — `EVOBGP_API_URL` и `EVOBGP_API_TOKEN`; при необходимости `CORS_ORIGINS`, `PORT`.
|
||||
3. **Рантайм distroless** — внутри образа **нет** `/bin/bash` и пакетного менеджера; отладка через `docker logs` / метрики. Интерактивная оболочка недоступна.
|
||||
|
||||
### Основная линия (`:latest`)
|
||||
|
||||
### Основная версия
|
||||
```bash
|
||||
docker run -d \
|
||||
--name s3-lists-manager \
|
||||
--name router-lists-ui \
|
||||
-p 3001:3001 \
|
||||
-e ENCRYPTION_KEY=your-64-hex-character-key-here \
|
||||
-e ENCRYPTION_KEY=<64-hex> \
|
||||
-e EVOBGP_API_URL=https://evobgp.example/v1 \
|
||||
-e EVOBGP_API_TOKEN=<token> \
|
||||
-e SQLITE_PATH=/data/router-lists.db \
|
||||
-e MIKROTIK_BACKUP_DIR=/data/backups/mikrotik \
|
||||
-v router-lists-data:/data \
|
||||
git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
### Tabler версия
|
||||
Каталог `/data` на томе должен быть доступен пользователю **nonroot** (образ distroless); при ошибках прав создайте том заранее или используйте bind-mount с `chown` под UID образа (обычно `65532` у nonroot).
|
||||
|
||||
### Ветка v5 (только теги `v5` / `v5-<sha>`)
|
||||
|
||||
```bash
|
||||
docker pull git.shts.su/[repository]:v5
|
||||
|
||||
docker run -d \
|
||||
--name router-lists-ui-v5 \
|
||||
-p 3002:3001 \
|
||||
-e ENCRYPTION_KEY=<64-hex> \
|
||||
-e EVOBGP_API_URL=https://evobgp.example/v1 \
|
||||
-e EVOBGP_API_TOKEN=<token> \
|
||||
-e SQLITE_PATH=/data/router-lists.db \
|
||||
-e MIKROTIK_BACKUP_DIR=/data/backups/mikrotik \
|
||||
-v router-lists-v5-data:/data \
|
||||
git.shts.su/[repository]:v5
|
||||
```
|
||||
|
||||
Чтобы зафиксировать конкретный коммит:
|
||||
|
||||
```bash
|
||||
docker run -d ... git.shts.su/[repository]:v5-1c6e6ab...
|
||||
```
|
||||
|
||||
### Tabler-ветка (если публикуется отдельным workflow)
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name s3-lists-manager-tabler \
|
||||
-p 3001:3001 \
|
||||
-e ENCRYPTION_KEY=your-64-hex-character-key-here \
|
||||
--name router-lists-ui-tabler \
|
||||
-p 3003:3001 \
|
||||
--env-file ./backend/.env \
|
||||
-v router-lists-tabler-data:/data \
|
||||
git.shts.su/[repository]:tabler
|
||||
```
|
||||
|
||||
## 🔄 Обновление
|
||||
## Обновление образа
|
||||
|
||||
### latest
|
||||
|
||||
### Основная версия
|
||||
```bash
|
||||
docker pull git.shts.su/[repository]:latest
|
||||
docker stop s3-lists-manager
|
||||
docker rm s3-lists-manager
|
||||
docker run -d \
|
||||
--name s3-lists-manager \
|
||||
-p 3001:3001 \
|
||||
-e ENCRYPTION_KEY=your-64-hex-character-key-here \
|
||||
git.shts.su/[repository]:latest
|
||||
docker stop router-lists-ui && docker rm router-lists-ui
|
||||
# затем снова docker run ... как выше
|
||||
```
|
||||
|
||||
### Tabler версия
|
||||
### v5
|
||||
|
||||
```bash
|
||||
docker pull git.shts.su/[repository]:tabler
|
||||
docker stop s3-lists-manager-tabler
|
||||
docker rm s3-lists-manager-tabler
|
||||
docker run -d \
|
||||
--name s3-lists-manager-tabler \
|
||||
-p 3001:3001 \
|
||||
-e ENCRYPTION_KEY=your-64-hex-character-key-here \
|
||||
git.shts.su/[repository]:tabler
|
||||
docker pull git.shts.su/[repository]:v5
|
||||
docker stop router-lists-ui-v5 && docker rm router-lists-ui-v5
|
||||
docker run -d ... git.shts.su/[repository]:v5
|
||||
```
|
||||
|
||||
## 🐳 Docker Compose
|
||||
## Docker Compose
|
||||
|
||||
Создайте файл `docker-compose.yml`:
|
||||
Пример **одной** службы на `latest` с томом данных (подставьте свой `image:` и при необходимости `env_file`):
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
s3-lists-manager:
|
||||
router-lists-ui:
|
||||
image: git.shts.su/[repository]:latest
|
||||
container_name: s3-lists-manager
|
||||
container_name: router-lists-ui
|
||||
ports:
|
||||
- "3001:3001"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- ENCRYPTION_KEY=${ENCRYPTION_KEY} # Обязательно! Используйте .env файл или secrets
|
||||
# Прокси EvoBGP для UI (Communities / Domains / …) — без CORS в браузере:
|
||||
# - EVOBGP_API_URL=http://evobgp:8080
|
||||
# - EVOBGP_API_TOKEN=...
|
||||
NODE_ENV: production
|
||||
ENCRYPTION_KEY: ${ENCRYPTION_KEY}
|
||||
EVOBGP_API_URL: ${EVOBGP_API_URL}
|
||||
EVOBGP_API_TOKEN: ${EVOBGP_API_TOKEN}
|
||||
SQLITE_PATH: /data/router-lists.db
|
||||
MIKROTIK_BACKUP_DIR: /data/backups/mikrotik
|
||||
volumes:
|
||||
- router-lists-data:/data
|
||||
|
||||
s3-lists-manager-tabler:
|
||||
image: git.shts.su/[repository]:tabler
|
||||
container_name: s3-lists-manager-tabler
|
||||
ports:
|
||||
- "3002:3001"
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- ENCRYPTION_KEY=${ENCRYPTION_KEY} # Обязательно! Используйте .env файл или secrets
|
||||
volumes:
|
||||
router-lists-data:
|
||||
```
|
||||
|
||||
**Создайте файл `.env` в той же директории:**
|
||||
```bash
|
||||
ENCRYPTION_KEY=your-64-hex-character-key-here
|
||||
```
|
||||
Отдельный сервис для **v5** — тот же фрагмент, но `image: git.shts.su/[repository]:v5`, другой `container_name` и при желании отдельный volume.
|
||||
|
||||
Запуск:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
## Переменные окружения (контейнер)
|
||||
|
||||
## 🔧 Переменные окружения
|
||||
| Переменная | Описание | Обязательная |
|
||||
|------------|----------|----------------|
|
||||
| `ENCRYPTION_KEY` | AES-256 для IPSec и паролей MikroTik (64 hex) | **Да** |
|
||||
| `EVOBGP_API_URL` | Базовый URL API EvoBGP (серверный прокси `/api/evobgp` и бэкенд-справочники) | По сценарию |
|
||||
| `EVOBGP_API_TOKEN` | Bearer к EvoBGP | По сценарию |
|
||||
| `SQLITE_PATH` | Путь к файлу SQLite внутри контейнера (персистентный том) | Рекомендуется явно задать, напр. `/data/router-lists.db` |
|
||||
| `MIKROTIK_BACKUP_DIR` | Каталог бэкапов `.rsc` на диске | Рекомендуется с томом, напр. `/data/backups/mikrotik` |
|
||||
| `PORT` | Порт HTTP внутри контейнера | Нет (по умолчанию `3001`) |
|
||||
| `CORS_ORIGINS` | Список Origin через запятую | Нет |
|
||||
| `LOG_LEVEL` | Уровень логов pino | Нет |
|
||||
|
||||
| Переменная | Описание | По умолчанию | Обязательная |
|
||||
|------------|----------|--------------|--------------|
|
||||
| `NODE_ENV` | Окружение Node.js | `production` | Нет |
|
||||
| `PORT` | Порт для запуска сервера | `3001` | Нет |
|
||||
| `ENCRYPTION_KEY` | Ключ шифрования для IPSec паролей (64 hex символа) | - | **Да** |
|
||||
| `EVOBGP_API_URL` | Базовый URL API EvoBGP для серверного прокси `/api/evobgp` (например `http://evobgp:8080` или `http://10.0.0.5:8080`; при необходимости к пути добавляется `/v1`) | - | Да, если используете интеграцию EvoBGP в UI |
|
||||
| `EVOBGP_API_TOKEN` | Bearer-токен к API EvoBGP (только на сервере, не в браузере) | - | Да, если используете интеграцию EvoBGP в UI |
|
||||
`ENCRYPTION_KEY` должен быть **один и тот же** между перезапусками, иначе не расшифровать уже сохранённые секреты.
|
||||
|
||||
### EvoBGP и reverse proxy (nginx)
|
||||
|
||||
Запросы UI идут на тот же origin: `/api/evobgp/…` обрабатывает **Node** внутри образа. Если перед приложением стоит **nginx**, нужно проксировать префикс `/api` на Node **без потери** сегмента `/api` в URI (иначе в upstream попадёт не тот путь и будет 404).
|
||||
Запросы UI идут на тот же origin: `/api/evobgp/…` обрабатывает **Node** внутри образа. Если перед приложением стоит **nginx**, нужно проксировать префикс `/api` на Node **без потери** сегмента `/api` в URI.
|
||||
|
||||
**Рекомендуемый вариант** (путь `/api/…` сохраняется):
|
||||
|
||||
@@ -126,140 +150,64 @@ location /api/ {
|
||||
}
|
||||
```
|
||||
|
||||
**Типичная ошибка**: внутри `location /api` указать `proxy_pass http://127.0.0.1:3001/;` — nginx **срезает** `/api`, в Node приходит `/evobgp/router-lists/catalog` вместо `/api/evobgp/router-lists/catalog`. В коде добавлен запасной маршрут на `/evobgp`, но лучше поправить nginx.
|
||||
**Типичная ошибка**: `proxy_pass http://127.0.0.1:3001/;` — nginx срезает `/api`. В коде есть запасной маршрут на `/evobgp`, но лучше исправить nginx.
|
||||
|
||||
**Проверка**: `GET http://<хост>:<порт>/api/evobgp` (без хвоста) должен вернуть JSON вида `{"ok":true,"proxy":true,"evobgpConfigured":true}` — если вместо этого HTML «404» или страница SPA, запрос **не доходит** до Node (только статика, другой порт или неверный `proxy_pass`).
|
||||
**Проверка**: `GET http://<хост>:<порт>/api/evobgp` → JSON вида `{"ok":true,"proxy":true,"evobgpConfigured":true}`.
|
||||
|
||||
### ENCRYPTION_KEY
|
||||
## Генерация `ENCRYPTION_KEY`
|
||||
|
||||
**Важно**: `ENCRYPTION_KEY` является обязательным параметром для работы с IPSec паролями. Этот ключ используется для шифрования/дешифрования паролей, хранящихся в S3.
|
||||
|
||||
**Генерация ключа:**
|
||||
```bash
|
||||
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||||
```
|
||||
|
||||
**Пример запуска с ENCRYPTION_KEY:**
|
||||
## Мониторинг
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name s3-lists-manager \
|
||||
-p 3001:3001 \
|
||||
-e ENCRYPTION_KEY=your-64-hex-character-key-here \
|
||||
git.shts.su/[repository]:latest
|
||||
docker logs -f router-lists-ui
|
||||
docker stats router-lists-ui
|
||||
```
|
||||
|
||||
**⚠️ Внимание**: Используйте один и тот же `ENCRYPTION_KEY` для всех запусков контейнера. При изменении ключа старые зашифрованные пароли не смогут быть расшифрованы.
|
||||
## Локальная сборка (как в CI)
|
||||
|
||||
## 📊 Мониторинг
|
||||
|
||||
### Просмотр логов
|
||||
```bash
|
||||
# Основная версия
|
||||
docker logs s3-lists-manager
|
||||
|
||||
# Tabler версия
|
||||
docker logs s3-lists-manager-tabler
|
||||
docker build -f Dockerfile.fast -t router-lists-ui:local .
|
||||
docker run --rm -p 3001:3001 --env-file ./backend/.env -v $(pwd)/data:/data \
|
||||
-e SQLITE_PATH=/data/router-lists.db \
|
||||
-e MIKROTIK_BACKUP_DIR=/data/backups/mikrotik \
|
||||
router-lists-ui:local
|
||||
```
|
||||
|
||||
### Статистика контейнеров
|
||||
(PowerShell на Windows: вместо `$(pwd)` используйте путь к каталогу данных.)
|
||||
|
||||
## CI/CD (Gitea Actions)
|
||||
|
||||
- [`.gitea/workflows/docker-publish.yml`](.gitea/workflows/docker-publish.yml) — пуш в перечисленные ветки (включая **v5**): сборка и push в `git.shts.su`.
|
||||
- Для **v5** в реестр уходят **только** теги `v5` и `v5-<sha>` (без `latest`).
|
||||
- Остальные ветки из списка workflow — `latest` и тег по SHA.
|
||||
|
||||
Шаг **Trigger container update webhook** (если задан `secrets.portainer_webhook`) выполняется после сборки; при ошибке шаг не валит job (`continue-on-error: true`).
|
||||
|
||||
## Безопасность и сеть
|
||||
|
||||
```bash
|
||||
docker stats s3-lists-manager s3-lists-manager-tabler
|
||||
docker network create router-lists-net
|
||||
docker run -d --network router-lists-net ... git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
## 🔍 Отладка
|
||||
Ограничение ресурсов:
|
||||
|
||||
### Вход в контейнер
|
||||
```bash
|
||||
# Основная версия
|
||||
docker exec -it s3-lists-manager /bin/bash
|
||||
|
||||
# Tabler версия
|
||||
docker exec -it s3-lists-manager-tabler /bin/bash
|
||||
docker run -d --memory=512m --cpus=0.5 ... git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
### Проверка процессов
|
||||
```bash
|
||||
docker exec s3-lists-manager ps aux
|
||||
```
|
||||
## Устранение неполадок
|
||||
|
||||
## 🏗️ Сборка локально
|
||||
|
||||
### Основная версия
|
||||
```bash
|
||||
git checkout main
|
||||
docker build -t s3-lists-manager:local .
|
||||
```
|
||||
|
||||
### Tabler версия
|
||||
```bash
|
||||
git checkout tabler
|
||||
docker build -t s3-lists-manager-tabler:local .
|
||||
```
|
||||
|
||||
## 📝 CI/CD
|
||||
|
||||
### Автоматическая сборка
|
||||
|
||||
- **Ветка `main`**: Автоматически создает образ с тегом `latest`
|
||||
- **Ветка `tabler`**: Автоматически создает образ с тегом `tabler`
|
||||
|
||||
### Workflow файлы
|
||||
|
||||
- `.gitea/workflows/docker-publish.yml` - Сборка основной версии
|
||||
- `.gitea/workflows/docker-publish-tabler.yml` - Сборка Tabler версии
|
||||
|
||||
## 🔒 Безопасность
|
||||
|
||||
### Проверка образа
|
||||
```bash
|
||||
docker scan git.shts.su/[repository]:latest
|
||||
docker scan git.shts.su/[repository]:tabler
|
||||
```
|
||||
|
||||
### Запуск в изолированной сети
|
||||
```bash
|
||||
docker network create s3-lists-network
|
||||
docker run -d \
|
||||
--name s3-lists-manager \
|
||||
--network s3-lists-network \
|
||||
-p 3001:3001 \
|
||||
git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
## 📈 Производительность
|
||||
|
||||
### Ограничение ресурсов
|
||||
```bash
|
||||
docker run -d \
|
||||
--name s3-lists-manager \
|
||||
--memory=512m \
|
||||
--cpus=0.5 \
|
||||
-p 3001:3001 \
|
||||
git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
### Мониторинг ресурсов
|
||||
```bash
|
||||
docker stats --no-stream s3-lists-manager
|
||||
```
|
||||
|
||||
## 🆘 Устранение неполадок
|
||||
|
||||
### Проверка статуса контейнера
|
||||
```bash
|
||||
docker ps -a | grep s3-lists-manager
|
||||
```
|
||||
|
||||
### Перезапуск контейнера
|
||||
```bash
|
||||
docker restart s3-lists-manager
|
||||
```
|
||||
|
||||
### Очистка неиспользуемых образов
|
||||
```bash
|
||||
docker ps -a --filter name=router-lists-ui
|
||||
docker restart router-lists-ui
|
||||
docker image prune -f
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Примечание**: Замените `[repository]` на актуальное имя вашего репозитория в Gitea.
|
||||
**Замените `[repository]`** на актуальный путь репозитория в Gitea (например `denozord/router-lists-ui`).
|
||||
|
||||
@@ -1,347 +1,129 @@
|
||||
# Router Lists UI
|
||||
|
||||
Полноценный UI/Backend для управления списками BGP (домены, IP-диапазоны, ASNs), фильтрами и конфигурациями MikroTik на базе S3 (Yandex Object Storage). Интерфейс построен на Tabler, frontend — Vite + React, backend — Express.
|
||||
UI/Backend для управления BGP-списками, фильтрами и конфигурациями MikroTik.
|
||||
Текущая модель хранения: **SQLite + локальная файловая система** (для `.rsc` backup MikroTik).
|
||||
|
||||
## Актуальная архитектура хранения
|
||||
|
||||
- Основные данные и объекты приложения хранятся в SQLite (через `better-sqlite3`).
|
||||
- MikroTik backup-файлы (`.rsc`) хранятся в локальной ФС в каталоге `MIKROTIK_BACKUP_DIR`.
|
||||
- AWS SDK/S3 в runtime не используются.
|
||||
- Часть имен API/сервисов (`s3*`) сохранена для обратной совместимости, но фактический backend storage — SQLite.
|
||||
|
||||
## Быстрый старт
|
||||
|
||||
### Требования
|
||||
|
||||
- Node.js 18+
|
||||
- S3-совместимое хранилище (Yandex Object Storage)
|
||||
- Доступы AWS: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `S3_BUCKET_NAME`, `AWS_REGION`
|
||||
- npm
|
||||
|
||||
### Запуск backend
|
||||
|
||||
```powershell
|
||||
cd backend
|
||||
npm i
|
||||
npm install
|
||||
# создайте .env и заполните (пример ниже)
|
||||
npm start
|
||||
```
|
||||
Сервис поднимется на `http://localhost:3001`.
|
||||
|
||||
Backend поднимется на `http://localhost:3001`.
|
||||
|
||||
### Запуск frontend
|
||||
```bash
|
||||
|
||||
```powershell
|
||||
cd frontend
|
||||
npm i
|
||||
npm install
|
||||
npm run dev
|
||||
```
|
||||
Frontend доступен на `http://localhost:5173` (по умолчанию). Production-сборка: `npm run build`.
|
||||
|
||||
## Главные особенности
|
||||
- Единая UX/UI библиотека Tabler, адаптивные панели действий и навигация.
|
||||
- Онлайн-обновление (WebSocket) BGP c потоковым логом и фоновое обновление (HTTP POST) из UI.
|
||||
- Блокировки (soft-lock) ресурсов с TTL, чтобы избежать гонок при одновременном редактировании.
|
||||
- Версионирование данных (история/откат), если включено версии в бакете.
|
||||
- Генерация конфигурации MikroTik из фильтров (`/api/filters/generate-config`) и экспорт в S3.
|
||||
- Метрики Prometheus: `/metrics`, health/ready: `/health`, `/ready`.
|
||||
Frontend доступен на `http://localhost:5173`.
|
||||
|
||||
### Важные переменные окружения
|
||||
- `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION`, `S3_BUCKET_NAME` — доступ к Object Storage
|
||||
- `ENCRYPTION_KEY` — ключ шифрования (64 hex символа) для IPSec и MikroTik паролей
|
||||
- `CORS_ORIGINS` — список разрешённых Origin через запятую (если пусто — разрешены все)
|
||||
- `LOG_LEVEL` — уровень логов pino (`info` по умолчанию)
|
||||
- `PORT` — порт backend (по умолчанию 3001)
|
||||
- `BGP_BACKGROUND_URL` — адрес фонового обновления BGP, например:
|
||||
- `http://77.232.38.173:8080/api/update_bgp/background?api_key=...`
|
||||
- Используется эндпоинтом прокси `POST /api/update-bgp/background` для обхода CORS
|
||||
## Важные переменные окружения
|
||||
|
||||
- `SQLITE_PATH` — путь к файлу SQLite (по умолчанию `backend/data/router-lists.db`).
|
||||
- `MIKROTIK_BACKUP_DIR` — каталог для локальных `.rsc` backup-файлов MikroTik.
|
||||
- `ENCRYPTION_KEY` — 64 hex-символа для шифрования секретов (IPSec/MikroTik).
|
||||
- `EVOBGP_API_URL`, `EVOBGP_API_TOKEN` — если используете интеграцию EvoBGP.
|
||||
- `CORS_ORIGINS`, `LOG_LEVEL`, `PORT` — эксплуатационные настройки сервиса.
|
||||
- `BGP_BACKGROUND_URL` — URL фонового обновления BGP для прокси-эндпоинта `POST /api/update-bgp/background`.
|
||||
|
||||
Пример `.env`:
|
||||
|
||||
```dotenv
|
||||
PORT=3001
|
||||
LOG_LEVEL=info
|
||||
AWS_ACCESS_KEY_ID=...
|
||||
AWS_SECRET_ACCESS_KEY=...
|
||||
AWS_REGION=ru-central1
|
||||
S3_BUCKET_NAME=...
|
||||
SQLITE_PATH=./data/router-lists.db
|
||||
MIKROTIK_BACKUP_DIR=./data/backups/mikrotik
|
||||
ENCRYPTION_KEY=<64-hex>
|
||||
CORS_ORIGINS=http://localhost:5173
|
||||
BGP_BACKGROUND_URL=http://77.232.38.173:8080/api/update_bgp/background?api_key=denozord2502
|
||||
BGP_BACKGROUND_URL=http://77.232.38.173:8080/api/update_bgp/background?api_key=...
|
||||
```
|
||||
|
||||
## API (backend)
|
||||
|
||||
Все ответы об ошибке имеют единый формат:
|
||||
Формат ошибок:
|
||||
|
||||
```json
|
||||
{ "code": "E_*", "message": "...", "details": {}, "requestId": "..." }
|
||||
```
|
||||
Успешные POST/PUT возвращают:
|
||||
|
||||
Формат успешных `POST/PUT`:
|
||||
|
||||
```json
|
||||
{ "ok": true, "etag": "...", "lastModified": "ISO", "contentLength": 123 }
|
||||
```
|
||||
И всегда выставляют заголовки `ETag`, `Last-Modified`, `Content-Length-Source` (если есть). GET поддерживают `countOnly=true` там, где это логично.
|
||||
|
||||
### Данные
|
||||
- GET `/api/domains-new` — список доменов `{ domain, community }`
|
||||
- `?q=`, `?offset=`, `?limit=`, `?countOnly=true`, `?format=std`
|
||||
- POST `/api/domains-new` — `{ domains: [{domain, community}], etag }`
|
||||
### Примечание по legacy-терминам
|
||||
|
||||
- GET `/api/ip-ranges` — список `[{ ipRange, community }]`
|
||||
- POST `/api/ip-ranges` — `{ ipRanges: [{ipRange, community}], etag }`
|
||||
- `GET /api/s3/last-modified` и функции вида `readS3*`/`writeS3*` — это **legacy-названия**.
|
||||
- Фактически эти операции работают с SQLite-backed хранилищем.
|
||||
|
||||
- GET `/api/asns` — список `[{ domain, type }]` (domain = AS, type = community)
|
||||
- POST `/api/asns` — `{ domains: [{domain, type}], etag }`
|
||||
### Основные эндпоинты
|
||||
|
||||
- GET `/api/communities` — справочник community (JSON)
|
||||
- POST `/api/communities` — `{ communities: [...] }` (валидация уникальности value)
|
||||
- Данные: `/api/domains-new`, `/api/ip-ranges`, `/api/asns`, `/api/communities`
|
||||
- Фильтры/конфиги: `/api/filters`, `/api/server-configs`, `/api/server-filters`
|
||||
- MikroTik: `/api/mikrotik/generate`, `/api/mikrotik/generate-interfaces`, `/api/mikrotik/generate-recursive-routes`, `/api/mikrotik/test-connection`, `/api/mikrotik/apply`
|
||||
- Прочее: `/api/servers`, `/api/billing`, `/api/auto-urls`, `/api/servers/availability`, `/api/locks/:resource`, `/api/history/:resource`
|
||||
|
||||
### Фильтры и конфигурации
|
||||
- GET `/api/filters` / POST `/api/filters` — фильтры для всех серверов.
|
||||
- GET `/api/filters/generate-config?format=text|json` — сгенерировать конфиг MikroTik из `filters.json`.
|
||||
- POST `/api/filters/export-config` — сохранить сгенерированный конфиг в S3 (`mikrotik-frouting-config.txt`).
|
||||
## Docker
|
||||
|
||||
- GET `/api/server-configs` / POST `/api/server-configs` — список серверов (id, name, ...).
|
||||
- GET `/api/server-configs/:serverId` / POST `/api/server-configs/:serverId` — конфиг конкретного сервера.
|
||||
- DELETE `/api/server-configs/:serverId` — удалить конфиг.
|
||||
- DELETE `/api/server-configs/:serverId/complete` — удалить конфиг и фильтры.
|
||||
Полная инструкция: [DOCKER.md](DOCKER.md).
|
||||
|
||||
- GET `/api/server-filters/:serverId` — фильтры сервера.
|
||||
- POST `/api/server-filters/:serverId` — сохранить фильтры сервера.
|
||||
- POST `/api/server-filters/generate-config` — сгенерировать конфиг MikroTik на лету из переданных `{ filters, format?: 'text'|'json' }`.
|
||||
- POST `/api/mikrotik/generate` — сгенерировать конфиг интерфейсов и маршрутов. Body: `{ format?: 'text'|'json', type?: 'interfaces'|'recursive'|'all', serverId?: string, config?, servers? }`. Возвращает `{ blocks }` — массив блоков с полем `code` (text) или `operations` (json).
|
||||
- GET `/api/mikrotik/generate-interfaces?format=text|json&serverId=` — только интерфейсы.
|
||||
- GET `/api/mikrotik/generate-recursive-routes?format=text|json&serverId=` — только рекурсивные маршруты.
|
||||
- POST `/api/mikrotik/test-connection` — проверить соединение с MikroTik. Body: `{ serverId }` или `{ host, port?, user?, password }`.
|
||||
- POST `/api/mikrotik/apply` — применить конфигурацию на MikroTik по API. Body: `{ serverId, type?: 'interfaces'|'recursive'|'all', dryRun?: boolean }`. Только для jumphost.
|
||||
Критично для production:
|
||||
|
||||
### Прочее
|
||||
- GET `/api/servers` / POST `/api/servers` — список серверов.
|
||||
- GET `/api/billing` / POST `/api/billing` — биллинг (ноды, статусы и т.п.).
|
||||
- GET `/api/auto-urls` / POST `/api/auto-urls` — список авто-URL.
|
||||
- POST `/api/auto-urls/process` — обработать авто-URL и добавить IP в `bgp_data/ips.txt`.
|
||||
- GET `/api/servers/availability?ttlSeconds=60` — быстрый TCP‑чек доступности нод.
|
||||
- GET `/api/s3/last-modified` — метаданные S3 (etag/lastModified/contentLength) по ключевым файлам.
|
||||
- POST `/api/update-bgp/background` — прокси к фоновой задаче обновления BGP. Требует `BGP_BACKGROUND_URL` в `.env`.
|
||||
- Locks: GET `/api/locks/:resource`, POST `/api/locks/:resource`, DELETE `/api/locks/:resource` (опциональные soft-locks для редактирования; доступ к S3 и долгие операции вроде speed-test блокировок не используют).
|
||||
- History: GET `/api/history/:resource`, POST `/api/history/:resource/rollback`.
|
||||
- Обязательно смонтировать volume для пути с `SQLITE_PATH`.
|
||||
- Обязательно смонтировать volume для `MIKROTIK_BACKUP_DIR`, иначе `.rsc` backup-файлы потеряются при пересоздании контейнера.
|
||||
- Использовать стабильный `ENCRYPTION_KEY` между перезапусками.
|
||||
|
||||
## Frontend
|
||||
- Vite + React, Tabler CSS/JS (`@tabler/core`).
|
||||
- Общий компонент `PageHeaderActions` — единый toolbar на страницах данных.
|
||||
- Модалка `WsUpdateModal` — поток логов online-обновления (ws).
|
||||
- Доступность: роли, подписи, фокус-кольца, hot-path без мыши.
|
||||
Пример запуска:
|
||||
|
||||
### Скрипты
|
||||
```bash
|
||||
npm run dev # dev-сервер
|
||||
npm run build # продакшн сборка
|
||||
```powershell
|
||||
docker run -d `
|
||||
--name router-lists-ui `
|
||||
-p 3001:3001 `
|
||||
--env-file ./backend/.env `
|
||||
-e SQLITE_PATH=/data/router-lists.db `
|
||||
-e MIKROTIK_BACKUP_DIR=/data/backups/mikrotik `
|
||||
-v router-lists-data:/data `
|
||||
git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
## Чек-лист проверки соответствия (S3 -> SQLite)
|
||||
|
||||
1. В `backend/package.json` нет зависимостей AWS SDK.
|
||||
2. Приложение стартует с `SQLITE_PATH` и создает/использует файл БД.
|
||||
3. CRUD по основным данным (`/api/domains-new`, `/api/ip-ranges`, `/api/asns`) работает после перезапуска контейнера с тем же volume.
|
||||
4. Созданный MikroTik backup появляется как локальный `.rsc` файл в каталоге `MIKROTIK_BACKUP_DIR`.
|
||||
5. После перезапуска контейнера с тем же volume backup-файл остается доступным.
|
||||
6. `GET /api/s3/last-modified` возвращает метаданные, но интерпретируется как legacy endpoint поверх SQLite.
|
||||
|
||||
## Структура репозитория
|
||||
```
|
||||
backend/ # Express API
|
||||
frontend/ # Vite React UI
|
||||
```
|
||||
|
||||
## Безопасность и эксплуатация
|
||||
- Helmet, RateLimit, CORS, отключён слабый etag на JSON.
|
||||
- Prometheus метрики по умолчанию.
|
||||
- Для истории версий включите versioning в бакете S3.
|
||||
```text
|
||||
backend/ Express API
|
||||
frontend/ Vite + React UI
|
||||
```
|
||||
|
||||
## Лицензия
|
||||
|
||||
MIT
|
||||
|
||||
# 📂 RouterOS Manager
|
||||
|
||||
|
||||
Веб-интерфейс для удобного управления файлами в S3-совместимом хранилище Yandex Cloud. Приложение позволяет в реальном времени просматривать, добавлять, редактировать, удалять и массово изменять записи в следующих файлах:
|
||||
|
||||
- **domains.txt** - список доменов и их шлюзов
|
||||
- **asns.txt** - список AS номеров и их шлюзов
|
||||
- **servers.json** - список серверов с расширенной информацией (IP, DNS, страна, провайдер, тип туннеля)
|
||||
|
||||
## ✨ Возможности
|
||||
|
||||
- **Три режима работы:** Управление списками доменов, AS-номеров и серверов через вкладки.
|
||||
- **CRUD операции:** Полный набор действий: создание, чтение, обновление и удаление записей.
|
||||
- **Поиск в реальном времени:** Мгновенная фильтрация списков по мере ввода.
|
||||
- **Массовая замена:** Быстрое обновление шлюзов для сотен записей в один клик.
|
||||
- **Сохранение в S3:** Все изменения сохраняются непосредственно в файлах в бакете Yandex Cloud.
|
||||
- **Docker-контейнеризация:** Готовый `Dockerfile` для сборки и запуска приложения в изолированном окружении.
|
||||
- **CI/CD с Gitea Actions:** Автоматическая сборка и публикация Docker-образа в Gitea Registry при пуше в `main`.
|
||||
- **Современный интерфейс:** Полностью интегрированный Tabler UI с официальными компонентами.
|
||||
|
||||
## 🛠️ Технологический стек
|
||||
|
||||
| Область | Технология |
|
||||
|--------------|-----------------------------------------------------------------------------------------------------------|
|
||||
| **Фронтенд** | [**React**](https://reactjs.org/) + [**Vite**](https://vitejs.dev/) |
|
||||
| | [**@tabler/core**](https://tabler.io/) (UI-компоненты для Tabler версии) |
|
||||
| | [**Tabler Icons**](https://tabler-icons.io/) (иконки) |
|
||||
| | [**Axios**](https://axios-http.com/) (HTTP-клиент) |
|
||||
| **Бэкенд** | [**Node.js**](https://nodejs.org/) + [**Express**](https://expressjs.com/) |
|
||||
| | [**AWS SDK for JS**](https://aws.amazon.com/sdk-for-javascript/) (для работы с Yandex Cloud S3) |
|
||||
| **CI/CD** | [**Docker**](https://www.docker.com/), [**Gitea Actions**](https://gitea.com/blog/2022/10/01/gitea-actions/) |
|
||||
|
||||
## 🏗️ Архитектура
|
||||
|
||||
Приложение состоит из двух основных частей: фронтенд на React и бэкенд на Node.js/Express, которые взаимодействуют через REST API.
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
subgraph Browser
|
||||
A[React Frontend]
|
||||
end
|
||||
|
||||
subgraph Server
|
||||
B(Node.js/Express API)
|
||||
end
|
||||
|
||||
subgraph Yandex Cloud
|
||||
C{S3 Bucket}
|
||||
D1[domains.txt]
|
||||
D2[asns.txt]
|
||||
D3[servers.json]
|
||||
end
|
||||
|
||||
A -- HTTP Requests --> B
|
||||
B -- AWS SDK --> C
|
||||
C --- D1
|
||||
C --- D2
|
||||
```
|
||||
|
||||
## 🚀 Установка и запуск
|
||||
|
||||
### Предварительные требования
|
||||
|
||||
- [Node.js](https://nodejs.org/) (v20.x или выше)
|
||||
- [npm](https://www.npmjs.com/) или [yarn](https://yarnpkg.com/)
|
||||
- Доступ к бакету Yandex Cloud S3 и сервисный аккаунт с правами на чтение и запись.
|
||||
|
||||
### 1. Настройка бэкенда
|
||||
|
||||
1. Перейдите в директорию `backend`:
|
||||
```bash
|
||||
cd backend
|
||||
```
|
||||
2. Создайте файл `.env` на основе примера `.env.example`. Заполните его вашими учетными данными от Yandex Cloud S3:
|
||||
```env
|
||||
# .env
|
||||
S3_ACCESS_KEY_ID=ВАШ_КЛЮЧ_ДОСТУПА
|
||||
S3_SECRET_ACCESS_KEY=ВАШ_СЕКРЕТНЫЙ_КЛЮЧ
|
||||
S3_BUCKET_NAME=ИМЯ_ВАШЕГО_БАКЕТА
|
||||
```
|
||||
3. Установите зависимости:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 2. Настройка фронтенда
|
||||
|
||||
1. Перейдите в директорию `frontend`:
|
||||
```bash
|
||||
cd ../frontend
|
||||
```
|
||||
2. Установите зависимости:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
### 3. Запуск приложения
|
||||
|
||||
1. **Запустите бэкенд-сервер.** В директории `backend` выполните:
|
||||
```bash
|
||||
npm start
|
||||
```
|
||||
Сервер запустится на `http://localhost:3001`.
|
||||
|
||||
2. **Запустите фронтенд.** В новой вкладке терминала, в директории `frontend`, выполните:
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
Приложение будет доступно по адресу `http://localhost:5173` и будет автоматически проксировать API-запросы на бэкенд.
|
||||
|
||||
## 🐳 Docker
|
||||
|
||||
Приложение полностью готово к запуску в Docker с двумя вариантами интерфейса.
|
||||
|
||||
### Доступные образы
|
||||
|
||||
#### Основная версия (main branch)
|
||||
```bash
|
||||
git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
#### Tabler версия (tabler branch)
|
||||
```bash
|
||||
git.shts.su/[repository]:tabler
|
||||
```
|
||||
|
||||
### Быстрый запуск
|
||||
|
||||
#### Основная версия
|
||||
```bash
|
||||
docker run -d \
|
||||
--name s3-lists-manager \
|
||||
-p 3001:3001 \
|
||||
--env-file ./backend/.env \
|
||||
git.shts.su/[repository]:latest
|
||||
```
|
||||
|
||||
#### Tabler версия
|
||||
```bash
|
||||
docker run -d \
|
||||
--name s3-lists-manager-tabler \
|
||||
-p 3002:3001 \
|
||||
--env-file ./backend/.env \
|
||||
git.shts.su/[repository]:tabler
|
||||
```
|
||||
|
||||
### Локальная сборка
|
||||
|
||||
Для сборки образа выполните команду в корневой директории проекта:
|
||||
```bash
|
||||
docker build -t s3-lists-manager .
|
||||
```
|
||||
|
||||
### Запуск контейнера
|
||||
|
||||
Для запуска контейнера необходимо передать переменные окружения. Это можно сделать с помощью флага `-e` или через `--env-file`.
|
||||
|
||||
```bash
|
||||
docker run --rm -p 3001:3001 --env-file ./backend/.env s3-lists-manager
|
||||
```
|
||||
|
||||
После этого приложение будет доступно по адресу `http://localhost:3001`.
|
||||
|
||||
### Docker Compose
|
||||
|
||||
Создайте файл `docker-compose.yml`:
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
s3-lists-manager:
|
||||
image: git.shts.su/[repository]:latest
|
||||
container_name: s3-lists-manager
|
||||
ports:
|
||||
- "3001:3001"
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ./backend/.env
|
||||
|
||||
s3-lists-manager-tabler:
|
||||
image: git.shts.su/[repository]:tabler
|
||||
container_name: s3-lists-manager-tabler
|
||||
ports:
|
||||
- "3002:3001"
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- ./backend/.env
|
||||
```
|
||||
|
||||
Запуск:
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
Подробная документация по Docker образам доступна в файле [DOCKER.md](DOCKER.md).
|
||||
|
||||
## ⚙️ API Endpoints
|
||||
|
||||
| Метод | Путь | Описание |
|
||||
|--------|---------------|----------------------------------|
|
||||
| `GET` | `/api/domains`| Получить список всех доменов. |
|
||||
| `POST` | `/api/domains`| Сохранить изменения в `domains.txt`. |
|
||||
| `GET` | `/api/asns` | Получить список всех AS. |
|
||||
| `POST` | `/api/asns` | Сохранить изменения в `asns.txt`. |
|
||||
| `GET` | `/api/servers`| Получить список всех серверов. |
|
||||
| `POST` | `/api/servers`| Сохранить изменения в `servers.json`. |
|
||||
Reference in New Issue
Block a user