194 lines
12 KiB
Markdown
194 lines
12 KiB
Markdown
# Proxmox VPS Panel
|
||
|
||
Self-hosted панель для мульти-тенантного управления VPS (VM и LXC) на вашем
|
||
Proxmox VE через API. Backend — FastAPI (Python), frontend — React (Vite), хранилище — Postgres.
|
||
|
||
Клиенты регистрируются, выбирают шаблон и разворачивают себе VM или LXC-контейнер одной кнопкой;
|
||
дальше могут запускать/останавливать/перезагружать/удалять сервер и управлять им через SSH.
|
||
Первый зарегистрированный пользователь автоматически становится администратором и управляет
|
||
шаблонами и списком пользователей.
|
||
|
||
## Возможности
|
||
|
||
- Регистрация/логин (JWT), роли admin / client
|
||
- Шаблоны VPS: админ создаёт тарифы, привязанные к VM-шаблону (клонирование) или CT-шаблону LXC
|
||
- Клиент создаёт инстанс из шаблона — панель сама берёт свободный VMID и вызывает Proxmox API
|
||
- Действия: start / stop / shutdown / reboot / delete
|
||
- Управление через SSH — IP-адрес инстанса виден в дашборде, логин/пароль задаются через cloud-init
|
||
- Проверка владельца во всех эндпоинтах — клиент не может управлять чужими VM
|
||
- Всё через docker-compose, разворачивается как Custom App в TrueNAS SCALE
|
||
- Healthcheck-эндпоинты (`/health`, `/health/ready`) и Docker-healthcheck у всех сервисов
|
||
- Backend работает от непривилегированного пользователя (non-root)
|
||
|
||
## Чего нет (сознательно, чтобы не раздувать первую версию)
|
||
|
||
- Поддержки нескольких Proxmox-нод/кластеров одновременно (сейчас один `PVE_NODE` в конфиге)
|
||
- Биллинга и лимитов по ресурсам на пользователя
|
||
- Очереди задач (Celery/Redis) — создание VPS идёт в фоне через `BackgroundTasks` FastAPI,
|
||
для нескольких одновременных заявок этого достаточно, для десятков в секунду — уже нет
|
||
- Управления сетью/IP-пулами (LXC получает адрес по DHCP, для VM выдаётся из клонированного шаблона)
|
||
- Веб-консоли (VNC) — для доступа к виртуальным машинам используйте SSH
|
||
- Alembic-миграций (сейчас `create_all()` — для прода рекомендуется добавить)
|
||
- Создания LXC из существующего контейнера по VMID — только из архива .tar.zst на storage
|
||
|
||
## 1. Подготовка Proxmox
|
||
|
||
### API-токен
|
||
|
||
Datacenter → Permissions → API Tokens → добавить токен для пользователя (например `root@pam`,
|
||
в проде лучше завести отдельного пользователя с минимально нужными правами).
|
||
|
||
Права, которые нужны панели: создание/клонирование/удаление VM и CT, управление питанием,
|
||
`Sys.Audit` для чтения статусов задач.
|
||
|
||
### Шаблон для VM
|
||
|
||
Создайте одну VM с cloud-init образом (Ubuntu/Debian cloud image), настройте её и переведите
|
||
в шаблон (`qm template <vmid>`). Полученный VMID указывается в панели как `source_vmid` шаблона.
|
||
|
||
### Шаблон для LXC
|
||
|
||
Скачайте официальный CT-шаблон через Proxmox (Node → local (storage) → CT Templates → Download),
|
||
например `debian-12-standard_12.7-1_amd64.tar.zst`. В панели укажите его как `source_template`
|
||
в формате `local:vztmpl/имя_файла.tar.zst`.
|
||
|
||
Панель создаёт LXC из такого архива в 4 шага:
|
||
1. `POST /nodes/{node}/lxc` с `ostemplate`, `start=0` (без запуска).
|
||
2. `POST /nodes/{node}/lxc/{vmid}/passwd` — установка root-пароля.
|
||
3. `PUT /nodes/{node}/lxc/{vmid}/resize` — создание rootfs нужного размера.
|
||
4. `POST /nodes/{node}/lxc/{vmid}/status/start` — запуск контейнера.
|
||
|
||
## 2. Настройка backend
|
||
|
||
Скопируйте `backend/.env.example` в `backend/.env` и заполните:
|
||
|
||
```
|
||
SECRET_KEY=<случайная строка> # обязательно смените!
|
||
PVE_HOST=https://<ip-вашего-proxmox>:8006
|
||
PVE_NODE=pve
|
||
PVE_TOKEN_NAME=root@pam!panel
|
||
PVE_TOKEN_VALUE=<значение токена>
|
||
```
|
||
|
||
Пароль Postgres задаётся через переменную окружения `POSTGRES_PASSWORD` в shell
|
||
или через `.env` рядом с `docker-compose.yml` (compose читает оба файла).
|
||
|
||
## 3. Настройка CORS
|
||
|
||
В `backend/.env` укажите `ALLOW_ORIGINS` — список доменов через запятую, с которыми
|
||
фронтенд будет обращаться к API. По умолчанию это `http://localhost:5173,http://127.0.0.1:5173`.
|
||
Для прода обязательно укажите конкретный домен:
|
||
|
||
```
|
||
ALLOW_ORIGINS=https://panel.example.com
|
||
```
|
||
|
||
## 4. Запуск
|
||
|
||
```bash
|
||
# Установите обязательные переменные:
|
||
export POSTGRES_PASSWORD=$(openssl rand -hex 16)
|
||
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Frontend будет на `http://<host>:5173`. Backend API наружу **не пробрасывается** —
|
||
все запросы идут через nginx фронтенда по пути `/api/*`. Если нужен прямой доступ
|
||
для отладки — раскомментируйте `ports` у сервиса `backend` в `docker-compose.yml`
|
||
(только `127.0.0.1:8000:8000`).
|
||
|
||
Первый, кто зарегистрируется на `/register`, станет администратором — заходите первым сами.
|
||
|
||
## 5. Установка на TrueNAS SCALE
|
||
|
||
TrueNAS SCALE умеет запускать произвольные Docker-приложения ("Apps → Discover Apps → Custom App"
|
||
либо через "Launch Docker Compose", если версия TrueNAS это поддерживает). Проще всего:
|
||
|
||
1. Скопируйте папку проекта на TrueNAS (например, в датасет `/mnt/tank/apps/vps-panel`).
|
||
2. Заполните `backend/.env`, как описано выше.
|
||
3. Из этой директории выполните `docker compose up -d --build` через shell TrueNAS
|
||
(System Settings → Shell, либо через SSH), либо оформите как Custom App.
|
||
4. Откройте порт 5173 наружу через reverse-proxy (например, встроенный в TrueNAS, либо
|
||
отдельный Nginx Proxy Manager), если панель должна быть доступна клиентам извне.
|
||
|
||
## Доступ к виртуальным машинам
|
||
|
||
IP-адрес инстанса виден в дашборде и в карточке инстанса (получается через
|
||
QEMU Guest Agent или LXC-интерфейсы). Для доступа:
|
||
|
||
```bash
|
||
ssh <cloud-init-user>@<ip-адрес>
|
||
```
|
||
|
||
Логин и пароль задаются клиентом при создании инстанса (поля «Пользователь» и «Пароль»
|
||
в форме создания — пробрасываются в cloud-init гостевой ОС).
|
||
|
||
## Безопасность перед продакшеном
|
||
|
||
- Смените `SECRET_KEY` и задайте сильный `POSTGRES_PASSWORD`
|
||
- Укажите конкретный домен в `ALLOW_ORIGINS` (а не `*`)
|
||
- Backend-порт 8000 не должен торчать наружу — закрыт по умолчанию, используйте nginx
|
||
- Используйте отдельного Proxmox-пользователя с минимально необходимыми правами для токена
|
||
панели, а не `root@pam`
|
||
- Не публикуйте `backend/.env` (он в `.gitignore`)
|
||
|
||
## Структура проекта
|
||
|
||
```
|
||
backend/
|
||
app/
|
||
main.py — точка входа FastAPI
|
||
config.py — переменные окружения (Pydantic v2 Settings)
|
||
database.py — SQLAlchemy engine и сессии
|
||
security.py — bcrypt + JWT
|
||
deps.py — Depends(get_current_user, require_admin)
|
||
models.py — таблицы: User, Template, Instance
|
||
schemas.py — Pydantic-схемы запросов/ответов
|
||
proxmox_client.py — вся логика вызовов Proxmox API (proxmoxer)
|
||
routers/
|
||
auth.py — регистрация / логин / /me
|
||
templates.py — CRUD шаблонов (admin) + импорт из Proxmox
|
||
instances.py — создание/список/действия/удаление VPS
|
||
admin.py — управление пользователями
|
||
frontend/
|
||
src/
|
||
pages/ — Login, Register, Dashboard, InstanceDetail, AdminTemplates, AdminUsers
|
||
components/ — InstanceCard
|
||
api.js — обёртка над fetch к backend
|
||
styles.css — UI-стили
|
||
docker-compose.yml
|
||
.gitignore
|
||
.dockerignore — для backend и frontend
|
||
```
|
||
|
||
## Changelog
|
||
|
||
### 0.4.0
|
||
- 🗑 **Удалено**: создание LXC путём клонирования существующего контейнера по VMID (`clone_lxc`).
|
||
LXC теперь создаётся ТОЛЬКО из архивного шаблона (`vztmpl/*.tar.zst`).
|
||
- 🛠 **Переписан `create_lxc`**: 4 явных шага — `ostemplate` → `passwd` → `resize` → `start`.
|
||
Раньше всё делалось одним POST-запросом с кучей параметров, теперь каждый шаг — отдельный
|
||
вызов Proxmox API, что упрощает отладку и делает процесс прозрачным.
|
||
- 🛠 Убран дублирующий `guest_action(start)` после создания LXC — старт теперь выполняется
|
||
внутри `create_lxc`.
|
||
|
||
### 0.3.0
|
||
- 🗑 Удалена VNC-консоль — для доступа к VM используйте SSH по IP из дашборда
|
||
- 🛠 Упрощена nginx-конфигурация (убран WebSocket-прокси для VNC)
|
||
- 🛠 Уменьшен размер frontend-образа (noVNC больше не качается)
|
||
|
||
### 0.2.0
|
||
- 🔒 Удалён закоммиченный `backend/.env` с реальными секретами
|
||
- 🔒 Добавлена проверка владельца во всех рутерах `instances.py`
|
||
- 🔒 CORS теперь читается из `ALLOW_ORIGINS` (по умолчанию только localhost)
|
||
- 🔒 Backend-порт 8000 закрыт снаружи по умолчанию
|
||
- 🔒 Postgres-пароль обязателен через `POSTGRES_PASSWORD` (нет дефолта `panel:panel`)
|
||
- 🔒 Добавлены security-заголовки и CSP в `nginx.conf`
|
||
- 🛠 Заменён `passlib` на прямой `bcrypt` (passlib несовместим с bcrypt 4.x)
|
||
- 🛠 Pydantic v2: `SettingsConfigDict` вместо устаревшего `class Config`
|
||
- 🛠 Удалены дубли функций/эндпоинтов в `proxmox_client.py` и `instances.py`
|
||
- 🛠 Backend запускается от non-root пользователя
|
||
- 🛠 Multi-stage Dockerfile для backend (меньше размер образа)
|
||
- 🛠 Добавлены healthcheck'и у всех сервисов в docker-compose
|
||
- 🛠 Структурированное логирование через `logging`
|