# 📖 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=` — сканировать 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) в любом месте приложения, чтобы открыть **палитру команд** — поисковый список всех пунктов навигации. Начните печатать для фильтрации, затем Enter для перехода. Палитра и боковое меню используют один унифицированный реестр навигации, поэтому всегда синхронизированы. ### Действия с ВМ Меню строки инстанса (⋯) содержит **Опции**, **Миграцию**, **Изменение ресурсов**, **Создание резервной копии** и **Удаление** наряду с действиями питания ниже. Меню остаётся открытым при живых обновлениях списка. | Действие | Описание | Хоткей | |--------|-------------|--------| | 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-`) во избежание коллизий. ### Предварительные требования - **Золотой шаблон 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 (`/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`» означает, что движок выдаёт это бесплатно, когда роль держит `: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 # Выполнить команду внутри контейнера 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*