docs: release notes and version bump for v1.15.0
Some checks failed
Deploy to Production / Trigger production update (push) Failing after 10s
Some checks failed
Deploy to Production / Trigger production update (push) Failing after 10s
This commit is contained in:
39
CHANGELOG.md
39
CHANGELOG.md
@@ -4,6 +4,45 @@ All notable changes to PVEmanager will be documented in this file.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [v1.15.0] - 2026-08-13
|
||||||
|
|
||||||
|
### 🚀 One-Command Bootstrap
|
||||||
|
|
||||||
|
- **`bootstrap.sh`** — installs the panel with a single command on either a plain Debian/Ubuntu host or directly on a Proxmox VE host. On a PVE host it provisions a Debian 12 LXC, installs the panel inside it via the existing `deploy.sh`, creates a local `root@pam` API token and registers that host as the panel's first node — no Proxmox password is ever transmitted
|
||||||
|
- Tolerates `apt-get update` failures from an unsubscribed PVE host's enterprise repo instead of aborting the whole bootstrap before `git`/`curl` are installed
|
||||||
|
- Registers the host at the correct `/proxmox/api/servers` path (the previous `/api/servers` 404'd, since the Proxmox router is mounted under `/proxmox`)
|
||||||
|
- Removed the insecure `pvemanager_secure_password` fallback for `POSTGRES_PASSWORD` in `compose.yml` — every deploy path already generates a real `.env` before the stack starts
|
||||||
|
|
||||||
|
### 💿 Images & Instances
|
||||||
|
|
||||||
|
- **ISO eject/mount rework** — the Images page now shows real ISO files already present on node storage (including ones that predate the node joining the panel); "Detach" is renamed **Eject**, the current image is shown inside the select, and a new **"boot from disk"** / **"boot from this ISO"** checkbox controls boot order on eject/mount
|
||||||
|
- Applying a new boot order reboots the guest via a **hybrid restart** — graceful ACPI shutdown with a forceStop fallback, then start — avoiding the guest-ping timeout seen on a freshly installed OS with no QEMU Guest Agent yet
|
||||||
|
|
||||||
|
### 🔒 RBAC & Access
|
||||||
|
|
||||||
|
- **`/profile` split from `/settings`** — account settings (profile, password, 2FA, SSH keys) moved to their own permission-free `/profile` page reached from the user menu and Ctrl+K, so revoking `setting:view` to keep a user out of panel settings no longer locks them out of their own account. `/settings` keeps the panel-wide tabs behind `setting:view`, with saving behind `setting:update`, security behind `setting:manage`, and SMTP/Telegram behind admin-only
|
||||||
|
- **Routes are now guarded by permission**, not just hidden from the sidebar — `/users`, `/logs` and `/settings` (and their tabs) previously rendered for anyone who typed the URL and let the backend answer with 403s; denied users are now redirected to the first page they can open
|
||||||
|
- Migration 42 drops `setting:view` from roles that don't also hold `setting:update`/`setting:manage`, since those grants only existed to reach the old combined settings page
|
||||||
|
|
||||||
|
### 👤 Ownership & Quotas
|
||||||
|
|
||||||
|
- **Owner assignment fixed at creation time** — newly created VMs/LXCs were silently ending up with `owner_id = NULL` because the sync job that registers a still-cloning VM beats the deploy flow to the database row; owner is now set on that update path too. A VM created by an admin on behalf of a user now also injects the **user's** SSH key instead of the admin's
|
||||||
|
- **Backfill migration** for instances created before the fix above, recovered from `deploy_tasks` and `audit_logs` and applied only when every piece of evidence agrees on the same existing user; ambiguous instances are left ownerless for `assign_instances_owner.py` to resolve by hand
|
||||||
|
- **Create Instance is disabled once a quota has no headroom left**, instead of only refusing inside the wizard — the button shows a tooltip naming which limits are full (skipped for admins, whose own quota doesn't apply to instances they create for someone else)
|
||||||
|
- The pre-wizard quota block is now distinct from the in-wizard one: no headroom at all keeps the wizard from opening; headroom that a chosen configuration would exceed opens the wizard but disables Next/Deploy with the offending metric named
|
||||||
|
|
||||||
|
### 🐛 Bug Fixes
|
||||||
|
|
||||||
|
- **Production deployments were bypassing TLS** — `compose.prod.yml`'s `ports: []` didn't actually drop the published `8000`/`3001` ports (Compose concatenates list-valued fields across `-f` files instead of overriding), so an SSL deployment kept answering unencrypted on both ports alongside HTTPS. Fixed with the `!reset` tag
|
||||||
|
- **SSL deployments reported "Failed to obtain SSL certificate" after successfully issuing one** — the success check couldn't read certbot's root-owned, mode-0700 output directory as a non-root user; the check now verifies the certificate from inside the container and falls back to HTTP only if nginx actually fails to come up with the new config
|
||||||
|
- **The frontend bundle's cold load could render a blank page** — the general request-rate limit (`10r/s`) applied to static assets too and started rejecting the SPA's ~86 preloaded chunks with 503s; and once that was fixed, `limit_conn addr 10` capped the whole page to 10 concurrent HTTP/2 streams (a browser multiplexes a page's entire load over one connection), producing the same blank page from a different limiter. Static assets now have their own rate-limit zone, and both `limit_conn` caps are raised
|
||||||
|
- **nginx workers were unable to open enough file descriptors** to match `worker_connections 2048` (Docker's default `RLIMIT_NOFILE` of 1024 quietly halved the real ceiling); raised to 8192
|
||||||
|
- Dropped `listen 443 ssl http2` (deprecated since nginx 1.25.1) and `ssl_stapling` (no OCSP responder in current Let's Encrypt certs) — both warned on nginx's periodic reload
|
||||||
|
- **Node uptime showed the wrong value on multi-node clusters** — the server card took `Math.max` over every cluster node's uptime instead of the current node's own, so rebooting one node could still show another node's higher uptime
|
||||||
|
- **The terminated-sessions toast never translated** — the message was assembled server-side in Python and returned verbatim, so the Russian UI showed "Terminated 0 sessions"; the count is now returned separately and the phrase is composed client-side (Russian needs four plural forms against English's two)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [v1.14.0] - 2026-07-24
|
## [v1.14.0] - 2026-07-24
|
||||||
|
|
||||||
### 🐛 Bug Fixes
|
### 🐛 Bug Fixes
|
||||||
|
|||||||
@@ -4,6 +4,45 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [v1.15.0] - 2026-08-13
|
||||||
|
|
||||||
|
### 🚀 Установка одной командой
|
||||||
|
|
||||||
|
- **`bootstrap.sh`** — устанавливает панель одной командой как на обычном хосте Debian/Ubuntu, так и напрямую на хосте Proxmox VE. На хосте PVE скрипт создаёт LXC на Debian 12, устанавливает панель внутри через существующий `deploy.sh`, создаёт локальный API-токен `root@pam` и регистрирует этот хост как первую ноду панели — пароль от Proxmox никуда не передаётся
|
||||||
|
- Скрипт переживает сбой `apt-get update` из-за недоступного enterprise-репозитория на неподписанном хосте PVE вместо того, чтобы прерывать весь bootstrap ещё до установки `git`/`curl`
|
||||||
|
- Регистрация хоста теперь идёт по правильному пути `/proxmox/api/servers` (раньше использовался `/api/servers`, отвечавший 404, — роутер Proxmox подключён под префиксом `/proxmox`)
|
||||||
|
- Убран небезопасный дефолт `pvemanager_secure_password` для `POSTGRES_PASSWORD` в `compose.yml` — на любом пути установки `.env` с реальным паролем уже создаётся до запуска стека
|
||||||
|
|
||||||
|
### 💿 Образы и инстансы
|
||||||
|
|
||||||
|
- **Переработка извлечения/монтирования ISO** — страница «Образы» теперь показывает реальные ISO-файлы, уже лежащие в хранилище ноды (включая те, что появились там до подключения ноды к панели); «Отсоединить» переименовано в **«Извлечь»**, текущий смонтированный образ отображается прямо в списке выбора, а новый чекбокс **«загрузка с диска»** / **«загрузка с этого ISO»** управляет порядком загрузки при извлечении/монтировании
|
||||||
|
- Применение нового порядка загрузки перезагружает гостевую систему через **гибридный рестарт** — штатное ACPI-выключение с откатом на принудительную остановку, затем запуск — что убирает таймаут ping гостя на свежеустановленной ОС, где ещё нет QEMU Guest Agent
|
||||||
|
|
||||||
|
### 🔒 RBAC и доступ
|
||||||
|
|
||||||
|
- **`/profile` отделён от `/settings`** — настройки аккаунта (профиль, пароль, 2FA, SSH-ключи) переехали на собственную страницу `/profile`, не требующую никакого разрешения, и открываются из меню пользователя и Ctrl+K. Теперь отзыв `setting:view`, чтобы не пускать пользователя в настройки панели, больше не блокирует доступ к его собственному аккаунту. `/settings` по-прежнему скрывает общепанельные вкладки за `setting:view`, сохранение — за `setting:update`, безопасность — за `setting:manage`, а SMTP/Telegram — только для админов
|
||||||
|
- **Маршруты теперь защищены по правам**, а не просто скрыты из сайдбара — раньше `/users`, `/logs` и `/settings` (и их вкладки) открывались по прямому переходу на URL кому угодно, а бэкенд лишь отвечал 403 на конкретные запросы; теперь пользователь без доступа перенаправляется на первую доступную ему страницу
|
||||||
|
- Миграция 42 снимает `setting:view` с ролей, у которых нет также `setting:update`/`setting:manage`, — этот доступ раньше выдавался только ради общей страницы настроек, включавшей профиль
|
||||||
|
|
||||||
|
### 👤 Владение инстансами и квоты
|
||||||
|
|
||||||
|
- **Исправлено назначение владельца при создании** — новые VM/LXC оставались с `owner_id = NULL`, потому что задача синхронизации, регистрирующая ещё клонирующуюся VM, опережала флоу деплоя и первой создавала запись в БД; теперь владелец проставляется и на этом пути обновления записи. VM, созданная админом от имени пользователя, теперь получает SSH-ключ именно **этого пользователя**, а не админа
|
||||||
|
- **Миграция для бэкфилла** владельца у инстансов, созданных до исправления выше: владелец восстанавливается из `deploy_tasks` и `audit_logs` и проставляется только тогда, когда все доступные данные указывают на одного и того же существующего пользователя; неоднозначные случаи остаются без владельца — для них нужен ручной запуск `assign_instances_owner.py`
|
||||||
|
- **Кнопка «Создать инстанс» отключается**, когда по какой-то квоте совсем не осталось свободного места, а не только отказывает внутри мастера — подсказка называет, какие именно лимиты исчерпаны (проверка пропускается для админов, чья личная квота не имеет отношения к инстансам, создаваемым для других)
|
||||||
|
- Блокировка перед открытием мастера теперь отделена от блокировки внутри него: полностью исчерпанная квота не даёт открыть мастер вовсе; квота, которую превысит именно выбранная конфигурация, открывает мастер, но блокирует «Далее»/«Развернуть» с указанием превышенного показателя
|
||||||
|
|
||||||
|
### 🐛 Исправления
|
||||||
|
|
||||||
|
- **Продакшн-деплой не отключал открытые порты** — `ports: []` в `compose.prod.yml` на деле ничего не убирал (Compose при слиянии нескольких `-f` файлов не заменяет списковые поля, а объединяет их), поэтому SSL-деплой продолжал отвечать без шифрования на портах `8000`/`3001` параллельно с HTTPS. Исправлено через тег `!reset`
|
||||||
|
- **SSL-деплой сообщал о неудаче даже после успешного выпуска сертификата** — проверка успеха не могла прочитать директорию certbot, принадлежащую root и имеющую права 0700, если деплой запускался не от root; теперь сертификат проверяется изнутри контейнера, а откат на HTTP выполняется только если nginx реально не поднялся с новым конфигом
|
||||||
|
- **Первая загрузка фронтенда могла показать пустую страницу** — общий лимит частоты запросов (`10r/s`) применялся и к статике, отклоняя часть из ~86 подгружаемых чанков SPA с 503; после исправления этого проявился второй лимитер — `limit_conn addr 10` ограничивал всю страницу 10 одновременными HTTP/2-потоками (браузер мультиплексирует всю загрузку страницы через одно соединение), давая тот же эффект пустой страницы. Теперь у статики отдельная зона лимита частоты, а оба лимита `limit_conn` подняты
|
||||||
|
- **Воркеры nginx не могли открыть достаточно файловых дескрипторов** под `worker_connections 2048` — дефолтный `RLIMIT_NOFILE` Docker в 1024 незаметно урезал реальный потолок вдвое; поднят до 8192
|
||||||
|
- Убраны `listen 443 ssl http2` (устарела с nginx 1.25.1) и `ssl_stapling` (у текущих сертификатов Let's Encrypt нет OCSP-респондера) — обе директивы выдавали предупреждения при периодическом reload nginx
|
||||||
|
- **Аптайм ноды показывался неверно в мультинодовых кластерах** — карточка сервера брала `Math.max` по аптайму всех нод кластера вместо аптайма именно текущей, поэтому перезагрузка одной ноды могла по-прежнему показывать более высокий аптайм другой
|
||||||
|
- **Тост о завершении сессий никогда не переводился** — сообщение собиралось на бэкенде на Python и возвращалось как есть, поэтому в русском интерфейсе показывалось "Terminated 0 sessions"; теперь количество возвращается отдельным полем, а фраза собирается на клиенте (для русского нужно четыре формы множественного числа против двух в английском)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [v1.14.0] - 2026-07-24
|
## [v1.14.0] - 2026-07-24
|
||||||
|
|
||||||
### 🐛 Исправления
|
### 🐛 Исправления
|
||||||
|
|||||||
20
README.md
20
README.md
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
**Modern web panel for managing Proxmox servers, virtual machines and LXC containers**
|
**Modern web panel for managing Proxmox servers, virtual machines and LXC containers**
|
||||||
|
|
||||||
[](CHANGELOG.md)
|
[](CHANGELOG.md)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](compose.yml)
|
[](compose.yml)
|
||||||
[](backend/)
|
[](backend/)
|
||||||
@@ -28,6 +28,7 @@ PVEmanager is a self-hosted web panel that provides a unified interface for mana
|
|||||||
- **Snapshot management** — create, rollback, delete snapshots with an async queue system
|
- **Snapshot management** — create, rollback, delete snapshots with an async queue system
|
||||||
- **OS templates** — deploy VMs from templates; cross-node replication handled automatically
|
- **OS templates** — deploy VMs from templates; cross-node replication handled automatically
|
||||||
- **Cloud image catalog** — browse, download, and convert OS images from cloud repositories (default Proxmox mirrors and custom sources); auto-convert to VM templates with architecture-aware filtering
|
- **Cloud image catalog** — browse, download, and convert OS images from cloud repositories (default Proxmox mirrors and custom sources); auto-convert to VM templates with architecture-aware filtering
|
||||||
|
- **ISO eject/mount** — attach or eject an ISO on a running VM, with a boot-order switch (boot from disk or from the ISO) applied via a graceful ACPI-then-forceStop hybrid reboot
|
||||||
- **CT template deployment** — create LXC containers directly from Proxmox CT template files (`.tar.zst`, `.tar.gz`) with full IPAM and SSH key integration
|
- **CT template deployment** — create LXC containers directly from Proxmox CT template files (`.tar.zst`, `.tar.gz`) with full IPAM and SSH key integration
|
||||||
- **Unified Create Instance Wizard** — multi-step wizard supporting both QEMU VM templates and LXC CT templates in a single flow
|
- **Unified Create Instance Wizard** — multi-step wizard supporting both QEMU VM templates and LXC CT templates in a single flow
|
||||||
- **SDN support** — manage Software-Defined Networking zones, VNets, and subnets; edit zones and VNets; auto-create IPAM networks for subnets
|
- **SDN support** — manage Software-Defined Networking zones, VNets, and subnets; edit zones and VNets; auto-create IPAM networks for subnets
|
||||||
@@ -47,10 +48,11 @@ PVEmanager is a self-hosted web panel that provides a unified interface for mana
|
|||||||
- **xterm.js terminal** — full interactive shell directly in the browser for LXC containers
|
- **xterm.js terminal** — full interactive shell directly in the browser for LXC containers
|
||||||
- **Remote commands** — execute bash commands via QEMU Guest Agent
|
- **Remote commands** — execute bash commands via QEMU Guest Agent
|
||||||
- **SSH Keys Management** — personal SSH key library per user; keys selectable when deploying VMs/LXC; admin can manage keys for any user
|
- **SSH Keys Management** — personal SSH key library per user; keys selectable when deploying VMs/LXC; admin can manage keys for any user
|
||||||
- **RBAC v2** — granular role-based access control with per-resource permissions
|
- **RBAC v2** — granular role-based access control with per-resource permissions; routes are guarded server- and client-side, not just hidden from the sidebar
|
||||||
|
- **Permission-free profile page** — account settings (profile, password, 2FA, SSH keys) live at `/profile` and never require a panel-settings permission, so restricting `setting:view` can't lock a user out of their own account
|
||||||
- **Server assignment** — directly assign specific Proxmox servers to users with workspace-conflict validation
|
- **Server assignment** — directly assign specific Proxmox servers to users with workspace-conflict validation
|
||||||
- **VM/LXC ownership** — assign an owner user to any VM or LXC container; non-privileged users see only their own instances everywhere, including the dashboard and per-node resource views
|
- **VM/LXC ownership** — assign an owner user to any VM or LXC container; non-privileged users see only their own instances everywhere, including the dashboard and per-node resource views; owner is set automatically on create, with a migration to backfill pre-existing instances
|
||||||
- **Per-user quotas** — limit each user's number of instances and total vCPU, RAM and disk; enforced at deploy time (HTTP 429), with admin management and self-service usage view
|
- **Per-user quotas** — limit each user's number of instances and total vCPU, RAM and disk; enforced at deploy time (HTTP 429); the Create Instance entry point itself is disabled once a quota has no headroom left, naming which limit is full
|
||||||
- **Session management** — active session list, remote session revocation, login protection
|
- **Session management** — active session list, remote session revocation, login protection
|
||||||
- **Smart login redirect** — users are automatically routed to the first page they have access to
|
- **Smart login redirect** — users are automatically routed to the first page they have access to
|
||||||
|
|
||||||
@@ -91,6 +93,16 @@ docker compose up -d
|
|||||||
|
|
||||||
> **Important:** Change the default password immediately after first login.
|
> **Important:** Change the default password immediately after first login.
|
||||||
|
|
||||||
|
### One-command bootstrap
|
||||||
|
|
||||||
|
`bootstrap.sh` installs the panel with a single command, on either a plain Debian/Ubuntu host or directly on a Proxmox VE host — on a PVE host it provisions a Debian 12 LXC, installs the panel inside it, and registers that host as the panel's first node automatically (no Proxmox password is ever transmitted):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.tzim.uz/markmorado/pvemanager.git
|
||||||
|
cd pvemanager
|
||||||
|
bash bootstrap.sh
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|||||||
22
README.ru.md
22
README.ru.md
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
**Современная веб-панель для управления серверами Proxmox, виртуальными машинами и контейнерами LXC**
|
**Современная веб-панель для управления серверами Proxmox, виртуальными машинами и контейнерами LXC**
|
||||||
|
|
||||||
[](CHANGELOG.md)
|
[](CHANGELOG.md)
|
||||||
[](LICENSE)
|
[](LICENSE)
|
||||||
[](compose.yml)
|
[](compose.yml)
|
||||||
[](backend/)
|
[](backend/)
|
||||||
@@ -28,6 +28,7 @@ PVEmanager — это самостоятельно размещаемая веб
|
|||||||
- **Управление снимками** — создавайте, откатывайте, удаляйте снимки с помощью асинхронной системы очередей
|
- **Управление снимками** — создавайте, откатывайте, удаляйте снимки с помощью асинхронной системы очередей
|
||||||
- **Шаблоны ОС** — развертывайте ВМ из шаблонов; автоматическая репликация между узлами
|
- **Шаблоны ОС** — развертывайте ВМ из шаблонов; автоматическая репликация между узлами
|
||||||
- **Каталог облачных образов** — просмотр и скачивание образов ОС из облачных репозиториев (стандартные зеркала Proxmox и кастомные источники); автоматическая конвертация в шаблоны VM с фильтрацией по архитектуре
|
- **Каталог облачных образов** — просмотр и скачивание образов ОС из облачных репозиториев (стандартные зеркала Proxmox и кастомные источники); автоматическая конвертация в шаблоны VM с фильтрацией по архитектуре
|
||||||
|
- **Извлечение/монтирование ISO** — подключайте или извлекайте ISO на работающей ВМ, с переключателем порядка загрузки (с диска или с ISO), применяемым через гибридную перезагрузку — штатное ACPI-выключение с откатом на принудительную остановку
|
||||||
- **Развёртывание CT-шаблонов** — создавайте LXC-контейнеры напрямую из CT-файлов Proxmox (`.tar.zst`, `.tar.gz`) с интеграцией IPAM и SSH-ключей
|
- **Развёртывание CT-шаблонов** — создавайте LXC-контейнеры напрямую из CT-файлов Proxmox (`.tar.zst`, `.tar.gz`) с интеграцией IPAM и SSH-ключей
|
||||||
- **Единый мастер создания инстансов** — многошаговый мастер для создания как VM-шаблонов QEMU, так и LXC CT-шаблонов
|
- **Единый мастер создания инстансов** — многошаговый мастер для создания как VM-шаблонов QEMU, так и LXC CT-шаблонов
|
||||||
- **Поддержка SDN** — управляйте зонами Software-Defined Networking, VNet и подсетями; редактируйте зоны и VNet; автоматическое создание сетей IPAM для подсетей
|
- **Поддержка SDN** — управляйте зонами Software-Defined Networking, VNet и подсетями; редактируйте зоны и VNet; автоматическое создание сетей IPAM для подсетей
|
||||||
@@ -45,10 +46,13 @@ PVEmanager — это самостоятельно размещаемая веб
|
|||||||
### Доступ и консоль
|
### Доступ и консоль
|
||||||
- **Консоль VNC** — консоль в браузере через noVNC, не требуется клиентское ПО
|
- **Консоль VNC** — консоль в браузере через noVNC, не требуется клиентское ПО
|
||||||
- **Терминал xterm.js** — полностью интерактивный shell непосредственно в браузере для контейнеров LXC
|
- **Терминал xterm.js** — полностью интерактивный shell непосредственно в браузере для контейнеров LXC
|
||||||
- **Удаленные команды** — выполняйте команды bash через QEMU Guest Agent- **Управление SSH-ключами** — личная библиотека SSH-ключей для каждого пользователя; ключи можно выбирать при развёртывании VM/LXC; админ может управлять ключами любого пользователя- **RBAC v2** — детальный контроль доступа на основе ролей с разрешениями для каждого ресурса
|
- **Удаленные команды** — выполняйте команды bash через QEMU Guest Agent
|
||||||
|
- **Управление SSH-ключами** — личная библиотека SSH-ключей для каждого пользователя; ключи можно выбирать при развёртывании VM/LXC; админ может управлять ключами любого пользователя
|
||||||
|
- **RBAC v2** — детальный контроль доступа на основе ролей с разрешениями для каждого ресурса; маршруты защищены и на бэкенде, и на фронтенде, а не просто скрыты из сайдбара
|
||||||
|
- **Страница профиля без разрешений** — настройки аккаунта (профиль, пароль, 2FA, SSH-ключи) находятся на странице `/profile` и не требуют никакого разрешения на настройки панели, так что ограничение `setting:view` не может заблокировать пользователю доступ к собственному аккаунту
|
||||||
- **Назначение серверов** — напрямую назначайте конкретные серверы Proxmox пользователям с проверкой конфликтов рабочих областей
|
- **Назначение серверов** — напрямую назначайте конкретные серверы Proxmox пользователям с проверкой конфликтов рабочих областей
|
||||||
- **Владелец ВМ/LXC** — назначайте пользователя-владельца любой ВМ или контейнеру LXC; непривилегированные пользователи везде видят только свои инстансы, включая дашборд и ресурсы по ноде
|
- **Владелец ВМ/LXC** — назначайте пользователя-владельца любой ВМ или контейнеру LXC; непривилегированные пользователи везде видят только свои инстансы, включая дашборд и ресурсы по ноде; владелец теперь проставляется автоматически при создании, а для уже существующих инстансов есть миграция для бэкфилла
|
||||||
- **Квоты на пользователя** — ограничение количества инстансов и суммарных vCPU, RAM и диска для каждого пользователя; проверка при развёртывании (HTTP 429), управление администратором и просмотр собственного использования
|
- **Квоты на пользователя** — ограничение количества инстансов и суммарных vCPU, RAM и диска для каждого пользователя; проверка при развёртывании (HTTP 429); сама кнопка «Создать инстанс» отключается, когда квота исчерпана, с указанием какого именно лимита не хватает
|
||||||
- **Управление сессиями** — список активных сессий, отзыв удаленных сессий, защита входа
|
- **Управление сессиями** — список активных сессий, отзыв удаленных сессий, защита входа
|
||||||
- **Умное перенаправление входа** — пользователи автоматически маршрутизируются на первую страницу, к которой у них есть доступ
|
- **Умное перенаправление входа** — пользователи автоматически маршрутизируются на первую страницу, к которой у них есть доступ
|
||||||
|
|
||||||
@@ -89,6 +93,16 @@ docker compose up -d
|
|||||||
|
|
||||||
> **Важно:** Измените пароль по умолчанию сразу после первого входа.
|
> **Важно:** Измените пароль по умолчанию сразу после первого входа.
|
||||||
|
|
||||||
|
### Установка одной командой
|
||||||
|
|
||||||
|
`bootstrap.sh` устанавливает панель одной командой — как на обычном хосте Debian/Ubuntu, так и напрямую на хосте Proxmox VE: на хосте PVE скрипт сам создаёт LXC на Debian 12, устанавливает панель внутри и регистрирует этот хост как первую ноду панели (пароль от Proxmox никуда не передаётся):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.tzim.uz/markmorado/pvemanager.git
|
||||||
|
cd pvemanager
|
||||||
|
bash bootstrap.sh
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Требования
|
## Требования
|
||||||
|
|||||||
39
WIKI.md
39
WIKI.md
@@ -102,6 +102,21 @@ docker compose up -d
|
|||||||
# Specify domain and email for Let's Encrypt
|
# Specify domain and email for Let's Encrypt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 4. One-command bootstrap (`bootstrap.sh`)
|
||||||
|
|
||||||
|
A single script that installs the panel on either a plain Debian/Ubuntu host or directly on a Proxmox VE host — it detects which by checking for `/etc/pve`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.tzim.uz/markmorado/pvemanager.git
|
||||||
|
cd pvemanager
|
||||||
|
bash bootstrap.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Plain Debian/Ubuntu host** — installs Docker and `git`/`curl`/`openssl`/`jq` if missing, clones the repo into `PVEMANAGER_DIR` (default `/opt/pvemanager`) and hands off to `deploy.sh --standalone`.
|
||||||
|
- **Proxmox VE host** — creates a Debian 12 LXC (DHCP on `vmbr0`, `nesting=1,keyctl=1` for Docker inside), installs the panel inside it via the same flow, then — once the panel answers `GET /health` — creates a `root@pam!pvemanager` API token locally on the PVE host (`pvesh create ... --privsep 0`) and registers that host as the panel's first node. **No Proxmox password is ever transmitted** to or through the panel.
|
||||||
|
- Configuration is via environment variables (`PVEMANAGER_REPO`, `PVEMANAGER_VERSION`, `PVEMANAGER_DIR`, and `PVEMANAGER_LXC_*` for the container's vmid/storage/bridge/resources) — see the header of `bootstrap.sh` for the full list and defaults.
|
||||||
|
- Tolerates `apt-get update` failures from an unsubscribed PVE host's enterprise repo instead of aborting before `git`/`curl` are installed.
|
||||||
|
|
||||||
### Environment Variables
|
### Environment Variables
|
||||||
|
|
||||||
#### Main (`.env`)
|
#### Main (`.env`)
|
||||||
@@ -702,6 +717,15 @@ The **Images** module allows you to browse, download, and manage OS images from
|
|||||||
|
|
||||||
The create-instance wizard offers a **blank VM** kind for ISO-based installs: it provisions an empty disk with the chosen ISO mounted on `ide2` and set first in the boot order, so the VM boots straight into the installer over the built-in noVNC console. Selecting a Windows guest automatically presets OVMF firmware, a SATA disk and an e1000 NIC, since the installer has no virtio drivers loaded yet.
|
The create-instance wizard offers a **blank VM** kind for ISO-based installs: it provisions an empty disk with the chosen ISO mounted on `ide2` and set first in the boot order, so the VM boots straight into the installer over the built-in noVNC console. Selecting a Windows guest automatically presets OVMF firmware, a SATA disk and an e1000 NIC, since the installer has no virtio drivers loaded yet.
|
||||||
|
|
||||||
|
### Ejecting and Mounting an ISO
|
||||||
|
|
||||||
|
From a VM's detail page, the ISO dialog shows every ISO already on the node's storage — including ones that predate the node joining the panel — and the image currently mounted, if any:
|
||||||
|
|
||||||
|
- **Mount** — pick an ISO from storage; optionally check **"boot from this ISO"** to put the CD-ROM drive first in the boot order.
|
||||||
|
- **Eject** (renamed from "Detach") — remove the mounted ISO; optionally check **"boot from disk"** to put the primary disk first in the boot order.
|
||||||
|
|
||||||
|
Either action that changes boot order applies it via a **hybrid reboot**: a graceful ACPI shutdown with a `forceStop` fallback, then start. This avoids the guest-ping timeout that a plain restart hits on a freshly installed OS with no QEMU Guest Agent running yet.
|
||||||
|
|
||||||
### Custom Mirrors (Admin Only)
|
### Custom Mirrors (Admin Only)
|
||||||
|
|
||||||
Administrators can configure custom image repositories:
|
Administrators can configure custom image repositories:
|
||||||
@@ -2226,7 +2250,9 @@ Any VM or LXC container can have an **owner** — a regular user responsible for
|
|||||||
|
|
||||||
Ownership is enforced everywhere a non-privileged user sees instances, not just the instance list. The live-resource endpoints — `/api/resources/all` (dashboard) and `/api/{server_id}/resources` (node/server page) — filter VMs/LXC by owner (matching each `vmid` against the `vm_instances` cache), so a user with only `proxmox.view` cannot see other owners' instances through the node page. **Admins** and roles with **`vm:manage`** are exempt and see everything.
|
Ownership is enforced everywhere a non-privileged user sees instances, not just the instance list. The live-resource endpoints — `/api/resources/all` (dashboard) and `/api/{server_id}/resources` (node/server page) — filter VMs/LXC by owner (matching each `vmid` against the `vm_instances` cache), so a user with only `proxmox.view` cannot see other owners' instances through the node page. **Admins** and roles with **`vm:manage`** are exempt and see everything.
|
||||||
|
|
||||||
Instances synced from Proxmox before ownership existed have `owner_id = NULL`. To bulk-assign an owner to them, run the helper script shipped in the backend image:
|
**Owner is set automatically on create** (`vm_create`/`ct_create`), including when an admin creates an instance on behalf of another user — the deploy flow injects that owner's SSH key (merged with any pasted/library keys) rather than the creator's.
|
||||||
|
|
||||||
|
Instances synced from Proxmox before ownership existed, or created before the fix above, have `owner_id = NULL`. A one-time migration backfills these automatically from `deploy_tasks` and `audit_logs` (`vm_create`/`ct_create`/`lxc_create` entries), but only when every applicable piece of evidence names the same existing user — ambiguous cases (e.g. a reused VMID) are deliberately left ownerless. To assign an owner to whatever is left, run the helper script shipped in the backend image:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose exec app python assign_instances_owner.py
|
docker compose exec app python assign_instances_owner.py
|
||||||
@@ -2260,13 +2286,22 @@ Per-user resource quotas cap how much a user can provision. Four metrics are lim
|
|||||||
- **Enforcement** — deploying a VM/LXC that would push any metric over its limit is rejected with **HTTP 429** and a bilingual message (`Превышена квота … / Quota exceeded …`) showing the projected value vs. the limit.
|
- **Enforcement** — deploying a VM/LXC that would push any metric over its limit is rejected with **HTTP 429** and a bilingual message (`Превышена квота … / Quota exceeded …`) showing the projected value vs. the limit.
|
||||||
- **Usage source** — current usage is computed from the `vm_instances` cache (`owner_id`), where RAM is stored in MB and disk in GB (no conversion needed).
|
- **Usage source** — current usage is computed from the `vm_instances` cache (`owner_id`), where RAM is stored in MB and disk in GB (no conversion needed).
|
||||||
|
|
||||||
|
### Two levels of client-side blocking
|
||||||
|
|
||||||
|
The backend's 429 is the only real enforcement, but the UI now warns before a user reaches it, using the same `exhaustedMetrics()` logic (`features/instances/quota.ts`) in both places so the two can't disagree:
|
||||||
|
|
||||||
|
- **No headroom at all** (used ≥ limit on any metric) — the **Create Instance** entry point itself is disabled, with a tooltip naming exactly which limits are full. No configuration would fit, so the wizard does not open.
|
||||||
|
- **Headroom left, but the chosen configuration would exceed it** — the wizard opens normally; from the configuration step onward, the metric that would be exceeded is named and **Next**/**Deploy** are disabled until the request is reduced.
|
||||||
|
|
||||||
|
Neither block applies to **admins** — their own quota says nothing about an instance they're creating on behalf of someone else, and the figures shown to them are informational only.
|
||||||
|
|
||||||
### Managing quotas (Admin)
|
### Managing quotas (Admin)
|
||||||
|
|
||||||
**Users** page → quota dialog. Live usage bars show current consumption against each limit. Leave a field empty for *unlimited*. Requires the `quota:manage` permission (`quota:view` to read).
|
**Users** page → quota dialog. Live usage bars show current consumption against each limit. Leave a field empty for *unlimited*. Requires the `quota:manage` permission (`quota:view` to read).
|
||||||
|
|
||||||
### Self-service
|
### Self-service
|
||||||
|
|
||||||
Each user sees their own limits and current usage on the **Settings** page. The **Create Instance** wizard shows the remaining quota as a hint on the configuration step.
|
Each user sees their own limits and current usage on the **Profile** page. The **Create Instance** wizard shows the remaining quota as a hint on the configuration step.
|
||||||
|
|
||||||
### REST API
|
### REST API
|
||||||
|
|
||||||
|
|||||||
39
WIKI.ru.md
39
WIKI.ru.md
@@ -101,6 +101,21 @@ docker compose up -d
|
|||||||
# Указать домен и email для Let's Encrypt
|
# Указать домен и email для Let's Encrypt
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 4. Установка одной командой (`bootstrap.sh`)
|
||||||
|
|
||||||
|
Один скрипт, который устанавливает панель как на обычном хосте Debian/Ubuntu, так и напрямую на хосте Proxmox VE — среда определяется по наличию `/etc/pve`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://git.tzim.uz/markmorado/pvemanager.git
|
||||||
|
cd pvemanager
|
||||||
|
bash bootstrap.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Обычный хост Debian/Ubuntu** — при необходимости ставит Docker и `git`/`curl`/`openssl`/`jq`, клонирует репозиторий в `PVEMANAGER_DIR` (по умолчанию `/opt/pvemanager`) и передаёт управление `deploy.sh --standalone`.
|
||||||
|
- **Хост Proxmox VE** — создаёт LXC на Debian 12 (DHCP на `vmbr0`, `nesting=1,keyctl=1` для Docker внутри), устанавливает панель внутри по тому же сценарию, а после того как панель ответит на `GET /health`, создаёт на самом хосте PVE локальный API-токен `root@pam!pvemanager` (`pvesh create ... --privsep 0`) и регистрирует этот хост как первую ноду панели. **Пароль от Proxmox никуда не передаётся.**
|
||||||
|
- Настраивается через переменные окружения (`PVEMANAGER_REPO`, `PVEMANAGER_VERSION`, `PVEMANAGER_DIR`, а также `PVEMANAGER_LXC_*` — vmid, хранилище, мост и ресурсы контейнера) — полный список и значения по умолчанию см. в заголовке `bootstrap.sh`.
|
||||||
|
- Скрипт переживает сбой `apt-get update` из-за недоступного enterprise-репозитория на неподписанном хосте PVE, не прерывая bootstrap до установки `git`/`curl`.
|
||||||
|
|
||||||
### Переменные окружения
|
### Переменные окружения
|
||||||
|
|
||||||
#### Основные (`.env`)
|
#### Основные (`.env`)
|
||||||
@@ -701,6 +716,15 @@ RAM: 512 МБ – 128 ГБ
|
|||||||
|
|
||||||
Мастер создания инстанса предлагает тип **«пустая ВМ»** для установки с ISO: создаётся ВМ с пустым диском и смонтированным на `ide2` образом, который ставится первым в порядке загрузки, — гость сразу попадает в установщик через встроенную консоль noVNC. Выбор гостя Windows автоматически задаёт прошивку OVMF, SATA-диск и сетевую карту e1000, так как у установщика ещё нет драйверов virtio.
|
Мастер создания инстанса предлагает тип **«пустая ВМ»** для установки с ISO: создаётся ВМ с пустым диском и смонтированным на `ide2` образом, который ставится первым в порядке загрузки, — гость сразу попадает в установщик через встроенную консоль noVNC. Выбор гостя Windows автоматически задаёт прошивку OVMF, SATA-диск и сетевую карту e1000, так как у установщика ещё нет драйверов virtio.
|
||||||
|
|
||||||
|
### Извлечение и монтирование ISO
|
||||||
|
|
||||||
|
На странице ВМ диалог ISO показывает все образы, уже лежащие в хранилище ноды — включая те, что появились там до подключения ноды к панели, — и текущий смонтированный образ, если он есть:
|
||||||
|
|
||||||
|
- **Монтировать** — выберите ISO из хранилища; опционально отметьте **«загрузка с этого ISO»**, чтобы поставить CD-ROM первым в порядке загрузки.
|
||||||
|
- **Извлечь** (переименовано из «Отсоединить») — снимает смонтированный ISO; опционально отметьте **«загрузка с диска»**, чтобы поставить основной диск первым в порядке загрузки.
|
||||||
|
|
||||||
|
Любое действие, меняющее порядок загрузки, применяется через **гибридную перезагрузку**: штатное ACPI-выключение с откатом на принудительную остановку, затем запуск. Это убирает таймаут ping гостя, с которым сталкивается обычный рестарт на свежеустановленной ОС, где ещё не запущен QEMU Guest Agent.
|
||||||
|
|
||||||
### Кастомные зеркала (только админ)
|
### Кастомные зеркала (только админ)
|
||||||
|
|
||||||
Администраторы могут настроить кастомные репозитории образов:
|
Администраторы могут настроить кастомные репозитории образов:
|
||||||
@@ -2139,7 +2163,9 @@ curl -H "Authorization: Bearer eyJ..." \
|
|||||||
|
|
||||||
Владение применяется везде, где непривилегированный пользователь видит инстансы, а не только в списке инстансов. Эндпоинты живых ресурсов — `/api/resources/all` (дашборд) и `/api/{server_id}/resources` (страница узла/сервера) — фильтруют ВМ/LXC по владельцу (сопоставляя каждый `vmid` с кэшем `vm_instances`), поэтому пользователь только с `proxmox.view` не может видеть инстансы других владельцев через страницу узла. **Админы** и роли с **`vm:manage`** освобождены от этого и видят всё.
|
Владение применяется везде, где непривилегированный пользователь видит инстансы, а не только в списке инстансов. Эндпоинты живых ресурсов — `/api/resources/all` (дашборд) и `/api/{server_id}/resources` (страница узла/сервера) — фильтруют ВМ/LXC по владельцу (сопоставляя каждый `vmid` с кэшем `vm_instances`), поэтому пользователь только с `proxmox.view` не может видеть инстансы других владельцев через страницу узла. **Админы** и роли с **`vm:manage`** освобождены от этого и видят всё.
|
||||||
|
|
||||||
Инстансы, синхронизированные из Proxmox до появления владения, имеют `owner_id = NULL`. Чтобы массово назначить им владельца, запустите вспомогательный скрипт из образа бэкенда:
|
**Владелец теперь проставляется автоматически при создании** (`vm_create`/`ct_create`), в том числе когда ВМ создаёт админ от имени другого пользователя — деплой инжектирует SSH-ключ именно этого владельца (объединённый с любыми вставленными вручную или взятыми из библиотеки ключами), а не ключ создавшего.
|
||||||
|
|
||||||
|
Инстансы, синхронизированные из Proxmox до появления владения, или созданные до исправления выше, имеют `owner_id = NULL`. Разовая миграция бэкфиллит их автоматически из `deploy_tasks` и `audit_logs` (записи `vm_create`/`ct_create`/`lxc_create`), но только когда все доступные данные указывают на одного и того же существующего пользователя — неоднозначные случаи (например, переиспользованный VMID) намеренно остаются без владельца. Чтобы назначить владельца тому, что осталось, запустите вспомогательный скрипт из образа бэкенда:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose exec app python assign_instances_owner.py
|
docker compose exec app python assign_instances_owner.py
|
||||||
@@ -2173,13 +2199,22 @@ docker compose exec app python assign_instances_owner.py
|
|||||||
- **Применение** — развёртывание VM/LXC, которое превысит любую метрику, отклоняется с **HTTP 429** и двуязычным сообщением (`Превышена квота … / Quota exceeded …`) с прогнозируемым значением и лимитом.
|
- **Применение** — развёртывание VM/LXC, которое превысит любую метрику, отклоняется с **HTTP 429** и двуязычным сообщением (`Превышена квота … / Quota exceeded …`) с прогнозируемым значением и лимитом.
|
||||||
- **Источник использования** — текущее использование вычисляется из кэша `vm_instances` (`owner_id`), где RAM хранится в МБ, а диск — в ГБ (без конвертации).
|
- **Источник использования** — текущее использование вычисляется из кэша `vm_instances` (`owner_id`), где RAM хранится в МБ, а диск — в ГБ (без конвертации).
|
||||||
|
|
||||||
|
### Два уровня блокировки на клиенте
|
||||||
|
|
||||||
|
Реально применяет ограничение только backend'ный HTTP 429, но интерфейс теперь предупреждает заранее, используя в обоих местах одну и ту же функцию `exhaustedMetrics()` (`features/instances/quota.ts`), чтобы они не могли разойтись:
|
||||||
|
|
||||||
|
- **Свободного места совсем не осталось** (использовано ≥ лимита хотя бы по одной метрике) — сама точка входа **«Создать инстанс»** отключается, а подсказка называет, какие именно лимиты исчерпаны. Ни одна конфигурация не влезет, поэтому мастер даже не открывается.
|
||||||
|
- **Место есть, но выбранная конфигурация его превысит** — мастер открывается как обычно; начиная с шага конфигурации называется метрика, которая была бы превышена, а **«Далее»**/**«Развернуть»** заблокированы, пока запрос не уменьшат.
|
||||||
|
|
||||||
|
Ни одна из блокировок не применяется к **админам** — их личная квота не имеет отношения к инстансу, который они создают для кого-то другого, а показанные им цифры носят чисто информационный характер.
|
||||||
|
|
||||||
### Управление квотами (админ)
|
### Управление квотами (админ)
|
||||||
|
|
||||||
Страница **Пользователи** → диалог квот. Живые полосы использования показывают текущее потребление против каждого лимита. Оставьте поле пустым для *без ограничений*. Требует право `quota:manage` (`quota:view` для чтения).
|
Страница **Пользователи** → диалог квот. Живые полосы использования показывают текущее потребление против каждого лимита. Оставьте поле пустым для *без ограничений*. Требует право `quota:manage` (`quota:view` для чтения).
|
||||||
|
|
||||||
### Self-service
|
### Self-service
|
||||||
|
|
||||||
Каждый пользователь видит свои лимиты и текущее использование на странице **Настройки**. Мастер **создания инстанса** показывает остаток квоты подсказкой на шаге конфигурации.
|
Каждый пользователь видит свои лимиты и текущее использование на странице **Профиль**. Мастер **создания инстанса** показывает остаток квоты подсказкой на шаге конфигурации.
|
||||||
|
|
||||||
### REST API
|
### REST API
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user