The RHEL-family qemu-guest-agent package starts the agent with an allow-list that omits guest-exec, guest-exec-status and guest-file-* (FILTER_RPC_ARGS in /etc/sysconfig/qemu-ga; older packages spelled the same restriction as BLOCK_RPCS or BLACKLIST_RPC). The agent answered "The command guest-exec has been disabled for this instance", so running scripts in a VM, assigning extra IP addresses and growing the filesystem after a disk resize did not work on Rocky Linux, AlmaLinux, CentOS Stream and Fedora guests. - patch-cloud-images.sh: clear all three variants while building the mirror (UNBLOCK_RPC=0 opts out) and add an ONLY filter to rebuild only part of the catalog. Three `[ ... ] && ...` statements that aborted the script under set -e are now plain ifs -- the one before mirrors.json generation killed every run that passed BASE_URL - builtin.py: point the five RHEL-family amd64 entries at the rebuilt mirror release 2026-08-22 with their new checksums. Ubuntu and Debian images are unaffected and stay in the previous releases, so older panel versions keep working - client.py: annotate the Proxmox error with what to clear inside the guest, the raw message names neither the file nor the variable - WIKI, CHANGELOG: document the restriction and the unblock command
2553 lines
158 KiB
Markdown
2553 lines
158 KiB
Markdown
# 📖 PVEmanager — Документация
|
||
|
||
> Полное руководство по установке, настройке и использованию PVEmanager v1.16.0
|
||
|
||
---
|
||
|
||
## 📑 Содержание
|
||
|
||
1. [Быстрый старт](#-быстрый-старт)
|
||
2. [Установка и развёртывание](#-установка-и-развёртывание)
|
||
3. [Основные возможности](#-основные-возможности)
|
||
4. [Система уведомлений](#-система-уведомлений)
|
||
5. [Управление ВМ и контейнерами](#-управление-вм-и-контейнерами)
|
||
6. [Массовые операции](#-массовые-операции)
|
||
7. [Шаблоны ОС](#-шаблоны-ос)
|
||
8. [Images — каталог облачных образов](#-images--каталог-облачных-образов)
|
||
9. [Развёртывание LXC из CT-шаблонов](#-развёртывание-lxc-из-ct-шаблонов)
|
||
10. [App Store](#-app-store)
|
||
11. [Кластеры Proxmox](#-кластеры-proxmox)
|
||
12. [Снимки (Snapshots)](#-снимки-snapshots)
|
||
13. [Резервные копии](#-резервные-копии)
|
||
14. [IPAM](#-ipam)
|
||
15. [Удалённое выполнение команд](#-удалённое-выполнение-команд)
|
||
16. [Мониторинг](#-мониторинг)
|
||
17. [Безопасность (RBAC v2)](#-безопасность)
|
||
18. [Локализация](#-локализация)
|
||
19. [Настройки](#-настройки)
|
||
20. [Управление SSH-ключами](#-управление-ssh-ключами)
|
||
21. [Сети (SDN и интерфейсы узлов)](#сетевые-интерфейсы-узлов)
|
||
22. [Инструмент pve CLI](#-инструмент-pve-cli)
|
||
23. [Справочник API](#-справочник-api)
|
||
24. [Рабочие области (Workspaces)](#-рабочие-области-workspaces)
|
||
25. [Назначение серверов пользователю](#-назначение-серверов-пользователю)
|
||
26. [Владелец ВМ / LXC](#-владелец-вм--lxc)
|
||
27. [Квоты](#-квоты)
|
||
28. [Логи и аудит](#-логи-и-аудит)
|
||
29. [Устранение неполадок](#-устранение-неполадок)
|
||
30. [FAQ](#-faq)
|
||
|
||
---
|
||
|
||
## 🚀 Быстрый старт
|
||
|
||
### Требования
|
||
|
||
- Docker и Docker Compose
|
||
- Минимум 2 ГБ RAM
|
||
- Сервер Proxmox VE с доступом к API
|
||
|
||
### Запуск за 1 минуту
|
||
|
||
```bash
|
||
# Клонировать репозиторий
|
||
git clone https://github.com/your-repo/pvemanager.git
|
||
cd pvemanager
|
||
|
||
# Скопировать и настроить переменные окружения
|
||
cp .env.example .env
|
||
cp backend/.env.example backend/.env
|
||
|
||
# Запуск
|
||
docker compose up -d
|
||
|
||
# Открыть в браузере
|
||
open http://localhost:3001
|
||
```
|
||
|
||
**Учётные данные по умолчанию:**
|
||
- Логин: `admin`
|
||
- Пароль: `admin123`
|
||
|
||
> ⚠️ Обязательно смените пароль после первого входа!
|
||
|
||
---
|
||
|
||
## 📦 Установка и развёртывание
|
||
|
||
### Варианты развёртывания
|
||
|
||
#### 1. Standalone (разработка)
|
||
|
||
```bash
|
||
docker compose up -d
|
||
```
|
||
- Порт UI: 3001 (frontend), порт API: 8000 (backend)
|
||
- Без обратного прокси NGINX
|
||
- Подходит для локальной разработки
|
||
|
||
#### 2. С NGINX (HTTP)
|
||
|
||
```bash
|
||
./deploy.sh
|
||
# Выбрать вариант 2
|
||
```
|
||
|
||
#### 3. С NGINX + SSL (продакшн)
|
||
|
||
```bash
|
||
./deploy.sh
|
||
# Выбрать вариант 3
|
||
# Указать домен и 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`)
|
||
|
||
```bash
|
||
# База данных
|
||
POSTGRES_PASSWORD=your_secure_password
|
||
|
||
# Часовой пояс
|
||
TZ=Your/Timezone
|
||
|
||
# Отключить проверку обновлений (для приватных репо без токена)
|
||
DISABLE_UPDATE_CHECK=false
|
||
|
||
# Токен GitHub для доступа к приватному репозиторию (опционально)
|
||
GITHUB_TOKEN=
|
||
```
|
||
|
||
#### Backend (`backend/.env`)
|
||
|
||
```bash
|
||
# Секретный ключ (сгенерируйте уникальный! минимум 32 символа)
|
||
SECRET_KEY=your-very-long-secret-key-change-me
|
||
|
||
# Пароль администратора по умолчанию — ОБЯЗАТЕЛЬНО смените перед первым развёртыванием!
|
||
ADMIN_PASSWORD=admin123
|
||
|
||
# Ключ шифрования Fernet для чувствительных полей БД (пароли Proxmox/cloud-init).
|
||
# Сгенерировать: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
||
# ВНИМАНИЕ: храните этот ключ в безопасности — его потеря означает потерю доступа к зашифрованным паролям.
|
||
# Если не задан, пароли хранятся в открытом виде (небезопасно).
|
||
FERNET_KEY=
|
||
|
||
# Время жизни JWT-токена (в минутах). По умолчанию: 480 (8 часов)
|
||
ACCESS_TOKEN_EXPIRE_MINUTES=480
|
||
|
||
# CORS-источники (через запятую). В продакшне используйте реальный домен(ы).
|
||
CORS_ORIGINS=*
|
||
```
|
||
|
||
#### Уведомления Email и Telegram
|
||
|
||
Настройки SMTP и Telegram-бота теперь управляются через веб-интерфейс:
|
||
|
||
1. Перейдите в **Настройки → Уведомления**
|
||
2. В разделе «Настройка каналов уведомлений» заполните:
|
||
- **SMTP** — параметры вашего почтового сервера
|
||
- **Telegram** — токен бота от @BotFather
|
||
3. Нажмите кнопку **Тест** для проверки настроек
|
||
|
||
---
|
||
|
||
## 📚 Справочник API
|
||
|
||
В этом разделе перечислены ключевые эндпоинты API. Все они требуют JWT-аутентификации.
|
||
|
||
### Аутентификация
|
||
|
||
- `POST /api/auth/login` — возвращает `access_token`
|
||
|
||
### Обновления системы
|
||
|
||
- `GET /settings/api/version` — текущая версия
|
||
- `GET /settings/api/updates/repository` — получить URL git-репозитория
|
||
- `PUT /settings/api/updates/repository` — задать URL git-репозитория
|
||
- `GET /settings/api/updates/check` — проверить наличие обновлений
|
||
- `POST /settings/api/updates/perform` — запустить обновление
|
||
|
||
### Серверы Proxmox
|
||
|
||
- `GET /api/servers` — список серверов
|
||
- `POST /api/servers` — добавить сервер (`auto_create_token` создаёт API-токен по логину/паролю)
|
||
- `PUT /api/servers/{id}` — обновить сервер
|
||
- `DELETE /api/servers/{id}` — удалить сервер
|
||
- `POST /api/servers/{id}/test` — проверить подключение
|
||
- `POST /api/servers/{id}/provision-token` — перевести сервер с пароля на автосозданный API-токен
|
||
|
||
### Виртуальные машины
|
||
|
||
- `GET /api/servers/{id}/resources` — список ВМ
|
||
- `POST /api/servers/{id}/vm/{vmid}/start?node={node}` — запустить ВМ
|
||
- `POST /api/servers/{id}/vm/{vmid}/stop?node={node}` — остановить ВМ
|
||
- `POST /api/servers/{id}/vm/{vmid}/restart?node={node}` — перезагрузить ВМ
|
||
- `GET /api/servers/{id}/vm/{vmid}/status?node={node}` — статус ВМ
|
||
|
||
### Контейнеры
|
||
|
||
- `GET /api/servers/{id}/resources` — список контейнеров
|
||
- `POST /api/servers/{id}/container/{vmid}/start?node={node}` — запустить контейнер
|
||
- `POST /api/servers/{id}/container/{vmid}/stop?node={node}` — остановить контейнер
|
||
- `POST /api/servers/{id}/container/{vmid}/restart?node={node}` — перезагрузить контейнер
|
||
- `GET /api/servers/{id}/container/{vmid}/status?node={node}` — статус контейнера
|
||
|
||
### Шаблоны ОС
|
||
|
||
- `GET /templates/api/groups` — список групп шаблонов
|
||
- `POST /templates/api/groups` — создать группу шаблонов
|
||
- `GET /templates/api/templates` — список шаблонов
|
||
- `POST /templates/api/templates` — создать шаблон
|
||
- `DELETE /templates/api/templates/{id}` — удалить шаблон
|
||
|
||
### IPAM
|
||
|
||
- `GET /ipam/api/networks` — список сетей
|
||
- `POST /ipam/api/networks` — создать сеть
|
||
- `DELETE /ipam/api/networks/{id}` — удалить сеть
|
||
- `GET /ipam/api/allocations` — список выделенных IP (фильтры: `network_id`, `pool_id`, `status`, `proxmox_server_id`, `proxmox_vmid`)
|
||
- `POST /ipam/api/allocations` — создать выделение IP
|
||
- `DELETE /ipam/api/allocations/{id}` — освободить IP
|
||
- `GET /ipam/api/guests/{server_id}/{vmid}/addresses` — все адреса инстанса
|
||
- `POST /ipam/api/guests/{server_id}/{vmid}/addresses` — выдать инстансу дополнительный адрес
|
||
- `POST /ipam/api/guests/{server_id}/{vmid}/addresses/{id}/apply` — повторить применение к гостю
|
||
- `POST /ipam/api/guests/{server_id}/{vmid}/addresses/{id}/primary` — сделать основным
|
||
- `DELETE /ipam/api/guests/{server_id}/{vmid}/addresses/{id}` — снять с гостя и освободить
|
||
- `POST /ipam/api/link-allocations` — просканировать гостей и зарегистрировать их адреса
|
||
|
||
### Уведомления
|
||
|
||
- `GET /api/notifications` — список уведомлений
|
||
- `PATCH /api/notifications/{id}/read` — отметить прочитанным
|
||
- `DELETE /api/notifications/{id}` — удалить уведомление
|
||
|
||
### Пользователи и роли
|
||
|
||
- `GET /api/users` — список пользователей (админ)
|
||
- `POST /api/users` — создать пользователя (админ)
|
||
- `PUT /api/users/{id}` — обновить пользователя (админ)
|
||
- `DELETE /api/users/{id}` — удалить пользователя (админ)
|
||
- `GET /api/roles` — список ролей (админ)
|
||
- `POST /api/roles` — создать роль (админ)
|
||
- `PUT /api/roles/{id}` — обновить роль (админ)
|
||
- `DELETE /api/roles/{id}` — удалить роль (админ)
|
||
|
||
### Квоты
|
||
|
||
- `GET /api/users/{id}/quota` — квота пользователя и текущее использование (требует `quota:view`)
|
||
- `PUT /api/users/{id}/quota` — задать квоту пользователя; `null` для метрики = без ограничений (требует `quota:manage`)
|
||
- `GET /api/quota` — собственная квота и использование текущего пользователя (self-service)
|
||
|
||
### Настройки
|
||
|
||
- `GET /settings/api/panel` — получить настройки панели
|
||
- `PUT /settings/api/panel` — обновить настройки панели
|
||
- `GET /settings/api/security` — получить настройки безопасности
|
||
- `PUT /settings/api/security` — обновить настройки безопасности
|
||
- `GET /settings/api/notifications` — получить настройки уведомлений
|
||
- `PUT /settings/api/notifications` — обновить настройки уведомлений
|
||
|
||
### Резервные копии и хранилища
|
||
|
||
- `GET /api/backups/storages/{server_id}` — список хранилищ
|
||
- `GET /api/backups/scan-nfs/{server_id}?server=<ip>` — сканировать NFS-сервер на доступные экспорты
|
||
- `POST /api/backups/storages/{server_id}` — добавить хранилище
|
||
- `PUT /api/backups/storages/{server_id}/{storage_id}` — обновить хранилище
|
||
- `DELETE /api/backups/storages/{server_id}/{storage_id}` — удалить хранилище
|
||
- `GET /api/backups/list/{server_id}?node=&storage=` — список файлов резервных копий
|
||
- `DELETE /api/backups/{server_id}/backup` — удалить файл резервной копии
|
||
- `POST /api/backups/create` — создать резервную копию VM/LXC (vzdump)
|
||
- `POST /api/backups/restore` — восстановить VM/LXC из резервной копии
|
||
- `GET /api/backups/task/{server_id}/{node}/{upid}` — статус/лог задачи
|
||
- `GET /api/backups/jobs` — список запланированных заданий резервного копирования
|
||
- `POST /api/backups/jobs` — создать запланированное задание
|
||
- `PUT /api/backups/jobs/{id}` — обновить задание
|
||
- `DELETE /api/backups/jobs/{id}` — удалить задание
|
||
|
||
### Высокая доступность (HA)
|
||
|
||
- `GET /api/{server_id}/ha/status` — статус HA для всех ВМ
|
||
- `GET /api/{server_id}/ha/{vm_type}/{vmid}` — статус HA для ВМ
|
||
- `POST /api/{server_id}/ha/{vm_type}/{vmid}/add` — добавить ВМ в HA
|
||
- `DELETE /api/{server_id}/ha/{vm_type}/{vmid}/remove` — убрать ВМ из HA
|
||
|
||
### SDN (Software Defined Networking)
|
||
|
||
- `GET /api/servers/{server_id}/sdn/status` — проверить доступность SDN
|
||
- `GET /api/servers/{server_id}/sdn/zones` — список зон
|
||
- `POST /api/servers/{server_id}/sdn/zones` — создать зону
|
||
- `PUT /api/servers/{server_id}/sdn/zones/{zone}` — обновить зону
|
||
- `GET /api/servers/{server_id}/sdn/vnets` — список VNet
|
||
- `POST /api/servers/{server_id}/sdn/vnets` — создать VNet
|
||
- `PUT /api/servers/{server_id}/sdn/vnets/{vnet}` — обновить VNet
|
||
- `POST /api/servers/{server_id}/sdn/vnets/{vnet}/subnets` — создать подсеть (поддерживает `create_ipam_network`)
|
||
- `DELETE /api/servers/{server_id}/sdn/vnets/{vnet}/subnets/{cidr}` — удалить подсеть
|
||
- `POST /api/servers/{server_id}/sdn/apply` — применить ожидающие изменения SDN
|
||
|
||
### Сети узлов
|
||
|
||
- `GET /api/servers/{server_id}/nodes` — список узлов сервера
|
||
|
||
### Прочее
|
||
|
||
- `POST /api/sync-vms` — принудительная немедленная синхронизация ВМ со всех серверов Proxmox
|
||
- `DELETE /proxmox/api/all-tasks/completed` — удалить все завершённые/проваленные/отменённые задачи текущего пользователя (и ProxmoxTask, и TaskQueue)
|
||
|
||
---
|
||
|
||
## 🏠 Основные возможности
|
||
|
||
### Дашборд
|
||
|
||
- **5 карточек статистики** — узлы, ВМ, контейнеры, кластеры, оповещения (в реальном времени)
|
||
- **Карточки ресурсов** — CPU, RAM, хранилище с мини-графиками (sparkline)
|
||
- **Чип статуса** в шапке — `All systems operational` / предупреждения / критические оповещения
|
||
- **Живые часы** в шапке
|
||
- Количество кластеров вычисляется автоматически из базы данных
|
||
- Счётчик оповещений из AuditLog (ошибки + критические за последние 24 ч)
|
||
- Недавние события аудита (последние 5) на дашборде
|
||
- **Селектор кластера** в боковой панели — показывает активный кластер или имя standalone
|
||
- **Бейдж версии** в шапке
|
||
|
||
### Серверы Proxmox
|
||
|
||
- Добавление нескольких серверов
|
||
- Аутентификация через API Token или пароль
|
||
- Автоматическое создание API-токена с переводом уже подключённых по паролю серверов без переподключения
|
||
- Мониторинг статуса серверов с различением недоступной ноды и отклонённых/протухших учётных данных
|
||
- Доступность storage по нодам
|
||
|
||
### Управление ВМ и LXC
|
||
|
||
- Просмотр всех виртуальных машин
|
||
- Запуск / Остановка / Перезагрузка / Выключение
|
||
- Изменение конфигурации (CPU, RAM, диск)
|
||
- VNC-консоль в браузере
|
||
- Удалённое выполнение команд
|
||
|
||
### Массовые операции
|
||
|
||
- Массовый запуск/остановка/перезагрузка/удаление ВМ и контейнеров
|
||
- Система очереди задач с отслеживанием прогресса
|
||
- Фоновая обработка
|
||
|
||
### Шаблоны ОС
|
||
|
||
- Быстрое развёртывание ВМ из шаблонов
|
||
- Кросс-узловое развёртывание шаблонов для кластеров
|
||
- Группы шаблонов и иконки
|
||
- Переустановка ВМ из шаблона
|
||
|
||
### Снимки (Snapshots)
|
||
|
||
- Создание, удаление, откат снимков VM/LXC
|
||
- Система очереди операций со снимками
|
||
- Архивирование снимков при удалении ВМ
|
||
|
||
### Резервные копии
|
||
|
||
- Ручное создание резервных копий (vzdump) для ВМ и контейнеров
|
||
- Просмотр и удаление копий по хранилищу/узлу
|
||
- Восстановление VM/LXC из копии с опциональным новым VMID
|
||
- **Запланированные задания** с cron-выражениями
|
||
- Политики хранения копий (keep_last, keep_daily, keep_weekly, keep_monthly)
|
||
- Управление пулами хранилищ (добавить, изменить, удалить)
|
||
- Отслеживание прогресса задач через UPID
|
||
|
||
### Высокая доступность (HA)
|
||
|
||
- Просмотр статуса HA для всех ВМ на сервере
|
||
- Добавление/удаление ВМ из групп Proxmox HA
|
||
- Статус HA и информация о группе для каждой ВМ
|
||
|
||
### IPAM (управление IP-адресами)
|
||
|
||
- Управление сетями и подсетями
|
||
- **Привязка к серверу и узлу** — сети привязываются к конкретному серверу и узлу Proxmox, чтобы исключить назначение IP между серверами
|
||
- **Ручной выбор сервера + сети** в модальном окне при привязке IP к VM/LXC
|
||
- Динамические селекторы сервера и узла в формах создания сети
|
||
- Автоматическое выделение IP
|
||
- Резервирование и освобождение IP
|
||
- **Несколько адресов на инстанс** — основной адрес и дополнительные, навешиваемые внутри гостя как alias
|
||
- История выделений
|
||
|
||
### Уведомления
|
||
|
||
- Оповещения о событиях ВМ в реальном времени
|
||
- Email-уведомления через SMTP
|
||
- Telegram-уведомления через Bot API
|
||
- In-App уведомления с иконкой колокольчика
|
||
|
||
### Безопасность
|
||
|
||
- RBAC v2 с атомарными правами (`resource:action`)
|
||
- Изоляция пользователей в стиле VPS (пользователи видят только свои инстансы)
|
||
- Блокировка IP (автоматическая и ручная)
|
||
- Управление сессиями
|
||
- Защита входа (блокировка, ограничение частоты)
|
||
- Журналы аудита
|
||
|
||
### Квоты
|
||
|
||
Ограничения ресурсов на пользователя, применяемые при развёртывании VM/LXC:
|
||
|
||
- **Ограничиваемые метрики** — количество инстансов, суммарные vCPU (ядра), суммарная RAM (МБ) и суммарный диск (ГБ), просуммированные по неудалённым, не-шаблонным инстансам пользователя
|
||
- **Без ограничений по умолчанию** — пользователь без строки квоты или с пустой метрикой (`NULL`) не ограничен по этой метрике; администраторы никогда не блокируются
|
||
- **Применение** — развёртывание инстанса, превышающего любой лимит, отклоняется с **HTTP 429** и двуязычным сообщением с прогнозируемым значением и лимитом
|
||
- **Управление админом** — задание лимитов на пользователя на странице **Пользователи** (диалог квот с живыми полосами использования); требует право `quota:manage` (`quota:view` для чтения)
|
||
- **Self-service** — каждый пользователь видит свои лимиты и текущее использование на странице **Настройки**, а остаток квоты показывается подсказкой в мастере создания инстанса
|
||
- Текущее использование берётся из кэша `vm_instances` (`owner_id`), где RAM хранится в МБ, а диск — в ГБ
|
||
|
||
### Мониторинг
|
||
|
||
- Метрики CPU, RAM, диска, сети в реальном времени
|
||
- Исторические графики (час, день, неделя, месяц) как для инстансов, так и для нод (вкладка «Графики» у ноды: CPU, IO delay, память, load average, сеть, swap, корневая ФС)
|
||
- Пороги оповещений по ресурсам
|
||
|
||
---
|
||
|
||
## 🔔 Система уведомлений
|
||
|
||
### Обзор
|
||
|
||
Система уведомлений обеспечивает:
|
||
- **Оповещения в реальном времени** о событиях ВМ
|
||
- **Email-уведомления** через SMTP
|
||
- **Telegram-уведомления** через Bot API
|
||
- **In-App уведомления** с иконкой колокольчика
|
||
|
||
### Типы уведомлений
|
||
|
||
| Тип | Описание | Пример |
|
||
|------|-------------|---------|
|
||
| `vm_status` | Изменения состояния ВМ | ВМ запущена/остановлена |
|
||
| `resource_alert` | Оповещения по ресурсам | CPU > 80%, RAM > 85% |
|
||
| `system` | Системные события | Ошибки подключения |
|
||
|
||
### Уровни важности
|
||
|
||
| Уровень | Цвет | Описание |
|
||
|-------|-------|-------------|
|
||
| `critical` | 🔴 Красный | Критические проблемы |
|
||
| `warning` | 🟠 Оранжевый | Предупреждения |
|
||
| `info` | 🔵 Синий | Информационные |
|
||
| `success` | 🟢 Зелёный | Успешные операции |
|
||
|
||
### Настройка Email
|
||
|
||
1. Перейдите в **Настройки** → **Уведомления**
|
||
2. В «Настройке каналов уведомлений» заполните данные SMTP:
|
||
- **SMTP-сервер** — адрес почтового сервера
|
||
- **Порт** — 465 для SSL, 587 для STARTTLS
|
||
- **Пользователь** — ваш email
|
||
- **Пароль** — пароль приложения
|
||
- **Email отправителя** — адрес отправителя
|
||
3. В «Настройках уведомлений» отметьте **Email-уведомления**
|
||
4. Нажмите **Тест** для проверки
|
||
|
||
**Поддерживаемые SMTP-серверы:**
|
||
|
||
| Сервер | Хост | Порт | TLS |
|
||
|--------|------|------|-----|
|
||
| Yandex | smtp.yandex.ru | 465 | SSL |
|
||
| Gmail | smtp.gmail.com | 587 | STARTTLS |
|
||
| Mail.ru | smtp.mail.ru | 465 | SSL |
|
||
|
||
> ⚠️ Для Yandex и Gmail используйте «пароль приложения», а не основной пароль!
|
||
|
||
### Настройка Telegram
|
||
|
||
1. Создайте бота через [@BotFather](https://t.me/BotFather)
|
||
2. В **Настройки → Уведомления** введите токен бота
|
||
3. Отправьте боту `/start`
|
||
4. Получите Chat ID через [@userinfobot](https://t.me/userinfobot)
|
||
5. В «Настройках уведомлений» включите Telegram и введите Chat ID
|
||
6. Нажмите **Проверить** для подтверждения
|
||
|
||
### Параметры уведомлений
|
||
|
||
| Параметр | Описание |
|
||
|-----------|-------------|
|
||
| Включено | Активировать канал |
|
||
| Только критические | Отправлять только критический уровень |
|
||
| Тихие часы | Период без уведомлений (напр., 23:00 – 07:00) |
|
||
|
||
### Фоновый мониторинг
|
||
|
||
Автоматически отслеживает:
|
||
- **Статус ВМ** каждые 30 секунд
|
||
- **Ресурсы** каждые 60 секунд
|
||
- **Пороги**: CPU > 80%, RAM > 85%, диск > 90%
|
||
|
||
---
|
||
|
||
## 🖥️ Управление ВМ и контейнерами
|
||
|
||
### Палитра команд (Ctrl+K)
|
||
|
||
Нажмите **Ctrl+K** (⌘K на macOS) в любом месте приложения, чтобы открыть **палитру команд** — поисковый список всех пунктов навигации. Начните печатать для фильтрации, затем <kbd>Enter</kbd> для перехода. Палитра и боковое меню используют один унифицированный реестр навигации, поэтому всегда синхронизированы.
|
||
|
||
### Действия с ВМ
|
||
|
||
Меню строки инстанса (⋯) содержит **Опции**, **Миграцию**, **Изменение ресурсов**, **Создание резервной копии** и **Удаление** наряду с действиями питания ниже. Меню остаётся открытым при живых обновлениях списка.
|
||
|
||
| Действие | Описание | Хоткей |
|
||
|--------|-------------|--------|
|
||
| Start | Запустить ВМ | - |
|
||
| Stop | Остановить (ACPI-выключение) | - |
|
||
| Restart | Перезагрузить | - |
|
||
| Force Stop | Принудительная остановка | - |
|
||
| Delete | Удалить ВМ | - |
|
||
|
||
> **Вкладки инстанса:** для **ВМ** карточки *Compute resources*, *CPU options*, *Disk management* и *Disk resize* находятся на вкладке **Hardware**; **LXC**-контейнеры (у которых нет вкладки Hardware) держат эти карточки на вкладке **Settings**.
|
||
|
||
### Массовые операции
|
||
|
||
Выберите несколько ВМ/контейнеров и выполните массовые действия:
|
||
|
||
1. Отметьте чекбокс рядом с каждой нужной ВМ
|
||
2. Используйте «Выбрать все» для выбора всех видимых ВМ
|
||
3. Нажмите кнопку действия в панели массовых операций:
|
||
- **Start All** — запустить все выбранные
|
||
- **Stop All** — остановить все выбранные
|
||
- **Restart All** — перезагрузить все выбранные
|
||
- **Delete All** — удалить все выбранные (с подтверждением)
|
||
|
||
Подробнее см. [Массовые операции](#-массовые-операции).
|
||
|
||
### Консоль (VNC / терминал)
|
||
|
||
- **QEMU-ВМ** — VNC-консоль через noVNC (графический вывод в браузере).
|
||
1. Откройте детали ВМ → нажмите **Console**, либо ПКМ по ВМ в списке → **VNC Console**
|
||
2. Полный проброс клавиатуры и мыши; поддержка полноэкранного режима
|
||
- **LXC-контейнеры** — интерактивный shell через терминал xterm.js.
|
||
1. Откройте детали контейнера → нажмите **Terminal**, либо ПКМ по контейнеру в списке → **Terminal**
|
||
2. Полный PTY: автодополнение, цвета, Unicode, изменение размера терминала при ресайзе окна
|
||
3. Использует WebSocket-протокол Proxmox `termproxy` (рукопожатие аутентификации + keepalive-пинги каждые 2 мин)
|
||
|
||
### Изменение конфигурации
|
||
|
||
```
|
||
CPU: 1–32 ядра
|
||
RAM: 512 МБ – 128 ГБ
|
||
Диск: увеличение размера (уменьшение невозможно)
|
||
```
|
||
|
||
> **Примечание (v1.2.0+):** изменение размера диска полностью асинхронно. Панель ждёт завершения задачи ресайза в Proxmox перед запуском ВМ, что предотвращает ошибки `lock file timeout`, возникавшие при немедленном запуске ВМ после запроса ресайза.
|
||
|
||
### Высокая доступность (HA)
|
||
|
||
Требуется кластер Proxmox с настроенным менеджером HA.
|
||
|
||
1. Откройте детали ВМ или контейнера
|
||
2. Перейдите на вкладку **HA**
|
||
3. Нажмите **Add to HA** и выберите HA-группу (опционально)
|
||
4. Для удаления — нажмите **Remove from HA**
|
||
|
||
> Операции панели сейчас отражают статус HA, но не заменяют конфигурацию менеджера Proxmox HA.
|
||
|
||
---
|
||
|
||
## ⚡ Массовые операции
|
||
|
||
### Обзор
|
||
|
||
Массовые операции позволяют выполнить одно и то же действие над несколькими ВМ или контейнерами одновременно. Это удобно, когда нужно запустить, остановить или перезагрузить много виртуальных машин сразу.
|
||
|
||
### Поддерживаемые действия
|
||
|
||
| Действие | Описание | Требуется подтверждение |
|
||
|--------|-------------|----------------------|
|
||
| Bulk Start | Запустить все выбранные VM/контейнеры | Нет |
|
||
| Bulk Stop | Остановить все выбранные (ACPI-выключение) | Нет |
|
||
| Bulk Restart | Перезагрузить все выбранные | Нет |
|
||
| Bulk Shutdown | Корректное выключение | Нет |
|
||
| Bulk Delete | Удалить все выбранные | Да (двойное подтверждение) |
|
||
|
||
### Как использовать
|
||
|
||
1. **Перейдите на страницу «Виртуальные машины»**
|
||
2. **Выберите ВМ** чекбоксами:
|
||
- Кликайте отдельные чекбоксы
|
||
- Или используйте «Выбрать все» для всех видимых ВМ
|
||
3. **Панель массовых действий** появляется внизу при выборе ВМ
|
||
4. **Нажмите нужное действие**
|
||
5. **Подтвердите** при запросе (для операций удаления)
|
||
|
||
### Панель задач (Task Drawer)
|
||
|
||
При запуске массовой операции **Task Drawer** автоматически открывается в боковой панели. Он показывает прогресс каждой задачи в реальном времени:
|
||
|
||
- **Выполняющиеся** задачи показывают спиннер и текущий прогресс (`completed / total`)
|
||
- **Завершённые** задачи зелёные; **проваленные** — красные
|
||
- Задачи старше **24 часов** автоматически скрываются из панели (остаются доступны на странице `/tasks`)
|
||
- Кнопка **корзины** (🗑) в шапке панели удаляет все завершённые/проваленные/отменённые задачи одним кликом
|
||
|
||
### Отслеживание UPID Proxmox
|
||
|
||
Начиная с v1.1.5, отдельные действия управления VM/LXC (start / stop / restart) связаны с реальным UPID задачи Proxmox. UPID регистрируется как запись `ProxmoxTask` и опрашивается в реальном времени, поэтому Task Drawer отражает фактическое состояние задачи на стороне Proxmox.
|
||
|
||
### Ограничения
|
||
|
||
- Одновременно выполняется только одна массовая задача
|
||
- Задачи обрабатываются последовательно
|
||
- Максимум элементов на задачу: не ограничено (но учитывайте нагрузку на сервер)
|
||
- Задачи нельзя приостановить (только отменить, если ожидают)
|
||
|
||
---
|
||
|
||
## 📋 Шаблоны ОС
|
||
|
||
### Концепция
|
||
|
||
Шаблоны ОС позволяют быстро развёртывать ВМ из предварительно настроенных шаблонов.
|
||
|
||
### Создание группы шаблонов
|
||
|
||
1. **Шаблоны ОС** → **Groups** → **Add Group**
|
||
2. Введите имя (напр., «Linux Servers»)
|
||
3. Добавьте описание
|
||
|
||
### Добавление шаблона
|
||
|
||
1. **Шаблоны ОС** → **Templates** → **Add Template**
|
||
2. Или: **Scan** → выбрать из Proxmox
|
||
|
||
### Развёртывание ВМ
|
||
|
||
1. Выберите шаблон
|
||
2. Укажите:
|
||
- Имя ВМ
|
||
- **Целевой узел** (для кластеров — выбрать, куда развернуть)
|
||
- CPU/RAM/диск
|
||
- IP-адрес (или авто из IPAM)
|
||
- SSH-ключ (опционально)
|
||
3. Нажмите **Deploy**
|
||
|
||
### Кросс-узловое развёртывание шаблонов (кластеры)
|
||
|
||
При использовании кластеров Proxmox шаблоны можно развернуть на любой узел кластера:
|
||
|
||
#### Как это работает
|
||
|
||
1. **Создание шаблона на любом узле** — шаблон изначально создаётся на одном узле кластера
|
||
2. **Выбор целевого узла** — при развёртывании ВМ выберите любой онлайн-узел кластера
|
||
3. **Автоматическая репликация** — если шаблона нет на целевом узле:
|
||
- Система клонирует шаблон на целевой узел
|
||
- Конвертирует клон в шаблон
|
||
- Отслеживает реплицированные шаблоны в базе данных
|
||
4. **Последующие развёртывания** — используют уже реплицированный шаблон (быстро)
|
||
|
||
#### Требования
|
||
|
||
- Кластер Proxmox (узлы должны быть в одном кластере)
|
||
- Рекомендуется общее хранилище (но не обязательно)
|
||
- Шаблон должен быть доступен с исходного узла
|
||
|
||
#### Пример
|
||
|
||
```
|
||
Кластер: pve1, pve2, pve3
|
||
Шаблон: Ubuntu-22.04 на pve1
|
||
|
||
Развёртывание на pve1: используется оригинальный шаблон (быстро)
|
||
Развёртывание на pve2: репликация шаблона → развёртывание (первый раз медленнее)
|
||
Развёртывание на pve3: репликация шаблона → развёртывание (первый раз медленнее)
|
||
|
||
Следующее развёртывание на pve2: используется реплицированный шаблон (быстро)
|
||
```
|
||
|
||
### Переустановка ВМ
|
||
|
||
1. Откройте детали ВМ
|
||
2. Нажмите **Reinstall**
|
||
3. Выберите шаблон
|
||
4. VMID сохраняется
|
||
|
||
---
|
||
|
||
## 📥 Images — каталог облачных образов
|
||
|
||
### Обзор
|
||
|
||
Модуль **Images** позволяет просматривать, скачивать и управлять образами ОС из облачных репозиториев. Образы можно скачивать напрямую в хранилище Proxmox и опционально автоматически конвертировать в шаблоны ВМ.
|
||
|
||
### Возможности
|
||
|
||
- **Просмотр облачных образов** — обнаружение образов ОС из стандартного репозитория Proxmox и кастомных зеркал
|
||
- **Скачивание образов** — загрузка образов `.qcow2` в любое хранилище Proxmox с отслеживанием прогресса
|
||
- **Автоконвертация в шаблон** — опциональная автоматическая конвертация скачанных образов в шаблоны ВМ Proxmox
|
||
- **Фильтрация по архитектуре** — образы фильтруются по платформе узла (x86-64, aarch64); архитектура по умолчанию соответствует выбранному узлу
|
||
- **Кастомные зеркала** — администраторы могут добавлять, редактировать и управлять кастомными источниками зеркал
|
||
- **Загрузка ISO** — установочный ISO можно скачать по URL, из сохранённого зеркала (`kind=iso`) или прямо на шаге ISO в мастере создания инстанса. Встроенный каталог намеренно ограничен `.qcow2` — у установочных ISO нет стабильной ссылки на «последнюю версию», поэтому жёстко прописанные ссылки протухали бы при каждом релизе
|
||
- **Загрузка локального файла** — ISO или шаблон LXC (`vztmpl`) можно загрузить со своего компьютера прямо в storage ноды — для образов, которые нигде публично не доступны панели
|
||
|
||
### Доступ к Images
|
||
|
||
1. Перейдите в **Infrastructure** → **Images** (боковое меню)
|
||
2. Выберите сервер и узел Proxmox
|
||
3. Просматривайте доступные образы, отфильтрованные по архитектуре
|
||
|
||
### Скачивание образа
|
||
|
||
1. Нажмите **Download** рядом с нужным образом
|
||
2. Выберите целевое хранилище
|
||
3. Опционально включите **Convert to Template** (создаёт шаблон ВМ по завершении)
|
||
4. Нажмите **Download** — прогресс отслеживается в реальном времени
|
||
5. По завершении образ доступен в хранилище для развёртывания ВМ
|
||
|
||
### Загрузка локального файла
|
||
|
||
1. Перейдите в **Infrastructure** → **Images** и выберите **Upload**
|
||
2. Укажите файл ISO или `vztmpl` и целевое хранилище
|
||
3. Панель передаёт файл на ноду в фоне; прогресс отслеживается так же, как при загрузке по URL
|
||
4. По завершении файл доступен в хранилище для развёртывания ВМ/CT
|
||
|
||
### Установка ОС с ISO
|
||
|
||
Мастер создания инстанса предлагает тип **«пустая ВМ»** для установки с ISO: создаётся ВМ с пустым диском и смонтированным на `ide2` образом, который ставится первым в порядке загрузки, — гость сразу попадает в установщик через встроенную консоль noVNC. Выбор гостя Windows автоматически задаёт прошивку OVMF, SATA-диск и сетевую карту e1000, так как у установщика ещё нет драйверов virtio.
|
||
|
||
### Извлечение и монтирование ISO
|
||
|
||
На странице ВМ диалог ISO показывает все образы, уже лежащие в хранилище ноды — включая те, что появились там до подключения ноды к панели, — и текущий смонтированный образ, если он есть:
|
||
|
||
- **Монтировать** — выберите ISO из хранилища; опционально отметьте **«загрузка с этого ISO»**, чтобы поставить CD-ROM первым в порядке загрузки.
|
||
- **Извлечь** (переименовано из «Отсоединить») — снимает смонтированный ISO; опционально отметьте **«загрузка с диска»**, чтобы поставить основной диск первым в порядке загрузки.
|
||
|
||
Любое действие, меняющее порядок загрузки, применяется через **гибридную перезагрузку**: штатное ACPI-выключение с откатом на принудительную остановку, затем запуск. Это убирает таймаут ping гостя, с которым сталкивается обычный рестарт на свежеустановленной ОС, где ещё не запущен QEMU Guest Agent.
|
||
|
||
### GitHub-зеркало с QEMU Guest Agent
|
||
|
||
Встроенный каталог образов amd64 ссылается на **GitHub-зеркало**, содержащее облачные образы с предустановленным `qemu-guest-agent`. Это даёт:
|
||
|
||
- Живые метрики на ВМ (CPU, память, заполнение диска, скорости I/O) сразу после деплоя — дополнительная установка агента не нужна
|
||
- В образах RHEL-семейства (Rocky Linux, AlmaLinux, CentOS Stream, Fedora) снято штатное ограничение RPC: пакет `qemu-guest-agent` там оставляет агенту allow-list без `guest-exec`, `guest-exec-status` и `guest-file-*` (`FILTER_RPC_ARGS` в `/etc/sysconfig/qemu-ga`), из-за чего в таких ВМ не работали выполнение скриптов, дополнительные IP-адреса и расширение ФС после ресайза диска
|
||
- Образы включают контрольную сумму **sha256**; если закешированный файл не совпадает с опубликованной суммой, панель скачает его повторно автоматически
|
||
|
||
Чтобы собрать или обновить зеркало самостоятельно, запустите вспомогательный скрипт на Linux-хосте с установленным QEMU:
|
||
|
||
```bash
|
||
bash patch-cloud-images.sh
|
||
```
|
||
|
||
Скрипт скачивает исходный `.qcow2`, устанавливает `qemu-guest-agent` через `virt-customize`, снимает блокировку RPC (отключается через `UNBLOCK_RPC=0`) и публикует патченный образ как GitHub Release.
|
||
|
||
### Кастомные зеркала (только админ)
|
||
|
||
Администраторы могут настроить кастомные репозитории образов:
|
||
|
||
1. Перейдите в **Настройки** → **Images** → **Custom Mirrors**
|
||
2. Нажмите **Add Mirror**
|
||
3. Введите URL зеркала (должен быть валидным репозиторием Proxmox)
|
||
4. Сохраните — зеркало сразу появится в браузере образов
|
||
|
||
**Формат URL зеркала:**
|
||
|
||
Валидное зеркало должно предоставлять стандартную структуру репозитория Proxmox с файлом `index.json`, содержащим метаданные образов.
|
||
|
||
### Эндпоинты API
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|--------|----------|-------------|
|
||
| `GET` | `/api/images` | Список доступных образов |
|
||
| `GET` | `/api/images/node-arch/{server_id}/{node}` | Архитектура узла |
|
||
| `POST` | `/api/images/download` | Запустить скачивание (возвращает UPID задачи) |
|
||
| `GET` | `/api/images/mirrors` | Список кастомных зеркал (админ) |
|
||
| `POST` | `/api/images/mirrors` | Добавить кастомное зеркало (админ) |
|
||
| `PUT` | `/api/images/mirrors/{id}` | Обновить зеркало (админ) |
|
||
| `DELETE` | `/api/images/mirrors/{id}` | Удалить зеркало (админ) |
|
||
|
||
### Отслеживание задачи скачивания
|
||
|
||
Скачивание образов отслеживается как задачи Proxmox (UPID). Используйте стандартный эндпоинт задач для мониторинга прогресса:
|
||
|
||
```bash
|
||
GET /api/backups/task/{server_id}/{node}/{upid}
|
||
```
|
||
|
||
---
|
||
|
||
## 📦 Развёртывание LXC из CT-шаблонов
|
||
|
||
### Обзор
|
||
|
||
Начиная с v1.5.0, LXC-контейнеры можно создавать напрямую из файлов CT-шаблонов Proxmox (`.tar.zst`, `.tar.gz`) без необходимости заранее настраивать запись «Шаблон ОС». Это стандартный способ развернуть Debian, Ubuntu, Alpine и другие дистрибутивы из списка загрузок Proxmox.
|
||
|
||
### Просмотр доступных CT-шаблонов
|
||
|
||
CT-шаблоны берутся напрямую из хранилища сервера Proxmox:
|
||
|
||
1. Перейдите в **Instances** → **Create Instance**
|
||
2. Выберите целевой сервер Proxmox
|
||
3. Выберите тип **LXC Container**
|
||
4. Мастер получает доступные файлы `.tar.zst` / `.tar.gz` со всех хранилищ выбранного сервера
|
||
|
||
### Развёртывание LXC-контейнера
|
||
|
||
1. Шаг **Server** — выберите сервер Proxmox
|
||
2. Шаг **Type** — выберите **LXC Container**
|
||
3. Шаг **Template** — выберите CT-шаблон из списка
|
||
4. Шаг **Config** — заполните:
|
||
- Имя контейнера (hostname)
|
||
- Ядра CPU, RAM (МБ), Swap (МБ), диск (ГБ)
|
||
- Хранилище, сетевой мост
|
||
- IP-адрес / шлюз (вручную или из IPAM)
|
||
- Root-пароль и/или SSH-ключи
|
||
- Владелец (только админ)
|
||
- Опции Start after create / On-boot
|
||
5. Шаг **Confirm** — проверьте и нажмите **Deploy**
|
||
|
||
Развёртывание выполняется асинхронно; прогресс отслеживается в Task Drawer.
|
||
|
||
### SSH-ключи при развёртывании LXC
|
||
|
||
- Выберите один или несколько ключей из личной библиотеки SSH-ключей (см. [Управление SSH-ключами](#-управление-ssh-ключами))
|
||
- Админы, развёртывающие от имени другого пользователя, могут выбрать ключи из библиотеки этого пользователя
|
||
- Ключи внедряются в `authorized_keys` контейнера во время провижининга
|
||
|
||
### Переустановка LXC-контейнера (CT-шаблон)
|
||
|
||
Контейнеры, созданные из CT-шаблонов, поддерживают переустановку:
|
||
|
||
1. Откройте меню действий контейнера → **Reinstall**
|
||
2. Опционально выберите другой CT-шаблон
|
||
3. Автоматически сохраняются:
|
||
- Root-пароль
|
||
- SSH-ключи
|
||
- IP-адрес и шлюз
|
||
4. Старый контейнер уничтожается, создаётся новый с тем же VMID
|
||
|
||
> **Примечание:** `nesting=1` включается по умолчанию для всех новых LXC-контейнеров для совместимости с systemd 255+ (cgroup v2).
|
||
|
||
---
|
||
|
||
## 🛒 App Store
|
||
|
||
Каталог self-hosted приложений с установкой в один клик. Каждое приложение работает в собственном **unprivileged LXC**-контейнере с **Docker Compose** (1 приложение = 1 LXC). Каталог **мультиисточниковый**: [`runtipi/runtipi-appstore`](https://github.com/runtipi/runtipi-appstore) (~265 приложений) и опционально [`getumbrel/umbrel-apps`](https://github.com/getumbrel/umbrel-apps) (~380 приложений). Источники выбираются через `APPSTORE_SOURCES`; id приложений Umbrel имеют префикс (`umbrel-<id>`) во избежание коллизий.
|
||
|
||
### Предварительные требования
|
||
|
||
- **Золотой шаблон LXC** (Debian 12 + Docker + Compose) на каждый сервер Proxmox. Соберите его из **App Store → золотой шаблон** (`POST /api/appstore/golden-template`, выбирает сервер/узел/хранилище) — это автоматизирует ручную процедуру из [docs/golden-template.md](docs/golden-template.md). Хранилище шаблона и rootfs выбираются из выпадающих списков, заполненных реальными хранилищами выбранного сервера/ноды (по content `vztmpl`/`rootdir`), с автоподстановкой `local`/`local-lvm`, если они доступны. Полученный volid vztmpl хранится **для каждого `server_id`** (шаблон, собранный на сервере A, лежит только в хранилище A и никогда не используется для установки на сервере B); `APPSTORE_GOLDEN_TEMPLATE` — лишь последний запасной вариант для серверов без собственной сборки.
|
||
- **SSH-доступ** от панели к узлу Proxmox (используется для `pct exec` / `pct push`).
|
||
- Установлен `FERNET_KEY` (шифрует секреты приложений на диске).
|
||
|
||
### Настройки окружения
|
||
|
||
| Переменная | По умолчанию | Назначение |
|
||
|---|---|---|
|
||
| `APPSTORE_GOLDEN_TEMPLATE` | — | запасной volid золотого vztmpl, используется только если у сервера нет собственного сохранённого шаблона |
|
||
| `APPSTORE_NAMESERVER` | `1.1.1.1 8.8.8.8` | DNS, явно задаваемый на LXC App Store (и на CT сборки золотого шаблона) — без него контейнер наследует резолвер узла, который может быть недоступен из сети LXC (напр., DNS только для Tailscale на хосте) и ломает pull образов |
|
||
| `APPSTORE_SOURCES` | `runtipi` | активные источники каталога через запятую (`runtipi`, `umbrel`) |
|
||
| `RUNTIPI_APPSTORE_REPO` | `runtipi/runtipi-appstore` | источник каталога Runtipi |
|
||
| `RUNTIPI_APPSTORE_REF` | `master` | ветка/тег/коммит (рекомендуется зафиксировать) |
|
||
| `UMBREL_APPSTORE_REPO` | `getumbrel/umbrel-apps` | источник каталога Umbrel (когда включён `umbrel`) |
|
||
| `UMBREL_APPSTORE_REF` | `master` | ветка/тег/коммит Umbrel |
|
||
| `UMBREL_APPSTORE_GALLERY_CDN` | `https://getumbrel.github.io/umbrel-apps-gallery` | CDN иконок Umbrel (`<app-id>/icon.svg`, скачиваются пофайлово параллельно) |
|
||
| `APPSTORE_DATA_DIR` | `/app/data/appstore` | кэш логотипов (смонтированный volume) |
|
||
| `CATALOG_SYNC_INTERVAL_HOURS` | `24` | интервал авто-синхронизации каталога |
|
||
| `APPSTORE_HOST_ARCH` | `amd64` | целевая архитектура узла (помечает неподдерживаемые приложения) |
|
||
|
||
### Каталог
|
||
|
||
- Экран **App Store**: сетка карточек с поиском и фильтрами по категориям; кнопка **Refresh catalog** + метка времени последней синхронизации. Когда включено более одного источника, появляются **фильтр источника** и **бейдж источника** на карточке (Runtipi / Umbrel).
|
||
- Автоматическая синхронизация каждые 24 ч; повреждённая запись приложения пропускается без провала всей синхронизации. Каждый источник синхронизируется независимо, а проход *исчез → недоступно* ограничен рамками источника.
|
||
- Приложения Umbrel: метаданные из `umbrel-app.yml`, иконки из репозитория gallery; при установке runtime-сервисы Umbrel `app_proxy`/`tor` вырезаются, а порт контейнера (`app_proxy → APP_PORT`) публикуется на хосте LXC.
|
||
- Страница приложения: описание, версия, ссылка на источник, дисклеймер установки и предпросмотр compose.
|
||
|
||
### Установка
|
||
|
||
Конвейер (каждый шаг журналируется и стримится по WebSocket):
|
||
|
||
1. Клонирование золотого шаблона LXC (по умолчанию 2 vCPU / 2048 МБ / 8 ГБ, DHCP или расширенные переопределения).
|
||
2. Запуск и ожидание IP.
|
||
3. `pct push` `docker-compose.yml` + `.env` (ответы формы + сгенерированные `random`-секреты) + любые вложенные `data_files`.
|
||
4. `docker compose up -d`.
|
||
5. HTTP health-check.
|
||
6. Показ URL приложения и одноразовых учётных данных.
|
||
|
||
Проваленный шаг ставит статус `error` с логом шага; **Retry** не пересоздаёт LXC (идемпотентно по VMID) и повторно использует исходные параметры установки (сохранены в `installed_apps.install_params`), **Delete** удаляет контейнер и запись.
|
||
|
||
**Заметки о надёжности:**
|
||
- Файлы, поставляемые с приложением каталога (`data_files`), доставляются в контейнер до `docker compose up`; учитываются Umbrel `APP_PASSWORD` / `default_credentials`.
|
||
- Каталоги bind-mount хоста (`volumes:` в compose приложения, и `${APP_DATA_DIR}/...`, и относительные пути) предварительно создаются с разрешительными правами до `up` — иначе Docker создаёт их как root, и non-root пользователи контейнера (напр., `mysql` у mariadb) получают `Permission denied`.
|
||
- Поиск VMID пропускает уже занятые записи — `nextid` не резервирует номер, поэтому повтор мог бы иначе занять другой контейнер.
|
||
- `pct create` повторяет несколько раз при временной ошибке config-lock (частой сразу после удаления того же VMID, пока узел ещё стирает старый диск).
|
||
- **Delete** теперь ждёт, пока Proxmox фактически подтвердит завершение задачи destroy (до 30 мин, покрывает медленное стирание диска), прежде чем пометить приложение удалённым — иначе VMID мог бы быть переиспользован, пока узел ещё занят.
|
||
- Значения `.env`, содержащие `#`, берутся в кавычки (парсер dotenv иначе обрезал бы их как inline-комментарий); порт, явно выбранный в мастере (включая `80`), публикуется как есть.
|
||
|
||
### Трей свёрнутых операций
|
||
|
||
Долгие операции App Store — **установка** приложения и **сборка золотого шаблона** — можно свернуть вместо того, чтобы держать диалог открытым:
|
||
|
||
- Свёрнутые операции живут в **глобальном хранилище** (сохраняется в `localStorage`) и рендерятся как **трей** в макете приложения, поэтому плашка **переживает навигацию по страницам и полную перезагрузку вкладки**. Трей сам опрашивает прогресс каждой операции (REST, каждые 3 с), независимо от диалога.
|
||
- **Клик по плашке** возвращает на страницу операции и переоткрывает диалог — установка возобновляется в мастере, сборка шаблона переоткрывает диалог золотого шаблона с предвыбранным сервером.
|
||
- **Свернуть** добавляет операцию в трей и закрывает диалог; ✕ на плашке лишь удаляет плашку (операция продолжает работать на сервере). Плашки операций, которых больше нет (`404` после перезагрузки), очищаются автоматически.
|
||
|
||
### Мои приложения
|
||
|
||
Управление установленными приложениями: **Start / Stop / Restart / Logs / Delete**, живой статус и кликабельный `IP:port`.
|
||
|
||
- **Реконсиляция** запускается каждые 60 с и при открытии экрана: LXC, удалённый вне PVEmanager, помечается `orphaned`.
|
||
- **Обновление**: делает pre-update снапшот Proxmox → `docker compose pull && up -d` → health-check; хранит только последний pre-update снапшот.
|
||
- **Откат**: восстанавливает снапшот (⚠️ также откатывает **данные** приложения к моменту снапшота) и возвращает версию в базе данных.
|
||
|
||
### Права
|
||
|
||
`app:view` (каталог + Мои приложения), `app:install` (установка), `app:manage` (синхронизация, жизненный цикл, обновление, откат, удаление). Админы обходят все проверки.
|
||
|
||
### REST API
|
||
|
||
```
|
||
GET /api/appstore/catalog # список (q, category, source)
|
||
GET /api/appstore/catalog/{app_id} # детали
|
||
GET /api/appstore/catalog/{app_id}/logo # логотип (публично)
|
||
POST /api/appstore/catalog/sync # ручная синхронизация (админ)
|
||
POST /api/appstore/apps/install # установка
|
||
GET /api/appstore/apps # список установленных
|
||
POST /api/appstore/apps/{id}/action/{start|stop|restart}
|
||
GET /api/appstore/apps/{id}/logs
|
||
POST /api/appstore/apps/{id}/update
|
||
POST /api/appstore/apps/{id}/rollback
|
||
POST /api/appstore/apps/reconcile
|
||
DELETE /api/appstore/apps/{id}
|
||
POST /api/appstore/golden-template # собрать золотой vztmpl для сервера
|
||
GET /api/appstore/golden-template/status?server_id=… # шаблон сервера + последняя операция сборки
|
||
```
|
||
|
||
---
|
||
|
||
## 🔗 Кластеры Proxmox
|
||
|
||
### Обзор
|
||
|
||
PVEmanager полностью поддерживает кластеры Proxmox, позволяя управлять несколькими узлами как единой сущностью.
|
||
|
||
### Добавление кластера
|
||
|
||
1. Перейдите в **Proxmox VE** → **Add Server**
|
||
2. Введите IP-адрес **любого узла** (напр., pve1)
|
||
3. Панель автоматически обнаружит все узлы кластера
|
||
4. Все узлы появятся в селекторах узлов
|
||
|
||
### Преимущества кластера
|
||
|
||
| Возможность | Standalone | Кластер |
|
||
|---------|------------|---------|
|
||
| Кол-во узлов | 1 | Несколько |
|
||
| Кросс-узловые шаблоны | ❌ | ✅ |
|
||
| Выбор целевого узла | ❌ | ✅ |
|
||
| Автоматический failover | ❌ | ✅ (Proxmox HA) |
|
||
|
||
### Создание кластера Proxmox
|
||
|
||
Если ваши узлы ещё не в кластере:
|
||
|
||
```bash
|
||
# На первом узле (pve1)
|
||
pvecm create my-cluster
|
||
|
||
# На других узлах (pve2, pve3 и т.д.)
|
||
pvecm add 10.10.10.11 # IP pve1
|
||
```
|
||
|
||
### Кросс-узловое развёртывание шаблонов
|
||
|
||
См. [Шаблоны ОС — Кросс-узловое развёртывание](#кросс-узловое-развёртывание-шаблонов-кластеры)
|
||
|
||
### Импорт уже существующего кластера
|
||
|
||
Если узлы уже объединены в кластер в обход панели (через `pvecm` или веб-интерфейс Proxmox), сначала добавьте каждый узел в панель как обычный standalone-сервер, затем воспользуйтесь **Кластер** → **Импорт**:
|
||
|
||
1. Выберите любой из уже добавленных узлов — панель прочитает с него `cluster/config/join` и определит реальное имя кластера и список узлов
|
||
2. Совпавшие по IP или hostname серверы панели будут отмечены автоматически; узлы, ещё не добавленные в панель, будут показаны в списке, но привязать их нельзя, пока они не добавлены как серверы
|
||
3. Подтвердите — панель только привяжет совпавшие записи серверов к группе кластера в своей БД; никакая команда `pvecm` не выполняется, реальный кластер не затрагивается
|
||
|
||
Это чисто БД-аналог **«Создать кластер»**/**«Присоединить ноду»**, которые выполняют настоящие операции `pvecm create`/`pvecm add` — используйте Импорт только когда узлы уже реально объединены в кластер.
|
||
|
||
---
|
||
|
||
## 📸 Снимки (Snapshots)
|
||
|
||
### Обзор
|
||
|
||
Снимки позволяют сохранять и восстанавливать состояние ВМ и контейнеров в любой момент времени.
|
||
|
||
### Создание снимка
|
||
|
||
1. Откройте детали ВМ или контейнера
|
||
2. Перейдите на вкладку **Snapshots**
|
||
3. Нажмите **Create Snapshot**
|
||
4. Введите имя и описание
|
||
5. Опционально включите состояние RAM (только QEMU-ВМ)
|
||
|
||
### Управление снимками
|
||
|
||
| Действие | Описание |
|
||
|--------|-------------|
|
||
| Create | Сохранить текущее состояние ВМ |
|
||
| Rollback | Восстановить к предыдущему состоянию снимка |
|
||
| Delete | Удалить существующий снимок |
|
||
|
||
> ⚠️ Откат отменит все изменения, сделанные после создания снимка!
|
||
|
||
### Очередь снимков
|
||
|
||
Операции со снимками обрабатываются через систему очереди задач. Прогресс отслеживается, результаты сохраняются для каждого элемента.
|
||
|
||
### Эндпоинты API
|
||
|
||
```bash
|
||
# Список снимков
|
||
GET /api/{server_id}/vm/{vmid}/snapshots?node={node}
|
||
|
||
# Создать снимок
|
||
POST /api/{server_id}/vm/{vmid}/snapshots?node={node}
|
||
|
||
# Удалить снимок
|
||
DELETE /api/{server_id}/vm/{vmid}/snapshots/{snapname}?node={node}
|
||
|
||
# Откатить к снимку
|
||
POST /api/{server_id}/vm/{vmid}/snapshots/{snapname}/rollback?node={node}
|
||
```
|
||
|
||
> Для LXC-контейнеров используйте `/container/` вместо `/vm/` в эндпоинтах выше.
|
||
|
||
---
|
||
|
||
## 💾 Резервные копии
|
||
|
||
### Обзор
|
||
|
||
PVEmanager предоставляет полный интерфейс управления резервными копиями на базе Proxmox `vzdump`. Можно создавать, просматривать, восстанавливать и удалять копии, а также настраивать автоматические запланированные задания.
|
||
|
||
### Управление хранилищами
|
||
|
||
Перед созданием копий убедитесь, что целевое хранилище настроено в Proxmox.
|
||
|
||
| Действие | Описание |
|
||
|--------|-------------|
|
||
| List storages | Просмотр всех хранилищ сервера |
|
||
| Add storage | Добавить пул хранилища (directory, NFS, CIFS и т.д.) |
|
||
| Edit storage | Изменить конфигурацию хранилища |
|
||
| Delete storage | Удалить хранилище из Proxmox |
|
||
|
||
### Создание резервной копии
|
||
|
||
1. Перейдите на страницу **Backups**
|
||
2. Выберите **сервер** и **узел**
|
||
3. Выберите **хранилище**, куда сохранить копию
|
||
4. Выберите **VM/контейнер** (по VMID)
|
||
5. Настройте опции:
|
||
- **Режим**: `snapshot` (по умолчанию), `suspend` или `stop`
|
||
- **Сжатие**: `zstd` (по умолчанию), `lzo`, `gzip`, `none`
|
||
6. Нажмите **Create Backup**
|
||
7. Возвращается UPID — используйте его для отслеживания прогресса
|
||
|
||
### Режимы резервного копирования
|
||
|
||
| Режим | Описание | Простой |
|
||
|------|-------------|----------|
|
||
| `snapshot` | Живой снимок (требует QEMU agent или LVM) | Нет |
|
||
| `suspend` | Приостановка ВМ на время копирования | Кратковременный |
|
||
| `stop` | Остановка ВМ, копирование, запуск | Полная остановка |
|
||
|
||
### Просмотр и удаление копий
|
||
|
||
- Просматривайте существующие копии по серверу, узлу и хранилищу
|
||
- Фильтруйте по VMID
|
||
- Удаляйте отдельные файлы копий
|
||
|
||
### Восстановление
|
||
|
||
1. Выберите файл копии из списка
|
||
2. Нажмите **Restore**
|
||
3. Укажите:
|
||
- **Целевое хранилище** для восстановления
|
||
- **Новый VMID** (опционально, оставить оригинал или назначить новый)
|
||
- **Start after restore** (опционально)
|
||
4. Восстановление выполняется как задача Proxmox (возвращается UPID для отслеживания)
|
||
|
||
> ⚠️ Восстановление в существующий VMID перезапишет его!
|
||
|
||
### Запланированные задания резервного копирования
|
||
|
||
Автоматизируйте регулярные копии с помощью cron-планирования.
|
||
|
||
#### Создание задания
|
||
|
||
```
|
||
Server: выбрать сервер Proxmox
|
||
Node: целевой узел
|
||
VMIDs: список через запятую (напр., 100,101,102)
|
||
Storage: назначение копии
|
||
Mode: snapshot / suspend / stop
|
||
Compress: zstd / lzo / gzip / none
|
||
Cron: стандартное 5-полевое cron-выражение
|
||
Enabled: переключатель вкл/выкл
|
||
```
|
||
|
||
#### Примеры cron-выражений
|
||
|
||
| Выражение | Значение |
|
||
|------------|---------|
|
||
| `0 2 * * *` | Каждый день в 02:00 |
|
||
| `0 3 * * 0` | Каждое воскресенье в 03:00 |
|
||
| `0 1 * * 1-5` | Будни в 01:00 |
|
||
| `30 4 1 * *` | Первый день каждого месяца в 04:30 |
|
||
|
||
#### Политики хранения
|
||
|
||
Настройте, сколько копий хранить автоматически:
|
||
|
||
| Параметр | Описание | По умолчанию |
|
||
|-----------|-------------|---------|
|
||
| `keep_last` | Хранить N последних копий | 3 |
|
||
| `keep_daily` | Одну в день в течение N дней | 7 |
|
||
| `keep_weekly` | Одну в неделю в течение N недель | 4 |
|
||
| `keep_monthly` | Одну в месяц в течение N месяцев | 6 |
|
||
|
||
#### Управление заданиями
|
||
|
||
- **List jobs** — все задания (админы видят все; пользователи — свои)
|
||
- **Enable/disable** — переключить без удаления
|
||
- **Edit** — изменить расписание, хранение, хранилище
|
||
- **Delete** — удалить задание и его запись в APScheduler
|
||
|
||
### Отслеживание задач
|
||
|
||
Каждая операция копирования (создание / восстановление / удаление) возвращает UPID Proxmox. Используйте его для опроса статуса и логов:
|
||
|
||
```bash
|
||
# Статус задачи
|
||
GET /api/backups/task/{server_id}/{node}/{upid}
|
||
```
|
||
|
||
---
|
||
|
||
## 🌐 IPAM
|
||
|
||
### Сети
|
||
|
||
Создавайте сети для организации IP-пространства:
|
||
|
||
```
|
||
Name: Production Network
|
||
CIDR: 192.168.1.0/24
|
||
VLAN: 100
|
||
Gateway: 192.168.1.1
|
||
DNS: 8.8.8.8, 8.8.4.4
|
||
Proxmox Server: выбрать сервер
|
||
Proxmox Node: выбрать узел (предотвращает назначение IP между серверами)
|
||
```
|
||
|
||
### Пулы IP
|
||
|
||
Пулы задают диапазоны для автоматического выделения:
|
||
|
||
```
|
||
Pool: Web Servers
|
||
Start: 192.168.1.10
|
||
End: 192.168.1.50
|
||
```
|
||
|
||
### Несколько адресов на инстанс
|
||
|
||
У гостя есть один **основной** адрес и любое количество дополнительных. Основной — это адрес из конфигурации интерфейса гостя (`net0` у LXC, `ipconfig0` у QEMU), именно он показывается в колонке IP списка инстансов. Дополнительные адреса навешиваются **внутри** гостя как alias на существующий интерфейс.
|
||
|
||
Управление — на вкладке **«Сеть»** инстанса, карточка **«IP-адреса»**:
|
||
|
||
| Действие | Что происходит |
|
||
|----------|----------------|
|
||
| Добавить IP | Выделяет адрес (следующий свободный в сети/пуле или введённый вручную) и применяет его к выбранному интерфейсу |
|
||
| Применить | Повторяет применение адреса, который раньше не удалось передать гостю |
|
||
| Сделать основным | Переносит флаг основного адреса; колонка IP и кэш инстанса следуют за ним |
|
||
| Освободить | Снимает адрес с гостя, затем освобождает его в IPAM |
|
||
|
||
Основной адрес из этой карточки не освобождается — он задаётся конфигурацией сетевого интерфейса и меняется через неё.
|
||
|
||
### Как применяется дополнительный адрес
|
||
|
||
Адрес поднимается командой `ip addr add`, сеть гостя при этом **не перезапускается**, поэтому работающий гость не теряет связь. Доставка использует тот же движок скриптов, что и раздел Scripts:
|
||
|
||
- **LXC** — `pct exec` по SSH к ноде (нужен пароль сервера либо SSH-ключ для `root@node`)
|
||
- **QEMU** — guest agent, в котором должен быть разрешён `guest-exec` (в некоторых образах он заблокирован в `/etc/sysconfig/qemu-ga` или `/etc/default/qemu-guest-agent`, см. [Установка Guest Agent](#установка-guest-agent); в образах встроенного каталога блокировка уже снята)
|
||
|
||
Proxmox пересоздаёт сетевую конфигурацию гостя при **каждом старте**, стирая всё, что было записано в родной стек. Чтобы адрес пережил перезагрузку, PVEmanager устанавливает небольшой oneshot systemd-юнит (`pvemanager-aliases.service`), который заново поднимает записанные адреса после `network-online.target`; каталог `/etc/systemd` Proxmox не трогает. Родной стек настраивается дополнительно, если он распознан — ifupdown, netplan, NetworkManager или sysconfig/network-scripts для RHEL-подобных гостей.
|
||
|
||
### Состояния адреса
|
||
|
||
| Состояние | Значение |
|
||
|-----------|----------|
|
||
| 🟢 applied | Поднят в госте и записан так, что вернётся после перезагрузки |
|
||
| 🟡 runtime_only | Поднят в госте, но сетевой стек не распознан и systemd нет — после перезагрузки исчезнет |
|
||
| 🟠 pending | Зарезервирован в IPAM, но гостю ещё не передан (гость выключен, нет guest agent, нет SSH к ноде) — нажмите **«Применить»** позже |
|
||
| 🔴 failed | Скрипт отработал с ошибкой; причина показана рядом с адресом |
|
||
|
||
Адрес резервируется в IPAM в любом случае, даже если применить его не удалось, — чтобы тем временем он не достался кому-то ещё.
|
||
|
||
### Статус IP
|
||
|
||
| Статус | Описание |
|
||
|--------|-------------|
|
||
| 🟢 Available | Свободен |
|
||
| 🔵 Allocated | Назначен ВМ |
|
||
| 🟠 Reserved | Зарезервирован |
|
||
|
||
---
|
||
|
||
## 💻 Удалённое выполнение команд
|
||
|
||
### Требования
|
||
|
||
- **QEMU Guest Agent** установлен и запущен в ВМ
|
||
- ВМ должна быть запущена
|
||
|
||
### Установка Guest Agent
|
||
|
||
**Debian/Ubuntu:**
|
||
```bash
|
||
apt install qemu-guest-agent
|
||
systemctl enable --now qemu-guest-agent
|
||
```
|
||
|
||
**CentOS/RHEL/AlmaLinux/Rocky/Fedora:**
|
||
```bash
|
||
dnf install qemu-guest-agent
|
||
systemctl enable --now qemu-guest-agent
|
||
```
|
||
|
||
В этих дистрибутивах агент по умолчанию запрещает `guest-exec` — панель получает `The command guest-exec has been disabled for this instance`, и выполнение команд, выдача дополнительных IP и расширение ФС не работают. Разблокировать:
|
||
|
||
```bash
|
||
sed -i -e 's/^FILTER_RPC_ARGS=.*/FILTER_RPC_ARGS=/' -e 's/^BLACKLIST_RPC=.*/BLACKLIST_RPC=/' -e 's/^BLOCK_RPCS=.*/BLOCK_RPCS=/' /etc/sysconfig/qemu-ga
|
||
systemctl restart qemu-guest-agent
|
||
```
|
||
|
||
Разметка `/etc/sysconfig/qemu-ga` менялась от версии к версии, поэтому команда чистит все три варианта: `FILTER_RPC_ARGS` (актуальные пакеты — allow-list, в котором `guest-exec` просто отсутствует), `BLOCK_RPCS` (qemu-ga 8.1+) и `BLACKLIST_RPC` (до 8.1). Пустое значение = агент без ограничений, как в Debian/Ubuntu, где фильтра нет вовсе; отсутствующие строки sed просто не найдёт.
|
||
|
||
**Windows:**
|
||
Скачайте [virtio-win drivers](https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/)
|
||
|
||
### Использование
|
||
|
||
1. Откройте детали ВМ
|
||
2. Перейдите на вкладку **Commands**
|
||
3. Введите команду или выберите из быстрых команд
|
||
4. Нажмите **Execute**
|
||
|
||
### Быстрые команды
|
||
|
||
| Команда | Описание |
|
||
|---------|-------------|
|
||
| `df -h` | Использование диска |
|
||
| `free -h` | Использование памяти |
|
||
| `uptime` | Время работы |
|
||
| `ps aux` | Список процессов |
|
||
| `systemctl status` | Статус служб |
|
||
|
||
### Ограничения
|
||
|
||
- Таймаут: 30 секунд
|
||
- Интерактивные команды не поддерживаются
|
||
- Требуется Guest Agent
|
||
|
||
---
|
||
|
||
## 📊 Мониторинг
|
||
|
||
### Метрики в реальном времени
|
||
|
||
- **CPU**: суммарная нагрузка + по ядрам
|
||
- **RAM**: использовано/всего
|
||
- **Диск**: использовано/всего + I/O (карточки по каждому диску на вкладке Overview)
|
||
- **Сеть**: входящий/исходящий трафик (скорости в байт/с)
|
||
- **Disk IOPS**: скорости чтения/записи по каждому диску через QEMU guest agent (`get_vm_fsinfo`)
|
||
- **Скорости сетевого I/O**: живые байт/с, вычисляемые из накопительных счётчиков в `metrics_broadcaster`
|
||
|
||
#### Гранулярность данных
|
||
|
||
| Источник | Гранулярность | Используется для |
|
||
|--------|-------------|---------|
|
||
| `cluster/resources` (pvestatd) | 10 с | Обзор узлов и хранилищ |
|
||
| `status/current` | 1 с | Метрики запущенных ВМ в реальном времени |
|
||
|
||
Все запущенные ВМ опрашиваются через `status/current` с частотой 1 с при ограниченной конкурентности. Результаты транслируются по WebSocket.
|
||
|
||
#### Где отображаются метрики
|
||
|
||
| Расположение | Показываемые данные |
|
||
|----------|-----------|
|
||
| Инстанс → вкладка Overview | Карточки заполнения по дискам, карточка Network I/O, карточка Disk I/O-rate |
|
||
| Список инстансов | Столбцы Net I/O и Disk I/O; Disk% для LXC |
|
||
| Список top-loaded на дашборде | Оверлей метрик CPU, RAM, Disk, Net |
|
||
|
||
### Периоды графиков
|
||
|
||
- Час
|
||
- День
|
||
- Неделя
|
||
- Месяц
|
||
|
||
### Оповещения
|
||
|
||
Пороговые значения для уведомлений:
|
||
|
||
| Метрика | Warning | Critical |
|
||
|--------|---------|----------|
|
||
| CPU | 80% | 90% |
|
||
| RAM | 85% | 95% |
|
||
| Диск | 90% | 95% |
|
||
|
||
---
|
||
|
||
## 🔒 Безопасность
|
||
|
||
### Обзор
|
||
|
||
PVEmanager включает комплексные функции безопасности для защиты вашей инфраструктуры.
|
||
|
||
### RBAC v2 — контроль доступа на основе ролей
|
||
|
||
> **Это тот раздел, который стоит прочитать, если RBAC кажется запутанным.** Здесь модель разобрана от начала до конца: что такое право (permission), как реально проверяется запрос, что умеет каждая встроенная роль и — самое важное — как реализовано «пользователь видит только свои ВМ» (это **отдельный** механизм от RBAC, который легко настроить неправильно). Источники истины в бэкенде: `backend/app/rbac/permissions.py` (каталог прав), `backend/app/rbac/engine.py` (логика проверки), `backend/app/rbac/migration.py` (роли по умолчанию).
|
||
|
||
#### Ментальная модель в одном абзаце
|
||
|
||
У **пользователя** ровно одна **роль**. Роль — это просто именованная JSON-карта **прав** → `true`/`false` (напр., `{"vm:view": true, "vm:delete": false}`). Каждый защищённый эндпоинт API объявляет нужное ему право (напр., «нужно `vm:create`»). При каждом запросе **Permission Engine** смотрит на карту прав роли вызывающего и отвечает да/нет. Нет ни ACL для отдельных ресурсов, ни рабочих «scope» у прав — право либо выдано роли, либо нет. Единственное кажущееся исключение — «пользователи видят только свои инстансы» — вообще **не** является правом: это отдельный фильтр по владельцу, описанный в конце раздела.
|
||
|
||
#### Формат права
|
||
|
||
Каждое право — атомарная строка:
|
||
|
||
```
|
||
resource:action
|
||
```
|
||
|
||
- **`resource`** — *над чем* вы действуете (`vm`, `backup`, `user`, …).
|
||
- **`action`** — *что вы делаете* (`view`, `create`, `delete`, …).
|
||
|
||
Примеры: `vm:view` (видеть ВМ), `server:create` (добавить сервер Proxmox), `log:export` (скачать логи аудита), `role:manage` (полное администрирование ролей).
|
||
|
||
> **Про `:scope`.** Технически dataclass права поддерживает третий сегмент `:scope`, но **ни одно встроенное право его не использует** — все реальные права глобальные (`resource:action`). Игнорируйте scope при проектировании ролей; изоляция арендаторов реализована через владельца, а не через scope `:own`. (В старых версиях этой вики документировались вымышленные коды вроде `vms:view:own` — их никогда не было в коде, и они удалены.)
|
||
|
||
#### Как на самом деле работает проверка права (движок)
|
||
|
||
Когда эндпоинт спрашивает «есть ли у пользователя `X:Y`?», `PermissionEngine.has_permission` применяет правила **по порядку** и возвращает `true` на первом совпадении:
|
||
|
||
1. **Обход для админа.** Если пользователь — администратор (`is_admin` или роль с именем `admin`), ответ всегда **да** — админы неявно держат все права и никогда не блокируются.
|
||
2. **Прямая выдача.** Точный код присутствует и равен `true` в карте роли (`vm:create` есть в роли → да).
|
||
3. **Wildcard-выдача.** Роль держит `resource:*` (напр., `vm:*` даёт *все* действия `vm:`). Wildcard не используется встроенными ролями, но вы можете добавить его в кастомные роли.
|
||
4. **`manage` подразумевает частые действия.** Если роль держит `resource:manage`, движок также выдаёт эти действия для ресурса: **`view`, `list`, `update`, `start`, `stop`, `restart`**. Так `vm:manage` в одиночку позволяет смотреть/редактировать/управлять питанием ВМ, не перечисляя эти действия отдельно. ⚠️ Учтите: `manage` **не** подразумевает `create` или `delete` — выдавайте их явно.
|
||
|
||
Если ни одно правило не совпало, доступ отклоняется с **HTTP 403 `Permission denied: X:Y`**.
|
||
|
||
> **Точки применения.** Эндпоинты защищают доступ через FastAPI-зависимость `PermissionChecker` (`Depends(PermissionChecker("vm:create"))`) или inline-вызов `require_permission(user, "vm:create")`. Фронтенд независимо скрывает пункты меню, на которые у пользователя нет прав (см. таблицу соответствия ниже), но реальной границей безопасности является именно проверка на бэкенде.
|
||
|
||
#### `requires` — зависимости прав
|
||
|
||
Многие права объявляют предпосылки (поле `requires` в `permissions.py`). Они выражают логические зависимости — напр., `vm:create` `requires` `vm:view` + `template:view`; `vm:execute` `requires` `vm:console`.
|
||
|
||
> **Важно:** `requires` — это **документация / подсказка для UI**, а **не** проверка в рантайме — движок не выдаёт предпосылки автоматически. Собирая кастомную роль, отмечайте предпосылки сами, иначе функция может работать наполовину (напр., пользователь, который может `vm:create`, но не имеет `vm:view`, не увидит только что созданную ВМ).
|
||
|
||
#### Полный каталог прав
|
||
|
||
Сгруппировано по ресурсам. «Подразумевается `manage`» означает, что движок выдаёт это бесплатно, когда роль держит `<resource>:manage` (правило 4 выше).
|
||
|
||
**Дашборд**
|
||
|
||
| Право | Что открывает |
|
||
|---|---|
|
||
| `dashboard:view` | Доступ к странице Дашборда и обзорной статистике |
|
||
|
||
**Серверы Proxmox и кластер** (`server`, `cluster`)
|
||
|
||
| Право | Что открывает |
|
||
|---|---|
|
||
| `server:view` | Видеть список серверов/узлов и статус |
|
||
| `server:create` | Добавить новый сервер Proxmox |
|
||
| `server:update` | Редактировать параметры подключения сервера |
|
||
| `server:delete` | Удалить сервер Proxmox |
|
||
| `server:manage` | Полное управление сервером, включая кластерные операции (требует `server:view`) |
|
||
| `cluster:manage` | Создание кластеров, присоединение/исключение узлов (требует `server:view`) |
|
||
|
||
**Виртуальные машины** (`vm`)
|
||
|
||
| Право | Что открывает |
|
||
|---|---|
|
||
| `vm:view` | Видеть ВМ (с учётом фильтра владельца — см. ниже) |
|
||
| `vm:create` | Создавать ВМ (требует `vm:view`, `template:view`) |
|
||
| `vm:update` | Менять конфигурацию ВМ (CPU/RAM/диск) |
|
||
| `vm:delete` | Удалять ВМ |
|
||
| `vm:start` / `vm:stop` / `vm:restart` | Действия питания |
|
||
| `vm:console` | Консоль noVNC / xterm.js |
|
||
| `vm:migrate` | Миграция между узлами одного кластера |
|
||
| `vm:remote_migrate` | Миграция в *другой* зарегистрированный кластер (требует `vm:migrate`) |
|
||
| `vm:execute` | Выполнять команды через QEMU guest agent (требует `vm:console`) |
|
||
| `vm:manage` | Полное управление ВМ **и глобальный флаг «видеть все инстансы»** (см. раздел про изоляцию) |
|
||
|
||
**LXC-контейнеры** (`lxc`) — та же структура, что у VM: `view`, `create`, `update`, `delete`, `start`, `stop`, `restart`, `console`, `migrate`, `remote_migrate`. (Отдельного `lxc:manage` нет; листинг/питание контейнеров управляется действиями `lxc:*` и тем же фильтром владельца, что и ВМ.)
|
||
|
||
**Шаблоны и образы** (`template`)
|
||
|
||
| Право | Что открывает |
|
||
|---|---|
|
||
| `template:view` | Просматривать шаблоны ОС |
|
||
| `template:create` / `template:update` / `template:delete` | Управлять записями шаблонов |
|
||
| `template:manage` | Полное управление шаблонами, включая страницу **Images** (скачивание облачных образов) |
|
||
|
||
**Хранилище** (`storage`): `storage:view`, `storage:manage`.
|
||
**Резервные копии** (`backup`): `backup:view`, `backup:create`, `backup:restore`, `backup:delete`, `backup:manage` (хранилища + запланированные задания).
|
||
**IPAM** (`ipam`): `ipam:view`, `ipam:manage`.
|
||
**Сети** (`network`): `network:view`, `network:manage` (интерфейсы узла + зоны/vnet/подсети SDN).
|
||
**Firewall** (`firewall`): `firewall:view`, `firewall:manage` (правила датацентра/узла/ВМ, группы, IP-наборы).
|
||
**Администрирование узла** (`node`): `node:view`, `node:manage` (службы systemd, APT), `node:upgrade` (apt dist-upgrade), `node:power` (перезагрузка/выключение физического узла).
|
||
**Пулы ресурсов** (`pool`): `pool:view`, `pool:manage`.
|
||
**PVE-доступ** (`access`): `access:view`, `access:manage` (realm-ы аутентификации и API-токены Proxmox).
|
||
**App Store** (`app`): `app:view` (каталог + Мои приложения), `app:install`, `app:manage` (синхронизация, обновление, откат, удаление).
|
||
**Скрипты** (`script`): `script:view`, `script:execute`, `script:manage` (редактирование скриптов и git-источников).
|
||
|
||
**Пользователи, квоты и роли** (`user`, `quota`, `role`)
|
||
|
||
| Право | Что открывает |
|
||
|---|---|
|
||
| `user:view` | Видеть список пользователей |
|
||
| `user:create` / `user:update` / `user:delete` | Управлять учётными записями |
|
||
| `user:manage` | Полное администрирование пользователей, включая управление SSH-ключами **других** пользователей |
|
||
| `quota:view` / `quota:manage` | Читать / задавать квоты ресурсов пользователей (требует `user:view`) |
|
||
| `role:view` | Видеть роли и их права |
|
||
| `role:create` / `role:update` / `role:delete` | Управлять ролями |
|
||
| `role:manage` | Полное администрирование ролей, включая назначение (требует `role:view`, `user:view`) |
|
||
|
||
**Логи** (`log`): `log:view`, `log:export`, `log:delete`.
|
||
**Настройки** (`setting`): `setting:view`, `setting:update` (настройки панели), `setting:manage` (безопасность и расширенные настройки). Эти права относятся **только к настройкам панели** — собственная учётная запись пользователя (профиль, пароль, 2FA, SSH-ключи, предпочтения уведомлений) живёт на `/profile`, ограничена самим пользователем и не требует никаких прав.
|
||
**Уведомления** (`notification`): `notification:view`, `notification:manage`.
|
||
|
||
> **Делегированное редактирование ролей.** Не-админ с `role:manage` может выдавать только те права, которыми **владеет сам** (`can_assign_permission` / `validate_role_permissions`). Это предотвращает эскалацию привилегий — нельзя раздать доступ, которого у вас нет. Админы освобождены от этого и могут выдавать что угодно.
|
||
|
||
#### Какое право открывает какую страницу в меню
|
||
|
||
Фронтенд (`frontend/src/lib/nav-items.ts`) скрывает пункт меню, если пользователь не админ и не держит указанное право. Пункты **без** права — **только для админа**. То же право защищает и сам маршрут (`RequirePermission` в `frontend/src/components/shared/route-guards.tsx`), поэтому скрытую страницу нельзя открыть вводом URL — при отказе пользователя перебрасывает на первую доступную ему страницу.
|
||
|
||
| Пункт меню | Требуемое право |
|
||
|---|---|
|
||
| Dashboard | `dashboard:view` |
|
||
| Instances | `vm:view` |
|
||
| Nodes | `server:view` |
|
||
| Cluster | `cluster:manage` |
|
||
| Templates | `template:view` |
|
||
| Images | `template:manage` |
|
||
| Backups | `backup:view` |
|
||
| Tasks | `vm:view` |
|
||
| App Store / My Apps | `app:view` |
|
||
| Scripts | `script:view` |
|
||
| IPAM | `ipam:view` |
|
||
| Networks | `server:manage` |
|
||
| Users | `user:view` |
|
||
| Workspaces | *(только админ)* |
|
||
| Logs | `log:view` |
|
||
| Settings (настройки панели) | `setting:view` |
|
||
| Профиль (меню пользователя, не сайдбар) | *(без права — любой вошедший)* |
|
||
|
||
#### Роли по умолчанию (встроенные)
|
||
|
||
Четыре роли пересоздаются/обновляются при каждом старте функцией `ensure_default_roles_new_format`. Это системные (`is_system`) роли. Логика посева **только добавляет отсутствующие ключи прав** — она никогда не перезаписывает ключи, которые админ уже переключил в UI, — поэтому ваши правки этих ролей переживают обновления. Новые права, добавленные при обновлении версии, также **добавляются (backfill)** к кастомным ролям, которые уже держат соответствующее «зонтичное» право (`backfill_granular_permissions`), поэтому кастомная роль на базе `server:manage` автоматически получает новые ключи `node:*` / `network:*` вместо молчаливой потери доступа.
|
||
|
||
| Роль | Назначение | Что может делать |
|
||
|------|--------------|----------------|
|
||
| **admin** | Администратор платформы | Всё. Держит каждое право *и* обход `is_admin` — видит все серверы, все инстансы (независимо от владельца), всех пользователей, настройки, безопасность. |
|
||
| **moderator** | Оператор без прав админа | Смотреть дашборд/серверы; **создавать + управлять питанием + консоль** ВМ и LXC; смотреть шаблоны/хранилище/firewall/сеть/узел/пулы/копии/IPAM/пользователей/логи; создавать копии; экспортировать логи; управлять уведомлениями. **Нет** удаления, изменения настроек, управления пользователями/ролями. Заметьте: без `vm:manage` модератор всё равно подчиняется фильтру владельца (см. ниже). |
|
||
| **user** | Стандартный арендатор (стиль VPS) | Смотреть + **start/stop/restart/console** для **своих** ВМ и LXC; смотреть шаблоны/хранилище/firewall/сеть/узел/пулы/IPAM; управлять своими уведомлениями. Собственный профиль, SSH-ключи и квота живут на `/profile` и не требуют прав, поэтому у роли намеренно **нет** `setting:view` (он открыл бы страницу настроек панели). **Нет** create/delete по умолчанию, **нет** дашборда. Ограничен своими инстансами, так как не имеет `vm:manage`. |
|
||
| **demo** | Read-only витрина | Только просмотр: дашборд, серверы, ВМ, LXC, шаблоны, хранилище, firewall, сеть, узел, пулы, IPAM. Ни действий питания, ни записи. |
|
||
|
||
> Точный JSON каждой роли лежит в `NEW_DEFAULT_ROLES` в `backend/app/rbac/migration.py` — сверяйтесь с ним, если нужен побайтовый набор прав.
|
||
|
||
#### Управление ролями в UI
|
||
|
||
1. Откройте **Пользователи** (нужно `role:view`; для редактирования — `role:manage` или админ).
|
||
2. Перейдите на вкладку **Roles** → **New Role** или отредактируйте существующую.
|
||
3. Права сгруппированы по категориям (Virtual Machines, Backups, User Management, …). Отметьте нужные чекбоксы.
|
||
4. Не забудьте отметить и **предпосылки** (`requires`) — движок не включает их автоматически.
|
||
5. Назначьте роль пользователю в диалоге редактирования пользователя.
|
||
|
||
Системные роли (admin/moderator/user/demo) удалить нельзя, но их наборы прав можно настраивать (ваши изменения сохраняются при обновлениях).
|
||
|
||
#### Legacy-формат прав
|
||
|
||
Старые релизы использовали точечный формат (`vms.view`, `proxmox.manage`). Он отображается на новый двоеточный формат через `LEGACY_PERMISSION_MAP` и конвертируется **один раз** в базе данных при старте, поэтому трансляция в рантайме не нужна. Вы всё ещё можете вписать legacy-код в кастомную роль — он разрешается прозрачно, — но новые роли должны использовать форму `resource:action`.
|
||
|
||
---
|
||
|
||
### Изоляция пользователей — «каждый видит только свои инстансы»
|
||
|
||
Это функция, которую чаще всего путают с RBAC. **Это не право.** Это отдельный фильтр по владельцу, наложенный *поверх* прав `vm:*`/`lxc:*`. Понимание этого разделения — ключ к правильной настройке арендаторов.
|
||
|
||
#### Правило
|
||
|
||
| Вызывающий | Видит / управляет |
|
||
|---|---|
|
||
| Админ или роль с именем `admin` | **Всеми** инстансами |
|
||
| Любая роль, держащая **`vm:manage`** | **Всеми** инстансами |
|
||
| Все остальные (включая стоковую роль `user`) | **Только** инстансами, которыми **владеет** (`owner_id == user.id`) |
|
||
|
||
Решение принимает `can_view_all_instances` в `backend/app/api/proxmox/_helpers.py`. Обратите внимание: ключ «видеть всё» — это **`vm:manage`**, а **не** `vm:view`. Стоковая роль `user` намеренно несёт только `vm:view`, чтобы страница Instances вообще работала — `vm:view` сам по себе никогда не раскрывает ВМ других арендаторов.
|
||
|
||
> ⚠️ **Самая частая ошибка конфигурации:** выдать `vm:manage` роли `user` (или кастомной «арендаторской» роли), чтобы «дать им управлять своими ВМ». Это включает глобальный обзор, и каждый пользователь внезапно видит **все** ВМ в панели. Для арендаторов выдавайте гранулярные действия (`vm:update`, `vm:delete`, `vm:start`, …) вместо `vm:manage`. Резервируйте `vm:manage` для операторов/админов, которые *должны* видеть всё.
|
||
|
||
#### Как владение применяется везде
|
||
|
||
Владение проверяется не только в списке инстансов, но и на каждой поверхности, доступной непривилегированному пользователю:
|
||
|
||
- **Список инстансов и действия над одним инстансом** — `check_vm_access` / `require_vm_access` проверяют `owner_id` перед любой операцией view/питание/консоль/снимок/копия/удаление.
|
||
- **Эндпоинты живых ресурсов** — дашборд (`/api/resources/all`) и страница узла/сервера (`/api/{server_id}/resources`) вызывают `get_owned_vmids` и фильтруют живой листинг Proxmox до принадлежащих VMID, поэтому пользователь только с `server:view` не может перечислить ВМ других владельцев через страницу узла.
|
||
|
||
#### Назначение владельца
|
||
|
||
1. **Автоматически** — когда пользователь развёртывает VM/LXC, он становится её `owner_id`.
|
||
2. **Вручную (админ)** — откройте инстанс → кнопка **Owner** → выберите пользователя → Save. REST API см. в [Владелец ВМ / LXC](#-владелец-вм--lxc).
|
||
|
||
Инстансы, синхронизированные из Proxmox до появления владения, имеют `owner_id = NULL` (видны только привилегированным пользователям). Массово назначить им владельца:
|
||
|
||
```bash
|
||
docker compose exec app python assign_instances_owner.py
|
||
```
|
||
|
||
#### RBAC vs Workspaces vs назначение серверов vs владение
|
||
|
||
Эти четыре механизма складываются — не-админ должен пройти **все** применимые фильтры:
|
||
|
||
| Слой | На какой вопрос отвечает | Где настраивается |
|
||
|---|---|---|
|
||
| **Роль RBAC** | *Какие действия* пользователь вообще может выполнять? | Пользователи → Roles |
|
||
| **Workspaces** | *Какие серверы* пользователю разрешено видеть? | [Рабочие области](#-рабочие-области-workspaces) |
|
||
| **Назначение серверов** | *Какие конкретные серверы* внутри этих областей? | [Назначение серверов пользователю](#-назначение-серверов-пользователю) |
|
||
| **Владение** | *Какие отдельные ВМ/LXC* (если нет `vm:manage`/админа)? | [Владелец ВМ / LXC](#-владелец-вм--lxc) |
|
||
|
||
---
|
||
|
||
### Снимки (в контексте безопасности)
|
||
|
||
Снимки позволяют сохранять и восстанавливать состояние ВМ и контейнеров.
|
||
|
||
#### Снимки ВМ
|
||
|
||
```bash
|
||
# Список снимков
|
||
GET /api/{server_id}/vm/{vmid}/snapshots?node={node}
|
||
|
||
# Создать снимок
|
||
POST /api/{server_id}/vm/{vmid}/snapshots?node={node}
|
||
{
|
||
"snapname": "before-update",
|
||
"description": "Before system update",
|
||
"vmstate": false # Включить состояние RAM (опционально)
|
||
}
|
||
|
||
# Удалить снимок
|
||
DELETE /api/{server_id}/vm/{vmid}/snapshots/{snapname}?node={node}
|
||
|
||
# Откатить к снимку
|
||
POST /api/{server_id}/vm/{vmid}/snapshots/{snapname}/rollback?node={node}&start=false
|
||
```
|
||
|
||
#### Снимки контейнеров
|
||
|
||
Те же эндпоинты, но используйте `/container/` вместо `/vm/`.
|
||
|
||
### SDN (Software Defined Networking)
|
||
|
||
Управление зонами SDN и виртуальными сетями Proxmox.
|
||
|
||
#### Проверка доступности SDN
|
||
|
||
```bash
|
||
GET /api/servers/{server_id}/sdn/status
|
||
```
|
||
|
||
Возвращает:
|
||
```json
|
||
{
|
||
"server_id": 1,
|
||
"sdn_available": true,
|
||
"pending_changes": false
|
||
}
|
||
```
|
||
|
||
#### Типы зон
|
||
|
||
| Тип | Описание |
|
||
|------|-------------|
|
||
| `simple` | Базовая изолированная сеть |
|
||
| `vlan` | Разделение на основе VLAN |
|
||
| `vxlan` | Overlay-сеть VXLAN |
|
||
| `evpn` | EVPN/VXLAN с BGP |
|
||
|
||
#### Эндпоинты SDN API
|
||
|
||
```bash
|
||
# Список зон
|
||
GET /api/servers/{server_id}/sdn/zones
|
||
|
||
# Создать зону
|
||
POST /api/servers/{server_id}/sdn/zones
|
||
{
|
||
"zone": "myzone",
|
||
"type": "simple"
|
||
}
|
||
|
||
# Обновить зону
|
||
PUT /api/servers/{server_id}/sdn/zones/{zone}
|
||
{
|
||
"mtu": 1500,
|
||
"dns": "8.8.8.8"
|
||
}
|
||
|
||
# Список VNet
|
||
GET /api/servers/{server_id}/sdn/vnets
|
||
|
||
# Создать VNet
|
||
POST /api/servers/{server_id}/sdn/vnets
|
||
{
|
||
"vnet": "vnet1",
|
||
"zone": "myzone",
|
||
"alias": "Production Network"
|
||
}
|
||
|
||
# Обновить VNet
|
||
PUT /api/servers/{server_id}/sdn/vnets/{vnet}
|
||
{
|
||
"alias": "Updated Alias",
|
||
"tag": 100
|
||
}
|
||
|
||
# Создать подсеть (с опциональным авто-созданием IPAM)
|
||
POST /api/servers/{server_id}/sdn/vnets/{vnet}/subnets
|
||
{
|
||
"subnet": "10.0.0.0/24",
|
||
"gateway": "10.0.0.1",
|
||
"snat": true,
|
||
"create_ipam_network": true
|
||
}
|
||
|
||
# Удалить подсеть (опционально удалить связанную сеть IPAM)
|
||
DELETE /api/servers/{server_id}/sdn/vnets/{vnet}/subnets/{subnet_cidr}?delete_ipam_network=true
|
||
|
||
# Применить изменения (обязательно после модификаций)
|
||
POST /api/servers/{server_id}/sdn/apply
|
||
```
|
||
|
||
### Сетевые интерфейсы узлов
|
||
|
||
Управление сетевыми интерфейсами (мосты, bond-ы, VLAN) напрямую на узлах Proxmox.
|
||
|
||
#### Доступ к странице «Сети»
|
||
|
||
1. Откройте **Networks** из бокового меню (требует право `server:manage`; записи в SDN/интерфейсы требуют `network:manage`)
|
||
2. Выберите **сервер** из выпадающего списка
|
||
3. Страница показывает две вкладки: **SDN** и **Node Interfaces**
|
||
|
||
#### Управление интерфейсами узла
|
||
|
||
| Действие | Описание |
|
||
|--------|-------------|
|
||
| List interfaces | Просмотр всех интерфейсов на выбранном узле |
|
||
| Create interface | Создать мост, bond, VLAN или alias |
|
||
| Edit interface | Изменить IP, маску, шлюз, порты и т.д. |
|
||
| Delete interface | Удалить конфигурацию интерфейса |
|
||
| Apply config | Активировать ожидающие изменения |
|
||
| Revert config | Откатить к рабочей конфигурации |
|
||
|
||
> ⚠️ Всегда **применяйте** изменения после создания или редактирования интерфейсов. Изменения находятся в staging до применения.
|
||
|
||
#### Эндпоинты Node Network API
|
||
|
||
```bash
|
||
# Список узлов сервера
|
||
GET /api/servers/{server_id}/nodes
|
||
|
||
# Список интерфейсов узла
|
||
GET /proxmox/api/servers/{server_id}/nodes/{node}/networks
|
||
|
||
# Детали интерфейса
|
||
GET /proxmox/api/servers/{server_id}/nodes/{node}/networks/{iface}
|
||
|
||
# Создать интерфейс
|
||
POST /proxmox/api/servers/{server_id}/nodes/{node}/networks
|
||
{
|
||
"iface": "vmbr1",
|
||
"type": "bridge",
|
||
"address": "10.0.0.1",
|
||
"netmask": "255.255.255.0",
|
||
"bridge_ports": "ens4",
|
||
"autostart": true
|
||
}
|
||
|
||
# Обновить интерфейс
|
||
PUT /proxmox/api/servers/{server_id}/nodes/{node}/networks/{iface}
|
||
{
|
||
"address": "10.0.0.2"
|
||
}
|
||
|
||
# Удалить интерфейс
|
||
DELETE /proxmox/api/servers/{server_id}/nodes/{node}/networks/{iface}
|
||
|
||
# Применить ожидающую конфигурацию сети
|
||
PUT /proxmox/api/servers/{server_id}/nodes/{node}/networks/apply
|
||
|
||
# Откатить ожидающие изменения
|
||
DELETE /proxmox/api/servers/{server_id}/nodes/{node}/networks/revert
|
||
```
|
||
|
||
#### Совместимость со старым форматом
|
||
|
||
Старый формат прав (`vms.view`, `proxmox.manage`) по-прежнему поддерживается и автоматически конвертируется в новый формат.
|
||
|
||
### Блокировка IP
|
||
|
||
Автоматическая и ручная блокировка IP защищает от brute-force атак.
|
||
|
||
#### Автоматическая блокировка
|
||
|
||
Когда пользователь несколько раз не может войти с одного IP:
|
||
1. После порога (по умолчанию: 10) неудачных попыток
|
||
2. IP блокируется на настроенное время (по умолчанию: 60 минут)
|
||
3. Блокировка может быть временной или постоянной
|
||
|
||
#### Ручная блокировка
|
||
|
||
Администраторы могут вручную блокировать IP:
|
||
- Блокировка с указанием причины
|
||
- Задать длительность или сделать постоянной
|
||
- Просмотр списка заблокированных IP
|
||
- Разблокировка по мере необходимости
|
||
|
||
### Управление сессиями
|
||
|
||
Отслеживание и контроль активных пользовательских сессий.
|
||
|
||
| Функция | Описание |
|
||
|---------|-------------|
|
||
| Active Sessions | Просмотр всех вошедших пользователей |
|
||
| Device Info | Определение браузера и устройства |
|
||
| IP Tracking | Логирование IP-адреса сессии |
|
||
| Single Session | Опция разрешить только одну сессию на пользователя |
|
||
| Force Logout | Завершить любую сессию |
|
||
|
||
### Защита входа
|
||
|
||
| Настройка | По умолчанию | Описание |
|
||
|---------|---------|-------------|
|
||
| Max Login Attempts | 5 | Попыток до блокировки аккаунта |
|
||
| Lockout Duration | 30 мин | Как долго аккаунт заблокирован |
|
||
| IP Block Threshold | 10 | Неудачных попыток до блокировки IP |
|
||
| IP Block Duration | 60 мин | Как долго IP заблокирован |
|
||
|
||
### Настройки безопасности
|
||
|
||
Доступ через **Настройки → Безопасность**:
|
||
|
||
| Настройка | По умолчанию | Описание |
|
||
|---------|---------|-------------|
|
||
| Session Timeout | 60 мин | Авто-выход после бездействия |
|
||
| Single Session | Выкл | Разрешить только одну сессию на пользователя |
|
||
| Password Min Length | 8 | Минимум символов пароля |
|
||
| Require Uppercase | Да | Пароль должен содержать заглавные |
|
||
| Require Lowercase | Да | Пароль должен содержать строчные |
|
||
| Require Numbers | Да | Пароль должен содержать цифры |
|
||
| Require Special | Нет | Пароль должен содержать спецсимволы |
|
||
| Password Expiry | 0 (никогда) | Дней до истечения пароля |
|
||
| API Rate Limit | 60/мин | Запросов API в минуту |
|
||
|
||
### Лучшие практики
|
||
|
||
1. **Смените пароли по умолчанию** сразу после установки
|
||
2. **Включите SSL/HTTPS** в продакшне
|
||
3. **Используйте надёжные пароли** с требованиями к сложности
|
||
4. **Мониторьте попытки входа** на предмет подозрительной активности
|
||
5. **Настройте файрвол** для ограничения доступа к панели
|
||
6. **Регулярно обновляйтесь** для получения патчей безопасности
|
||
|
||
---
|
||
|
||
## 📝 Логи и аудит
|
||
|
||
### Обзор
|
||
|
||
Страница **Логи** (`/logs` в боковом меню) даёт админам полный поисковый обзор таблицы `audit_logs` панели. Она дополняет ленту активности дашборда более глубокой фильтрацией, пагинацией и агрегированной статистикой за 24 часа.
|
||
|
||
### Макет страницы
|
||
|
||
1. **Карточки статистики (окно 24ч)** — всего событий, число ошибок, неудачные входы, число строк на текущей странице
|
||
2. **Фильтры** — свободный поиск (по сообщению и имени пользователя) и выпадающий список уровней из `GET /logs/api/levels`
|
||
3. **Таблица логов** — время, бейдж уровня, категория, имя пользователя, сообщение
|
||
4. **Пагинация** — управляется API (`page`, `limit`)
|
||
|
||
### Уровни логов
|
||
|
||
| Уровень | Цвет | Описание |
|
||
|-------|-------|-------------|
|
||
| `INFO` | 🔵 Синий | Информационные события |
|
||
| `SUCCESS` | 🟢 Зелёный | Успешные операции |
|
||
| `WARNING` | 🟡 Жёлтый | Некритические предупреждения |
|
||
| `ERROR` | 🔴 Красный | Сбои |
|
||
| `CRITICAL` | 🟣 Фиолетовый | Критические события безопасности / системы |
|
||
|
||
### Справочник API
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|--------|----------|-------------|
|
||
| `GET` | `/logs/api/logs` | Список записей аудита (с пагинацией) |
|
||
| `GET` | `/logs/api/stats` | Агрегированная статистика (по умолчанию 24ч) |
|
||
| `GET` | `/logs/api/levels` | Различные уровни для выпадающего фильтра |
|
||
| `GET` | `/logs/api/categories` | Различные категории |
|
||
|
||
#### Параметры запроса для `GET /logs/api/logs`
|
||
|
||
| Имя | Тип | Описание |
|
||
|------|------|-------------|
|
||
| `search` | string | Свободный поиск по сообщению/имени пользователя |
|
||
| `level` | string | Фильтр по уровню (`INFO`, `ERROR`, …) |
|
||
| `category` | string | Фильтр по категории |
|
||
| `username` | string | Фильтр по имени пользователя |
|
||
| `page` | int | Номер страницы (с 1) |
|
||
| `limit` | int | Размер страницы (по умолчанию 50) |
|
||
| `date_from` | ISO date | Нижняя граница (включительно) |
|
||
| `date_to` | ISO date | Верхняя граница (включительно) |
|
||
|
||
#### Форма ответа
|
||
|
||
```json
|
||
{
|
||
"logs": [
|
||
{
|
||
"id": 1234,
|
||
"timestamp": "2026-06-04T10:21:33Z",
|
||
"level": "INFO",
|
||
"category": "vm",
|
||
"username": "admin",
|
||
"message": "VM 100 started on node pve1"
|
||
}
|
||
],
|
||
"total": 532,
|
||
"page": 1,
|
||
"limit": 50,
|
||
"pages": 11
|
||
}
|
||
```
|
||
|
||
### Контроль доступа
|
||
|
||
Страница «Логи» защищена правом `log:view` в RBAC v2. Стоковая роль `admin` имеет его; `moderator` имеет доступ только на чтение; роли `user` и `demo` эту страницу не видят.
|
||
|
||
### Хранение
|
||
|
||
Хранение логов управляется через **Настройки → Панель → Дни хранения логов** (добавлено в v1.5.2). Записи старше настроенного числа дней удаляются автоматически. По умолчанию — 30 дней.
|
||
|
||
---
|
||
|
||
## 🔑 Управление SSH-ключами
|
||
|
||
### Обзор
|
||
|
||
У каждого пользователя есть личная библиотека SSH-ключей. Ключи из библиотеки можно выбирать при развёртывании ВМ или LXC-контейнеров, избавляя от необходимости каждый раз вставлять публичный ключ вручную.
|
||
|
||
### Управление SSH-ключами
|
||
|
||
1. Перейдите в **Настройки** → **SSH Keys**
|
||
2. Нажмите **Add Key**
|
||
3. Заполните:
|
||
- **Name** — читаемая метка (напр., `Work laptop`)
|
||
- **Public Key** — вставьте полный публичный ключ (`ssh-rsa ...`, `ssh-ed25519 ...` и т.д.)
|
||
- **Private Key** *(опционально)* — хранится в базе в зашифрованном виде
|
||
- **Comment** *(опционально)* — свободная заметка
|
||
4. Нажмите **Save**
|
||
|
||
SHA-256 отпечаток вычисляется и отображается автоматически.
|
||
|
||
### Использование ключей при развёртывании
|
||
|
||
- В **мастере создания инстанса** на шаге **Config** показан селектор ключей
|
||
- Обычные пользователи видят свои ключи
|
||
- Админы, выбирающие владельца, видят ключи владельца в дополнение к своим
|
||
|
||
### Синхронизация SSH-ключей при смене владельца
|
||
|
||
Когда администратор переназначает ВМ или LXC другому пользователю (через диалог **Владелец** на странице инстанса), панель автоматически:
|
||
|
||
1. Удаляет публичный SSH-ключ предыдущего владельца из `ciuser`/authorized keys инстанса
|
||
2. Внедряет публичный SSH-ключ нового владельца
|
||
|
||
Учётные данные для доступа всегда соответствуют текущему владельцу — ручная ротация ключей не нужна.
|
||
|
||
### Управление ключами админом
|
||
|
||
Админы (пользователи с правом `user:manage`) могут просматривать и управлять SSH-ключами любого пользователя:
|
||
|
||
```
|
||
GET /api/ssh-keys/user/{user_id} — список ключей конкретного пользователя
|
||
```
|
||
|
||
### Справочник API
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|--------|----------|-------------|
|
||
| `GET` | `/api/ssh-keys` | Список своих SSH-ключей |
|
||
| `POST` | `/api/ssh-keys` | Добавить новый ключ |
|
||
| `PUT` | `/api/ssh-keys/{id}` | Обновить ключ |
|
||
| `DELETE` | `/api/ssh-keys/{id}` | Удалить ключ |
|
||
| `GET` | `/api/ssh-keys/user/{user_id}` | Список ключей любого пользователя (админ) |
|
||
|
||
---
|
||
|
||
## 🌍 Локализация
|
||
|
||
### Поддерживаемые языки
|
||
|
||
- 🇷🇺 Русский (полное покрытие начиная с v1.16.0)
|
||
- 🇺🇸 Английский (по умолчанию)
|
||
- 🇺🇿 Узбекский (частично)
|
||
|
||
> **v1.16.0** завершил полный проход по переводам: все ранее захардкоженные или непереведённые строки на дашборде, в инстансах, образах, App Store, нодах, ролях, хранилищах, скриптах, сертификатах, графиках, мастере, массовой миграции и реалмах доступа теперь корректно переведены на русский и английский.
|
||
|
||
### Переключение языка
|
||
|
||
Начиная с v1.5.2, язык является **пользовательской** настройкой, хранящейся в базе данных.
|
||
|
||
1. **Настройки** → **Profile**
|
||
2. Выберите язык в выпадающем списке **Language**
|
||
3. Нажмите **Save** — интерфейс переключится немедленно без перезагрузки страницы
|
||
|
||
### Добавление нового языка
|
||
|
||
Переводы хранятся плоскими JSON-файлами в `backend/app/locales/`.
|
||
Чтобы добавить новый язык, просто создайте новый файл — изменения кода не требуются:
|
||
|
||
```bash
|
||
# Создать файл локали для узбекского
|
||
cp backend/app/locales/en.json backend/app/locales/uz.json
|
||
# Затем переведите значения в uz.json
|
||
```
|
||
|
||
Имя файла становится кодом языка (`uz.json` → `"uz"`). Панель подхватит его при следующем старте (или вызовите `I18nService.reload()` в рантайме).
|
||
|
||
> **Структура:** каждый файл — плоский JSON-объект `{"key": "переведённая строка"}`.
|
||
> Ключи должны совпадать с существующими ключами в `ru.json` / `en.json`.
|
||
|
||
---
|
||
|
||
## ⚙️ Настройки
|
||
|
||
### Профиль пользователя
|
||
|
||
- Полное имя
|
||
- Email (для уведомлений)
|
||
- Смена пароля
|
||
- **Язык** — язык UI пользователя (хранится в колонке БД `users.language`); применяется сразу при сохранении через `i18n.changeLanguage()`; у каждой учётной записи своя настройка
|
||
- **Публичный SSH-ключ** — хранится в профиле пользователя и автоматически внедряется в VM/LXC при развёртывании через cloud-init
|
||
|
||
### Настройки панели
|
||
|
||
| Параметр | Описание | По умолчанию |
|
||
|-----------|-------------|---------|
|
||
| Refresh interval | Частота обновления данных | 30 сек |
|
||
| Log retention | Сколько дней хранить логи | 30 дней |
|
||
| Panel name | Отображаемое имя (read-only в UI, можно переопределить в БД) | env `PANEL_NAME` |
|
||
|
||
> **Примечание:** настройка языка перенесена с вкладки «Панель» на вкладку «Профиль» в v1.5.2 — теперь каждый пользователь управляет своим языком независимо.
|
||
|
||
### Обновления системы и выбор репозитория
|
||
|
||
Панель поддерживает автоматические обновления из Git-репозитория. Можно выбрать, какой репозиторий использовать:
|
||
|
||
**Доступные варианты:**
|
||
1. **git.tzim.uz/markmorado/pvemanager** (по умолчанию) — основной репозиторий
|
||
2. **github.com/markmorado/pvemanager** — зеркало
|
||
3. **Кастомный репозиторий** — ваш форк или зеркало
|
||
|
||
**Как сменить репозиторий:**
|
||
|
||
1. Перейдите в **Настройки** → **System Updates**
|
||
2. В выпадающем списке «Git Repository» выберите предпочтительный репозиторий
|
||
3. Для кастомного репозитория:
|
||
- Выберите «Custom Repository...» из списка
|
||
- Введите полный URL (напр., `https://git.example.com/user/repo`)
|
||
- Нажмите Save
|
||
|
||
Настройка репозитория влияет на:
|
||
- Проверку обновлений (сравнение версий)
|
||
- Получение changelog
|
||
- Процесс обновления панели
|
||
|
||
> **Примечание:** убедитесь, что выбранный репозиторий содержит валидные файлы `VERSION` и `CHANGELOG.md`.
|
||
|
||
### Как работает процесс обновления
|
||
|
||
Начиная с v1.1.1, обновления выполняются **сторожевым процессом на хосте** (`pvemanager-update.service`), а не внутри контейнера. Это решает фундаментальную проблему, когда `docker compose down` убивал бы внутриконтейнерный скрипт до завершения пересборки.
|
||
|
||
```
|
||
[UI: "Update Panel"] → perform_update() → пишет .update_trigger
|
||
↓ (опрос каждые 3 сек)
|
||
[pvemanager-update.service на ХОСТЕ]
|
||
обнаруживает триггер → удаляет его → выполняет:
|
||
git pull
|
||
docker compose down
|
||
docker compose build --no-cache app
|
||
docker compose up -d
|
||
```
|
||
|
||
**Логи:** `./logs/update_host.log` (видны из панели)
|
||
|
||
### Установка сторожа обновлений
|
||
|
||
Сторож нужно установить один раз на хост-машине. Он автоматически настраивается при запуске `deploy.sh`, либо его можно установить/переустановить отдельно:
|
||
|
||
```bash
|
||
# Установка или переустановка (требует root для systemd)
|
||
sudo ./deploy.sh --watchdog
|
||
|
||
# Проверить, что запущен
|
||
systemctl status pvemanager-update
|
||
|
||
# Смотреть живой лог обновления
|
||
tail -f logs/update_host.log
|
||
```
|
||
|
||
**Требования:**
|
||
- systemd на хосте
|
||
- Пользователь, запускающий `deploy.sh --watchdog` (или `$SUDO_USER`), должен быть в группе `docker` (root разрешён всегда)
|
||
- Volume `.:/project:rw` в `compose.yml` должен присутствовать (он есть по умолчанию)
|
||
|
||
> **Примечание для non-root:** если вы запустите `./deploy.sh --watchdog` без sudo, он сгенерирует готовые файлы в `./systemd/` и напечатает точные `sudo`-команды для их установки.
|
||
|
||
### Настройки уведомлений
|
||
|
||
- In-App: всегда включены
|
||
- Email: требует настройки SMTP
|
||
- Telegram: требует токен бота
|
||
|
||
---
|
||
|
||
## 🛠️ Инструмент pve CLI
|
||
|
||
Начиная с v1.1.2, PVEmanager поставляется со скриптом `pve` — удобным CLI-ярлыком для частых задач управления.
|
||
|
||
### Установка
|
||
|
||
```bash
|
||
# Требует root (копирует скрипт в /usr/local/bin/pve и правит путь проекта)
|
||
sudo ./deploy.sh --install-cli
|
||
```
|
||
|
||
После установки команда `pve` доступна системно.
|
||
|
||
### Использование
|
||
|
||
```bash
|
||
pve help # Показать все доступные команды
|
||
pve logs # Смотреть живые логи app
|
||
pve restart # Перезапустить все контейнеры
|
||
pve update # Запустить обновление панели (через сторож)
|
||
pve exec <cmd> # Выполнить команду внутри контейнера app
|
||
pve status # Показать статус docker compose
|
||
pve dev # Запустить frontend в dev-режиме (Vite HMR)
|
||
pve dev stop # Остановить dev-режим, вернуться к production frontend
|
||
```
|
||
|
||
### Как это работает
|
||
|
||
- `deploy.sh --install-cli` читает файл `pve` из корня проекта
|
||
- Заменяет плейсхолдер `PVE_DIR` фактическим путём проекта
|
||
- Записывает результат в `/usr/local/bin/pve` и делает исполняемым
|
||
- Перезапустите `sudo ./deploy.sh --install-cli` после перемещения каталога проекта
|
||
|
||
> **Примечание:** бинарник `pve` отражает каталог проекта на момент установки. Если вы перемещаете проект — переустановите CLI.
|
||
|
||
---
|
||
|
||
## 🔌 Справочник API
|
||
|
||
### Аутентификация
|
||
|
||
```bash
|
||
# Получить токен
|
||
POST /api/auth/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"username": "admin",
|
||
"password": "admin123"
|
||
}
|
||
|
||
# Ответ
|
||
{
|
||
"access_token": "eyJ...",
|
||
"token_type": "bearer"
|
||
}
|
||
```
|
||
|
||
### Использование токена
|
||
|
||
```bash
|
||
curl -H "Authorization: Bearer eyJ..." \
|
||
http://localhost:8000/api/notifications
|
||
```
|
||
|
||
### Основные эндпоинты
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|--------|----------|-------------|
|
||
| GET | `/api/servers` | Список серверов Proxmox |
|
||
| GET | `/api/servers/{id}` | Получить конкретный сервер |
|
||
| POST | `/api/servers` | Добавить сервер |
|
||
| PUT | `/api/servers/{id}` | Обновить сервер |
|
||
| DELETE | `/api/servers/{id}` | Удалить сервер |
|
||
| POST | `/api/servers/{id}/test` | Проверить подключение |
|
||
| GET | `/api/servers/{id}/resources` | ВМ и контейнеры сервера |
|
||
| POST | `/api/servers/{id}/vm/{vmid}/{action}` | Управление ВМ (start/stop/restart) |
|
||
| POST | `/api/servers/{id}/container/{vmid}/{action}` | Управление контейнером (start/stop/restart) |
|
||
| GET | `/api/servers/{id}/vm/{vmid}/status` | Статус ВМ |
|
||
| GET | `/api/servers/{id}/container/{vmid}/status` | Статус контейнера |
|
||
| GET | `/ipam/api/networks` | Список сетей IPAM |
|
||
| POST | `/ipam/api/networks` | Создать сеть IPAM |
|
||
| GET | `/ipam/api/allocations` | Список выделений IP |
|
||
| POST | `/ipam/api/allocations` | Создать выделение IP |
|
||
| GET | `/templates/api/groups` | Список групп шаблонов |
|
||
| GET | `/templates/api/templates` | Список шаблонов ОС |
|
||
| POST | `/templates/api/templates` | Создать шаблон ОС |
|
||
| GET | `/api/notifications` | Список уведомлений |
|
||
| PATCH | `/api/notifications/{id}/read` | Отметить прочитанным |
|
||
| DELETE | `/api/notifications/{id}` | Удалить уведомление |
|
||
| GET | `/api/users` | Список пользователей (только админ) |
|
||
| POST | `/api/users` | Создать пользователя (только админ) |
|
||
| GET | `/settings/api/panel` | Получить настройки панели |
|
||
| PUT | `/settings/api/panel` | Обновить настройки панели |
|
||
| GET | `/logs/api/logs` | Получить логи аудита |
|
||
| GET | `/logs/api/stats` | Статистика логов |
|
||
| GET | `/api/backups/storages/{server_id}` | Список хранилищ Proxmox |
|
||
| GET | `/api/backups/scan-nfs/{server_id}` | Сканировать NFS-сервер на экспорты |
|
||
| POST | `/api/backups/create` | Создать копию VM/LXC |
|
||
| POST | `/api/backups/restore` | Восстановить VM/LXC из копии |
|
||
| GET | `/api/backups/list/{server_id}` | Список файлов копий |
|
||
| DELETE | `/api/backups/{server_id}/backup` | Удалить файл копии |
|
||
| GET | `/api/backups/jobs` | Список запланированных заданий |
|
||
| POST | `/api/backups/jobs` | Создать запланированное задание |
|
||
| GET | `/api/{server_id}/ha/status` | Статус HA для всех ВМ |
|
||
| POST | `/api/{server_id}/ha/{vm_type}/{vmid}/add` | Добавить ВМ в HA-группу |
|
||
| DELETE | `/api/{server_id}/ha/{vm_type}/{vmid}/remove` | Убрать ВМ из HA |
|
||
| POST | `/api/sync-vms` | Принудительная синхронизация ВМ из Proxmox |
|
||
| GET | `/api/servers/{id}/nodes` | Список узлов сервера |
|
||
| PUT | `/api/servers/{id}/sdn/zones/{zone}` | Обновить зону SDN |
|
||
| PUT | `/api/servers/{id}/sdn/vnets/{vnet}` | Обновить VNet SDN |
|
||
| DELETE | `/api/servers/{id}/sdn/vnets/{vnet}/subnets/{cidr}` | Удалить подсеть SDN |
|
||
|
||
### Документация Swagger
|
||
|
||
Доступна по адресу: `http://localhost:8000/docs`
|
||
|
||
---
|
||
|
||
## 🗂️ Рабочие области (Workspaces)
|
||
|
||
Рабочие области — это именованные группы серверов Proxmox с ограниченным доступом пользователей. Они позволяют администраторам разделять инфраструктуру и давать пользователям доступ только к их серверам.
|
||
|
||
### Ключевые понятия
|
||
|
||
| Понятие | Описание |
|
||
|---|---|
|
||
| **Workspace** | Именованная группа с опциональным цветом и описанием |
|
||
| **Default Workspace** | Создаётся автоматически; все серверы по умолчанию в ней |
|
||
| **Назначение сервера** | Один сервер может принадлежать нескольким рабочим областям |
|
||
| **Назначение пользователя** | Пользователи видят только назначенные им области |
|
||
|
||
### Управление рабочими областями (админ)
|
||
|
||
1. Откройте **Настройки → Workspaces** (пункт бокового меню) или перейдите на `/workspaces`
|
||
2. Нажмите **New Workspace** для создания
|
||
3. Назначьте серверы на вкладке **Servers** внутри детали области
|
||
4. Назначьте пользователей на вкладке **Users**
|
||
|
||
### Переключение рабочих областей (боковая панель)
|
||
|
||
- Активная область показана в боковой панели под логотипом
|
||
- Кликните имя области, чтобы открыть переключатель
|
||
- Выберите область — все списки ВМ/серверов сразу фильтруются
|
||
- Выберите **All Workspaces** (только админ), чтобы снять фильтр
|
||
|
||
### API
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|---|---|---|
|
||
| `GET` | `/api/workspaces` | Список областей (фильтруется для не-админов) |
|
||
| `POST` | `/api/workspaces` | Создать область (админ) |
|
||
| `GET` | `/api/workspaces/{id}` | Деталь области с серверами/пользователями |
|
||
| `PUT` | `/api/workspaces/{id}` | Обновить область (админ) |
|
||
| `DELETE` | `/api/workspaces/{id}` | Удалить область (админ) |
|
||
| `POST` | `/api/workspaces/{id}/servers` | Добавить сервер в область |
|
||
| `DELETE` | `/api/workspaces/{id}/servers/{server_id}` | Убрать сервер из области |
|
||
| `POST` | `/api/workspaces/{id}/users` | Добавить пользователя в область |
|
||
| `DELETE` | `/api/workspaces/{id}/users/{user_id}` | Убрать пользователя из области |
|
||
|
||
Передавайте заголовок `X-Active-Workspace: {id}` в запросах API для фильтрации ответов по области.
|
||
|
||
---
|
||
|
||
## 👤 Назначение серверов пользователю
|
||
|
||
Назначение серверов позволяет админам напрямую связывать конкретные серверы Proxmox с отдельными пользователями. В сочетании с рабочими областями это даёт тонкий контроль: пользователь видит только серверы, которые **одновременно** и в его рабочей области, **и** явно назначены ему.
|
||
|
||
### Как это работает
|
||
|
||
1. Пользователь принадлежит одной или нескольким **рабочим областям**
|
||
2. Админ назначает пользователю конкретные **серверы** (из серверов, разделяющих хотя бы одну область с пользователем)
|
||
3. Пользователь видит только пересечение: серверы-области ∩ назначенные-серверы
|
||
|
||
### Управление назначениями (UI)
|
||
|
||
1. Откройте страницу **Пользователи**
|
||
2. Нажмите **Edit** для пользователя
|
||
3. На вкладке **Servers** — отметьте/снимите серверы; несовместимые серверы (другая область) подсвечены
|
||
4. Save — назначения применяются немедленно
|
||
|
||
### REST API
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|---|---|---|
|
||
| `GET` | `/api/users/{id}/servers` | Назначенные серверы пользователя |
|
||
| `GET` | `/api/users/{id}/server-assignments` | Все серверы с флагами `assigned` и `compatible` |
|
||
| `PUT` | `/api/users/{id}/servers` | Задать серверы (заменяет текущий список); тело: `{"server_ids": [1,2]}` |
|
||
|
||
Возвращает `409 workspace_conflict`, если какой-либо сервер не разделяет ни одной области с пользователем.
|
||
|
||
---
|
||
|
||
## 🖥️ Владелец ВМ / LXC
|
||
|
||
У любой ВМ или LXC-контейнера может быть **владелец** — обычный пользователь, ответственный за этот инстанс. Владелец отображается в списке ВМ.
|
||
|
||
### Изоляция
|
||
|
||
Владение применяется везде, где непривилегированный пользователь видит инстансы, а не только в списке инстансов. Эндпоинты живых ресурсов — `/api/resources/all` (дашборд) и `/api/{server_id}/resources` (страница узла/сервера) — фильтруют ВМ/LXC по владельцу (сопоставляя каждый `vmid` с кэшем `vm_instances`), поэтому пользователь только с `proxmox.view` не может видеть инстансы других владельцев через страницу узла. **Админы** и роли с **`vm:manage`** освобождены от этого и видят всё.
|
||
|
||
**Владелец теперь проставляется автоматически при создании** (`vm_create`/`ct_create`), в том числе когда ВМ создаёт админ от имени другого пользователя — деплой инжектирует SSH-ключ именно этого владельца (объединённый с любыми вставленными вручную или взятыми из библиотеки ключами), а не ключ создавшего.
|
||
|
||
Инстансы, синхронизированные из Proxmox до появления владения, или созданные до исправления выше, имеют `owner_id = NULL`. Разовая миграция бэкфиллит их автоматически из `deploy_tasks` и `audit_logs` (записи `vm_create`/`ct_create`/`lxc_create`), но только когда все доступные данные указывают на одного и того же существующего пользователя — неоднозначные случаи (например, переиспользованный VMID) намеренно остаются без владельца. Чтобы назначить владельца тому, что осталось, запустите вспомогательный скрипт из образа бэкенда:
|
||
|
||
```bash
|
||
docker compose exec app python assign_instances_owner.py
|
||
```
|
||
|
||
### Назначение владельца (админ)
|
||
|
||
Откройте страницу деталей ВМ → кнопка **Owner** → выберите пользователя → Save.
|
||
|
||
### REST API
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|---|---|---|
|
||
| `GET` | `/api/{server_id}/vm/{vmid}/owner` | Текущий владелец + список пользователей |
|
||
| `PUT` | `/api/{server_id}/vm/{vmid}/owner` | Задать или очистить владельца (`{"user_id": null}` для очистки) |
|
||
|
||
---
|
||
|
||
## 🎯 Квоты
|
||
|
||
Квоты ресурсов на пользователя ограничивают, сколько пользователь может выделить. Ограничиваются четыре метрики, каждая суммируется по **неудалённым, не-шаблонным** инстансам пользователя:
|
||
|
||
| Метрика | Единица | Поле квоты |
|
||
|---|---|---|
|
||
| Инстансы | количество | `max_instances` |
|
||
| vCPU | ядра | `max_cores` |
|
||
| RAM | МБ | `max_memory_mb` |
|
||
| Диск | ГБ | `max_disk_gb` |
|
||
|
||
- **Без ограничений по умолчанию** — пользователь без строки квоты или с пустой метрикой (`NULL`) не ограничен по этой метрике. Админы и ненастроенные пользователи никогда не блокируются.
|
||
- **Применение** — развёртывание VM/LXC, которое превысит любую метрику, отклоняется с **HTTP 429** и двуязычным сообщением (`Превышена квота … / Quota exceeded …`) с прогнозируемым значением и лимитом.
|
||
- **Источник использования** — текущее использование вычисляется из кэша `vm_instances` (`owner_id`), где RAM хранится в МБ, а диск — в ГБ (без конвертации).
|
||
|
||
### Два уровня блокировки на клиенте
|
||
|
||
Реально применяет ограничение только backend'ный HTTP 429, но интерфейс теперь предупреждает заранее, используя в обоих местах одну и ту же функцию `exhaustedMetrics()` (`features/instances/quota.ts`), чтобы они не могли разойтись:
|
||
|
||
- **Свободного места совсем не осталось** (использовано ≥ лимита хотя бы по одной метрике) — сама точка входа **«Создать инстанс»** отключается, а подсказка называет, какие именно лимиты исчерпаны. Ни одна конфигурация не влезет, поэтому мастер даже не открывается.
|
||
- **Место есть, но выбранная конфигурация его превысит** — мастер открывается как обычно; начиная с шага конфигурации называется метрика, которая была бы превышена, а **«Далее»**/**«Развернуть»** заблокированы, пока запрос не уменьшат.
|
||
|
||
Ни одна из блокировок не применяется к **админам** — их личная квота не имеет отношения к инстансу, который они создают для кого-то другого, а показанные им цифры носят чисто информационный характер.
|
||
|
||
### Управление квотами (админ)
|
||
|
||
Страница **Пользователи** → диалог квот. Живые полосы использования показывают текущее потребление против каждого лимита. Оставьте поле пустым для *без ограничений*. Требует право `quota:manage` (`quota:view` для чтения).
|
||
|
||
### Self-service
|
||
|
||
Каждый пользователь видит свои лимиты и текущее использование на странице **Профиль**. Мастер **создания инстанса** показывает остаток квоты подсказкой на шаге конфигурации.
|
||
|
||
### REST API
|
||
|
||
| Метод | Эндпоинт | Описание |
|
||
|---|---|---|
|
||
| `GET` | `/api/users/{id}/quota` | Лимиты пользователя + текущее использование (требует `quota:view`) |
|
||
| `PUT` | `/api/users/{id}/quota` | Задать лимиты; `null` для метрики = без ограничений (требует `quota:manage`) |
|
||
| `GET` | `/api/quota` | Собственные лимиты + использование текущего пользователя (self-service) |
|
||
|
||
---
|
||
|
||
## 🔧 Устранение неполадок
|
||
|
||
### Проблемы запуска
|
||
|
||
#### Контейнер не запускается
|
||
|
||
```bash
|
||
# Проверить логи
|
||
docker compose logs app
|
||
|
||
# Проверить статус
|
||
docker compose ps
|
||
```
|
||
|
||
#### Ошибка подключения к базе данных
|
||
|
||
```bash
|
||
# Проверить, запущена ли БД
|
||
docker compose logs db
|
||
|
||
# Перезапустить
|
||
docker compose restart db
|
||
docker compose restart app
|
||
```
|
||
|
||
### Проблемы Proxmox
|
||
|
||
#### «Connection refused»
|
||
|
||
- Проверьте IP-адрес сервера
|
||
- Проверьте, что порт 8006 открыт
|
||
- Проверьте файрвол на Proxmox
|
||
|
||
#### «Authentication failed»
|
||
|
||
- Проверьте логин/пароль
|
||
- Используйте формат `user@pam` или `user@pve`
|
||
- Попробуйте создать API Token
|
||
|
||
### Проблемы уведомлений
|
||
|
||
#### Email не отправляется
|
||
|
||
1. Проверьте настройки SMTP в `backend/.env`
|
||
2. Для порта 465 требуется SSL
|
||
3. Для порта 587 требуется STARTTLS
|
||
4. Проверьте «пароль приложения» для Yandex/Gmail
|
||
|
||
```bash
|
||
# Проверить переменные в контейнере
|
||
docker compose exec app env | grep SMTP
|
||
```
|
||
|
||
#### Telegram не работает
|
||
|
||
1. Проверьте токен бота
|
||
2. Отправьте боту `/start`
|
||
3. Проверьте Chat ID
|
||
4. Убедитесь, что бот не заблокирован
|
||
|
||
#### Кнопка «Тест» зависает
|
||
|
||
- Проверьте логи: `docker compose logs app --tail 50`
|
||
- SMTP-сервер может быть недоступен
|
||
- Таймаут — 10 секунд
|
||
|
||
### Проблемы VNC / терминала
|
||
|
||
#### «VNC connection failed» (QEMU)
|
||
|
||
- Проверьте, что ВМ запущена
|
||
- Убедитесь, что VNC включён в настройках узла Proxmox
|
||
- Попробуйте перезапустить ВМ
|
||
- Проверьте, что у API-пользователя Proxmox есть привилегия `VM.Console`
|
||
|
||
#### «Connection closed» сразу при открытии VNC
|
||
|
||
- Это была известная ошибка, исправленная в v1.3.0 (noVNC получал уже открытый WebSocket вместо URL)
|
||
- Обновитесь до v1.3.0 или новее
|
||
|
||
#### Терминал не подключается (LXC)
|
||
|
||
- Проверьте, что контейнер **запущен** (не остановлен и не приостановлен)
|
||
- Проверьте, что у API-пользователя Proxmox есть привилегия `VM.Console` на узле
|
||
- Проверьте логи: `docker compose logs app --tail 50`
|
||
|
||
### Проблемы команд
|
||
|
||
#### «Guest Agent not running»
|
||
|
||
```bash
|
||
# В ВМ выполнить:
|
||
systemctl status qemu-guest-agent
|
||
systemctl start qemu-guest-agent
|
||
```
|
||
|
||
#### Команда зависает
|
||
|
||
- Таймаут — 30 секунд
|
||
- Не используйте интерактивные команды
|
||
- Проверьте, что ВМ отвечает
|
||
|
||
### Проблемы производительности
|
||
|
||
#### Высокое использование памяти
|
||
|
||
```bash
|
||
# Перезапустить контейнеры
|
||
docker compose restart
|
||
|
||
# Очистить логи
|
||
docker system prune -f
|
||
```
|
||
|
||
#### Медленная загрузка страниц
|
||
|
||
- Увеличьте интервал обновления в настройках
|
||
- Проверьте сеть до сервера Proxmox
|
||
|
||
### Проблемы с учётной записью
|
||
|
||
#### Админ забыл пароль
|
||
|
||
Если админ забыл пароль, его можно сбросить через командную строку:
|
||
|
||
**Вариант 1: Сброс к паролю по умолчанию**
|
||
|
||
```bash
|
||
# Выполнить внутри контейнера app
|
||
docker compose exec app python -c "
|
||
from app.db import get_db
|
||
from app.models import User
|
||
from app.auth import get_password_hash
|
||
|
||
db = next(get_db())
|
||
admin = db.query(User).filter(User.username == 'admin').first()
|
||
if admin:
|
||
admin.hashed_password = get_password_hash('admin123')
|
||
db.commit()
|
||
print('Admin password reset to: admin123')
|
||
else:
|
||
print('Admin user not found')
|
||
db.close()
|
||
"
|
||
```
|
||
|
||
**Вариант 2: Задать свой пароль**
|
||
|
||
```bash
|
||
# Замените YOUR_NEW_PASSWORD на нужный пароль
|
||
docker compose exec app python -c "
|
||
from app.db import get_db
|
||
from app.models import User
|
||
from app.auth import get_password_hash
|
||
|
||
db = next(get_db())
|
||
admin = db.query(User).filter(User.username == 'admin').first()
|
||
if admin:
|
||
admin.hashed_password = get_password_hash('YOUR_NEW_PASSWORD')
|
||
db.commit()
|
||
print('Admin password has been reset')
|
||
else:
|
||
print('Admin user not found')
|
||
db.close()
|
||
"
|
||
```
|
||
|
||
**Вариант 3: Сброс пароля любого пользователя**
|
||
|
||
```bash
|
||
# Замените USERNAME на нужное имя пользователя
|
||
docker compose exec app python -c "
|
||
from app.db import get_db
|
||
from app.models import User
|
||
from app.auth import get_password_hash
|
||
|
||
db = next(get_db())
|
||
user = db.query(User).filter(User.username == 'USERNAME').first()
|
||
if user:
|
||
user.hashed_password = get_password_hash('newpassword123')
|
||
db.commit()
|
||
print('Password reset for user: USERNAME')
|
||
else:
|
||
print('User not found')
|
||
db.close()
|
||
"
|
||
```
|
||
|
||
> ⚠️ **Заметка о безопасности:** после сброса пароля немедленно войдите и смените его на надёжный через веб-интерфейс.
|
||
|
||
---
|
||
|
||
## ❓ FAQ
|
||
|
||
### Общие вопросы
|
||
|
||
**В: Можно ли использовать без Proxmox?**
|
||
О: Нет, панель специально разработана для управления Proxmox.
|
||
|
||
**В: Сколько серверов можно добавить?**
|
||
О: Не ограничено.
|
||
|
||
**В: Поддерживается ли кластер Proxmox?**
|
||
О: Да, добавьте любой узел кластера.
|
||
|
||
### Безопасность
|
||
|
||
**В: Пароли хранятся в открытом виде?**
|
||
О: Нет, используется bcrypt-хэширование.
|
||
|
||
**В: Как сменить SECRET_KEY?**
|
||
О: Измените в `.env` и перезапустите. Все сессии будут инвалидированы.
|
||
|
||
### Уведомления
|
||
|
||
**В: Почему не приходят письма?**
|
||
О: Проверьте настройки SMTP, особенно порт и TLS.
|
||
|
||
**В: Можно ли отключить уведомления?**
|
||
О: Да, в настройках уведомлений.
|
||
|
||
**В: Как задать тихие часы?**
|
||
О: В настройках уведомлений укажите период (напр., 23:00 – 07:00).
|
||
|
||
### Интеграции
|
||
|
||
**В: Есть ли API для интеграции?**
|
||
О: Да, REST API с документацией по адресу `/docs`.
|
||
|
||
**В: Можно ли добавить webhooks?**
|
||
О: Пока нет, но запланировано в будущих версиях.
|
||
|
||
---
|
||
|
||
## 📞 Поддержка
|
||
|
||
- **GitHub Issues**: [Создать issue](https://github.com/your-repo/server-panel/issues)
|
||
- **Документация**: этот файл (WIKI.ru.md)
|
||
- **Changelog**: [CHANGELOG.ru.md](CHANGELOG.ru.md)
|
||
|
||
---
|
||
|
||
*Последнее обновление: 24 июля 2026*
|
||
*Версия: 1.13.0*
|