Сравнить коммиты
1
Коммитов
| Автор | SHA1 | Дата | |
|---|---|---|---|
|
|
5f2bdd921d |
+87
-387
@@ -1,379 +1,69 @@
|
|||||||
# Virtuality
|
# Virtuality
|
||||||
|
|
||||||
**Virtuality** — лёгкая серверная платформа виртуализации на базе **KVM**, **QEMU**, **libvirt**, **Cockpit** и собственной web-панели.
|
Платформа управления виртуализацией для одиночной Linux-ноды: KVM/QEMU/libvirt плюс собственная web-панель на FastAPI. Предназначена для администратора домашнего сервера, VPS или ARM64-платы (Raspberry Pi, Orange Pi 5), которому нужен упрощённый аналог Proxmox: создание VM из ISO, управление питанием, NAT/bridge-сеть с пробросом портов, web-консоль noVNC, журнал фоновых операций и самообновление ноды из git.
|
||||||
|
|
||||||
Цель проекта — собрать понятную, компактную и расширяемую систему для управления виртуальными машинами, ISO-образами, NAT/bridge-сетью, пробросом портов, диагностикой, web-console/noVNC, backup/snapshot-функциями и будущей кластеризацией.
|
Установка выполняется одной командой; установщик сам определяет профиль хоста (x86_64 / raspberry-arm64 / orangepi5-arm64 / generic-arm64) и ставит соответствующий набор пакетов. Авторизация в панели — по существующему Linux-пользователю (PAM/shadow), отдельной базы пользователей нет.
|
||||||
|
|
||||||
> Текущий статус: ранняя стадия разработки. Уже есть one-command установка, автоопределение профиля хоста, web-панель, авторизация через Linux-пользователя, ISO-менеджер, создание VM из интерфейса, журнал операций, NAT Router для VPS/ARM edge nodes и port forwarding.
|
Исходный README автора сохранён в `README.upstream.md` — там подробные разделы про порты, директории, диагностику, NAT Router и полезные команды.
|
||||||
|
|
||||||
---
|
## Стек
|
||||||
|
|
||||||
## Поддерживаемые профили хоста
|
- Python 3, FastAPI, Uvicorn, Jinja2, itsdangerous (подписанные cookie-сессии)
|
||||||
|
- Bash — установщики, диагностика, сетевые скрипты, TUI-дашборд
|
||||||
|
- KVM, QEMU, libvirt (`virsh`, `virt-install`), Cockpit + Cockpit Machines
|
||||||
|
- nftables — NAT-роутер и port forwarding, netplan — настройка bridge `br0`
|
||||||
|
- noVNC + websockify — web-консоль VM
|
||||||
|
- systemd — юниты `virtuality-web`, `virtuality-auto-update.service/.timer`
|
||||||
|
- Хранение состояния — файлы JSON в `/var/lib/virtuality`, СУБД не используется
|
||||||
|
- Внешние API отсутствуют; обновления тянутся с GitHub (git pull или zip-архив ветки)
|
||||||
|
|
||||||
Virtuality автоматически определяет профиль сборки во время установки:
|
## Структура
|
||||||
|
|
||||||
```text
|
| Путь | Назначение |
|
||||||
x86_64 # обычный сервер, домашний сервер, VPS
|
| --- | --- |
|
||||||
raspberry-arm64 # Raspberry Pi ARM64 edge node
|
| `install.sh` | Основной установщик: проверка требований, apt-пакеты, клонирование репозитория, запуск установки ноды и панели |
|
||||||
orangepi5-arm64 # Orange Pi 5 / RK3588 ARM64 edge node
|
| `bootstrap.sh` | Публичная точка входа one-command установки на чистый сервер |
|
||||||
generic-arm64 # другая ARM64-плата
|
| `install_virtuality_node.sh` | Установка компонентов ноды: KVM/QEMU/libvirt, Cockpit, storage pools, firewall |
|
||||||
```
|
| `setup_github_sync.sh` | Настройка git-синхронизации репозитория на ноде |
|
||||||
|
| `VERSION`, `updates/versions.json` | Текущая версия и манифест истории версий, используется центром обновлений панели |
|
||||||
|
| `web/app.py` | Базовое FastAPI-приложение панели: логин, дашборд, ISO, создание VM, карточка VM, сеть, операции, health |
|
||||||
|
| `web/network_core.py` | NAT-роутер, nftables-правила, port forwarding, диагностика сети |
|
||||||
|
| `web/host_profile.py` | Определение и чтение профиля хоста |
|
||||||
|
| `web/update_core.py` | Центр обновлений: сравнение версий и коммитов, запуск обновления, лог |
|
||||||
|
| `web/templates/` | Jinja2-шаблоны страниц панели (`dashboard`, `vm_create`, `vm_detail`, `iso`, `disk_images`, `network`, `logs`, `update`, `console`, `operations`, `login`, `_sidebar`) |
|
||||||
|
| `web/static/` | `app.css`, `themes.css` (переключаемые темы, включая MacOS Flat), `panel.js`, статическая база знаний |
|
||||||
|
| `scripts/install_web_panel.sh` | Установка панели в `/opt/virtuality/web`, venv, systemd-юнит, применение всех патчей |
|
||||||
|
| `scripts/patch_*.py` | ~28 python-патчей, дописывающих функциональность в **установленный** `app.py` (диски, boot order, автозапуск VM, noVNC, сетевые диапазоны, центр логов, центр обновлений и т. д.) |
|
||||||
|
| `scripts/setup_bridge_br0.sh` | Безопасная настройка bridge `br0` через netplan с бэкапом и откатом |
|
||||||
|
| `scripts/check_node.sh`, `virtuality_healthcheck.sh`, `virtuality_console_dashboard.sh` | Диагностика ноды, healthcheck-команда `vhealth`, консольный btop-подобный дашборд |
|
||||||
|
| `scripts/auto_update_check.sh`, `apply_github_update.sh` | Автообновление по systemd-таймеру и применение обновления |
|
||||||
|
| `scripts/create_test_vm.sh`, `clean_install.sh`, `fix_cockpit_auth.sh` | Вспомогательные операции |
|
||||||
|
| `docs/` | `ARCHITECTURE.md`, `REQUIREMENTS.md`, `ROADMAP.md`, `FIRST_VM.md` |
|
||||||
|
|
||||||
Профиль сохраняется здесь:
|
Важная особенность архитектуры: репозиторный `web/app.py` — это **не** полный код панели. `install_web_panel.sh` копирует его в `/opt/virtuality/web/app.py` и затем последовательно применяет патч-скрипты из `scripts/`, которые вставляют в файл недостающие маршруты и функции (менеджер дисковых образов, web-консоль, центр логов, центр обновлений, сетевые доработки). Полная функциональность существует только после установки.
|
||||||
|
|
||||||
```text
|
## Как запустить
|
||||||
/var/lib/virtuality/config/host_profile.json
|
|
||||||
```
|
|
||||||
|
|
||||||
В web-панели профиль виден на странице:
|
Установка на чистый Ubuntu/Debian-сервер (требует root или sudo):
|
||||||
|
|
||||||
```text
|
|
||||||
/host
|
|
||||||
```
|
|
||||||
|
|
||||||
Для ARM64-плат правильный сценарий — **ARM64-гости**, NAT-сеть и позже cloud-image/cloud-init шаблоны. x86_64 ISO на Raspberry/Orange Pi не являются целевым режимом.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Быстрая установка одной командой
|
|
||||||
|
|
||||||
Одна команда работает и под `root`, и под обычным пользователем с `sudo`:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | bash
|
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Как выбирается пользователь для входа в web-панель:
|
Выбор Linux-пользователя для входа в панель:
|
||||||
|
|
||||||
```text
|
|
||||||
Если запуск под root → login: root
|
|
||||||
Если запуск через sudo → login: текущий sudo-пользователь
|
|
||||||
Если задан VIRTUALITY_USER → login: указанный Linux-пользователь
|
|
||||||
```
|
|
||||||
|
|
||||||
Принудительно выбрать пользователя:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_USER=<linux_user> bash
|
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_USER=<linux_user> bash
|
||||||
```
|
```
|
||||||
|
|
||||||
Пример:
|
Установка из локального клона:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_USER=admin bash
|
sudo bash install_virtuality_node.sh
|
||||||
```
|
|
||||||
|
|
||||||
Установка с авторизацией под `root`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_USER=root bash
|
|
||||||
```
|
|
||||||
|
|
||||||
Если пароль выбранного Linux-пользователя не задан:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo passwd <linux_user>
|
|
||||||
```
|
|
||||||
|
|
||||||
Для root:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
passwd root
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Что уже есть
|
|
||||||
|
|
||||||
- универсальная one-command установка через `install.sh`;
|
|
||||||
- автоопределение профиля хоста: x86_64, Raspberry Pi ARM64, Orange Pi 5 ARM64, generic ARM64;
|
|
||||||
- установка разных пакетных наборов под x86 и ARM64;
|
|
||||||
- красивый пошаговый installer с live-status и логами;
|
|
||||||
- preflight-проверка системных требований;
|
|
||||||
- установка KVM/QEMU/libvirt;
|
|
||||||
- установка Cockpit и Cockpit Machines;
|
|
||||||
- рабочая директория `/opt/virtuality/source`;
|
|
||||||
- libvirt storage pools `virtuality-images` и `virtuality-iso`;
|
|
||||||
- firewall-правила для SSH, Cockpit, VNC и web-панели;
|
|
||||||
- безопасная ручная настройка bridge `br0` через `netplan try`;
|
|
||||||
- NAT Router `virtuality-nat` для VPS/ARM edge nodes;
|
|
||||||
- port forwarding через nftables;
|
|
||||||
- автоматическое определение IP VM для проброса портов;
|
|
||||||
- healthcheck одной командой `vhealth`;
|
|
||||||
- консольный dashboard для физического монитора;
|
|
||||||
- web-панель Virtuality на FastAPI;
|
|
||||||
- авторизация web-панели через системного Linux-пользователя;
|
|
||||||
- `/host` — профиль хоста и проверки готовности;
|
|
||||||
- `/network` — NAT, DHCP leases, port forwarding, nftables preview;
|
|
||||||
- `/iso` — ISO-менеджер;
|
|
||||||
- `/operations` — журнал фоновых операций;
|
|
||||||
- список VM;
|
|
||||||
- управление VM: Start, Shutdown, Reboot, Power off, Autostart on/off, Delete VM with disks;
|
|
||||||
- создание VM из web-интерфейса;
|
|
||||||
- выбор сетевого режима при создании VM: `virtuality-nat` или `br0`;
|
|
||||||
- прогресс создания VM и live-лог `virt-install`;
|
|
||||||
- страница деталей VM: `dominfo`, VNC display, IP, диски, сетевые интерфейсы.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Системные требования
|
|
||||||
|
|
||||||
Минимально для x86_64 тестового стенда:
|
|
||||||
|
|
||||||
```text
|
|
||||||
CPU: 2 ядра с Intel VT-x / AMD-V
|
|
||||||
RAM: 4 GB
|
|
||||||
/: минимум 8 GB свободно
|
|
||||||
/var/lib: минимум 20 GB свободно
|
|
||||||
OS: Ubuntu Server 24.04 LTS / Debian-like с apt
|
|
||||||
Network: один проводной интерфейс
|
|
||||||
```
|
|
||||||
|
|
||||||
Рекомендуемо для x86_64:
|
|
||||||
|
|
||||||
```text
|
|
||||||
CPU: 4+ ядра
|
|
||||||
RAM: 16+ GB
|
|
||||||
Storage: 100+ GB SSD/NVMe под /var/lib/virtuality
|
|
||||||
Network: 1 Gbit/s+
|
|
||||||
OS: Ubuntu Server 24.04 LTS
|
|
||||||
```
|
|
||||||
|
|
||||||
ARM64 edge nodes:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Raspberry Pi 4/5 ARM64: желательно 8 GB RAM
|
|
||||||
Orange Pi 5 ARM64: желательно 8/16/32 GB RAM и NVMe
|
|
||||||
Гости: ARM64 Linux VM
|
|
||||||
Сеть: virtuality-nat по умолчанию
|
|
||||||
```
|
|
||||||
|
|
||||||
Подробнее: [`docs/REQUIREMENTS.md`](docs/REQUIREMENTS.md)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Порты
|
|
||||||
|
|
||||||
```text
|
|
||||||
Cockpit: https://SERVER_IP:9090
|
|
||||||
Virtuality UI: http://SERVER_IP:8088
|
|
||||||
VNC: 5900-5999/tcp
|
|
||||||
SSH: 22/tcp
|
|
||||||
```
|
|
||||||
|
|
||||||
Изменить порт web-панели:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_WEB_PORT=8089 bash
|
|
||||||
```
|
|
||||||
|
|
||||||
Для VPS/ARM NAT-сценария входящие сервисы VM открываются через port forwarding в разделе `/network`.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Директории
|
|
||||||
|
|
||||||
```text
|
|
||||||
/opt/virtuality/source # исходники проекта из GitHub
|
|
||||||
/opt/virtuality/web # установленная web-панель
|
|
||||||
/opt/virtuality/venv # Python virtualenv web-панели
|
|
||||||
/opt/virtuality/virtuality.env # базовый env ноды
|
|
||||||
/var/lib/virtuality/config # конфиги Virtuality
|
|
||||||
/var/lib/virtuality/config/host_profile.json
|
|
||||||
/var/lib/virtuality/iso # ISO-образы
|
|
||||||
/var/lib/virtuality/images # qcow2-диски VM
|
|
||||||
/var/lib/virtuality/network # port_forwards.json
|
|
||||||
/var/lib/virtuality/backups # backups
|
|
||||||
/var/log/virtuality # логи установки и диагностики
|
|
||||||
/var/log/virtuality/operations # JSON/log фоновых операций
|
|
||||||
/etc/virtuality/nftables/virtuality.nft # nftables-правила Virtuality
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Диагностика
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo vhealth
|
|
||||||
```
|
|
||||||
|
|
||||||
Дополнительно:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cat /var/lib/virtuality/config/host_profile.json
|
|
||||||
systemctl status virtuality-web --no-pager
|
|
||||||
journalctl -u virtuality-web -n 120 --no-pager
|
|
||||||
virsh list --all
|
|
||||||
virsh pool-list --all
|
|
||||||
virsh net-list --all
|
|
||||||
virsh net-dhcp-leases virtuality-nat
|
|
||||||
ip -br a
|
|
||||||
ip route
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Web-панель
|
|
||||||
|
|
||||||
URL:
|
|
||||||
|
|
||||||
```text
|
|
||||||
http://SERVER_IP:8088
|
|
||||||
```
|
|
||||||
|
|
||||||
Основные разделы:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/ # дашборд
|
|
||||||
/host # профиль хоста и проверки
|
|
||||||
/iso # ISO-менеджер
|
|
||||||
/network # NAT Router и проброс портов
|
|
||||||
/operations # журнал операций
|
|
||||||
/vm/create # создание VM
|
|
||||||
```
|
|
||||||
|
|
||||||
Переустановка web-панели:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /opt/virtuality/source
|
|
||||||
sudo bash scripts/install_web_panel.sh
|
sudo bash scripts/install_web_panel.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
Статус:
|
Обновление на ноде:
|
||||||
|
|
||||||
```bash
|
|
||||||
systemctl status virtuality-web --no-pager
|
|
||||||
```
|
|
||||||
|
|
||||||
Логи:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
journalctl -u virtuality-web -f
|
|
||||||
```
|
|
||||||
|
|
||||||
Вход:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Login: выбранный Linux-пользователь
|
|
||||||
Pass: пароль этого Linux-пользователя
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Сеть: Bridge и NAT Router
|
|
||||||
|
|
||||||
### Bridge br0
|
|
||||||
|
|
||||||
Подходит для домашнего/офисного сервера, где VM должны получать IP из локальной сети.
|
|
||||||
|
|
||||||
По умолчанию one-command установщик **не включает `br0` автоматически**, чтобы не уронить SSH-сессию.
|
|
||||||
|
|
||||||
Сначала нужно посмотреть сетевой интерфейс:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ip -br a
|
|
||||||
ip route
|
|
||||||
```
|
|
||||||
|
|
||||||
Затем запустить bridge setup, например для `enp2s0`:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /opt/virtuality/source
|
|
||||||
sudo bash scripts/setup_bridge_br0.sh enp2s0 static
|
|
||||||
```
|
|
||||||
|
|
||||||
Ожидаемый результат:
|
|
||||||
|
|
||||||
```text
|
|
||||||
enp2s0 UP
|
|
||||||
br0 UP SERVER_IP/24
|
|
||||||
default via GATEWAY dev br0
|
|
||||||
```
|
|
||||||
|
|
||||||
### Virtuality NAT Router
|
|
||||||
|
|
||||||
Подходит для VPS, Raspberry Pi, Orange Pi 5 и других ARM64 edge nodes.
|
|
||||||
|
|
||||||
Схема:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Интернет / LAN
|
|
||||||
↓
|
|
||||||
Хост Virtuality
|
|
||||||
↓
|
|
||||||
virtuality-nat / virbr100
|
|
||||||
↓
|
|
||||||
VM 192.168.100.x
|
|
||||||
```
|
|
||||||
|
|
||||||
Создать или починить NAT-сеть можно в web-панели:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/network → Создать / починить NAT-сеть
|
|
||||||
```
|
|
||||||
|
|
||||||
Параметры по умолчанию:
|
|
||||||
|
|
||||||
```text
|
|
||||||
Network: virtuality-nat
|
|
||||||
Bridge: virbr100
|
|
||||||
Subnet: 192.168.100.0/24
|
|
||||||
Gateway: 192.168.100.1
|
|
||||||
DHCP: 192.168.100.50–192.168.100.200
|
|
||||||
```
|
|
||||||
|
|
||||||
Проброс порта добавляется в `/network`. IP VM определяется автоматически через `virsh domifaddr`, а если не получилось — через DHCP leases и MAC-адрес VM.
|
|
||||||
|
|
||||||
Пример SSH-проброса:
|
|
||||||
|
|
||||||
```text
|
|
||||||
VM: ubuntu-test
|
|
||||||
Внешний порт сервера: 2222
|
|
||||||
Порт внутри VM: 22
|
|
||||||
Протокол: tcp
|
|
||||||
```
|
|
||||||
|
|
||||||
Подключение:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ssh user@SERVER_IP -p 2222
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ISO и создание VM
|
|
||||||
|
|
||||||
Загрузка ISO через web-панель:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/iso
|
|
||||||
```
|
|
||||||
|
|
||||||
Создание VM:
|
|
||||||
|
|
||||||
```text
|
|
||||||
/vm/create
|
|
||||||
```
|
|
||||||
|
|
||||||
При создании VM можно выбрать сеть:
|
|
||||||
|
|
||||||
```text
|
|
||||||
VPS NAT Router — virtuality-nat
|
|
||||||
Bridge — br0 / локальная сеть
|
|
||||||
```
|
|
||||||
|
|
||||||
Для x86_64 можно использовать обычные x86_64 ISO. Для Raspberry Pi / Orange Pi 5 нужны ARM64 ISO или, в будущем, ARM64 cloud images.
|
|
||||||
|
|
||||||
Пример загрузки Alpine x86_64 ISO:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sudo wget -O /var/lib/virtuality/iso/alpine-standard-x86_64.iso https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/x86_64/alpine-standard-3.20.3-x86_64.iso
|
|
||||||
sudo virsh pool-refresh virtuality-iso
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Обновление
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /opt/virtuality/source
|
cd /opt/virtuality/source
|
||||||
@@ -382,51 +72,61 @@ sudo bash scripts/install_web_panel.sh
|
|||||||
sudo systemctl restart virtuality-web
|
sudo systemctl restart virtuality-web
|
||||||
```
|
```
|
||||||
|
|
||||||
Полная повторная установка компонентов ноды:
|
Доступ после установки:
|
||||||
|
|
||||||
```bash
|
```text
|
||||||
cd /opt/virtuality/source
|
Virtuality UI: http://SERVER_IP:8088
|
||||||
sudo bash install_virtuality_node.sh
|
Cockpit: https://SERVER_IP:9090
|
||||||
sudo bash scripts/install_web_panel.sh
|
VNC: 5900-5999/tcp
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
Локальный запуск панели без установщика возможен (`uvicorn app:app` из `web/` после `pip install -r web/requirements.txt`), но функциональность будет урезана: не применены патч-скрипты, отсутствуют каталоги `/var/lib/virtuality`, `virsh` и права на libvirt. Полноценный dev-режим в репозитории не предусмотрен.
|
||||||
|
|
||||||
## Полезные команды
|
Минимальные требования (из `docs/REQUIREMENTS.md`): 2 ядра с VT-x/AMD-V, 4 GB RAM, 8 GB свободно на `/`, 20 GB под `/var/lib/virtuality`, Ubuntu Server 24.04 LTS или Debian-подобная система с apt.
|
||||||
|
|
||||||
```bash
|
## Конфигурация
|
||||||
sudo vhealth
|
|
||||||
virsh list --all
|
|
||||||
virsh pool-list --all
|
|
||||||
virsh net-list --all
|
|
||||||
virsh net-dhcp-leases virtuality-nat
|
|
||||||
ip -br a
|
|
||||||
ip route
|
|
||||||
sudo nft list ruleset
|
|
||||||
sudo ufw status
|
|
||||||
systemctl status libvirtd --no-pager
|
|
||||||
systemctl status cockpit.socket --no-pager
|
|
||||||
systemctl status virtuality-web --no-pager
|
|
||||||
journalctl -u virtuality-web -f
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
Переменные окружения установщиков (`install.sh`, `bootstrap.sh`):
|
||||||
|
|
||||||
## Roadmap
|
| Переменная | Назначение | Пример / по умолчанию |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `VIRTUALITY_USER` | Linux-пользователь для входа в панель | `viktor`; по умолчанию `SUDO_USER` или `root` |
|
||||||
|
| `VIRTUALITY_WEB_PORT` | Порт web-панели | `8088` |
|
||||||
|
| `VIRTUALITY_REPO_URL` | Источник исходников | `https://github.com/viktor138irk/virtuality.git` |
|
||||||
|
| `VIRTUALITY_INSTALL_URL` | URL самого установщика для self-install | raw.githubusercontent.com/... |
|
||||||
|
| `VIRTUALITY_PROJECT_BASE_DIR` / `VIRTUALITY_PROJECT_DIR` | Куда ставить проект | `/opt/virtuality`, `/opt/virtuality/source` |
|
||||||
|
| `VIRTUALITY_SETUP_BRIDGE` / `VIRTUALITY_BRIDGE_IFACE` | Настроить bridge `br0` и на каком интерфейсе | `0`, пусто |
|
||||||
|
| `VIRTUALITY_CREATE_TEST_VM` | Создать тестовую VM после установки | `0` |
|
||||||
|
| `VIRTUALITY_SKIP_REQUIREMENTS` | Пропустить проверку требований | `0` |
|
||||||
|
| `VIRTUALITY_MIN_ROOT_FREE_MB` / `MIN_VAR_FREE_MB` / `MIN_RAM_MB` / `MIN_CPU_CORES` | Пороги проверки требований | `8192` / `20480` / `4096` / `2` |
|
||||||
|
| `VIRTUALITY_CLEAN_BEFORE_INSTALL` | Очистка перед установкой | `0` |
|
||||||
|
| `VIRTUALITY_INSTALL_VERBOSE` | Подробный вывод установки | `0` |
|
||||||
|
|
||||||
- ARM64 cloud-image templates;
|
Переменные времени выполнения панели (читаются из `/opt/virtuality/virtuality.env` и окружения):
|
||||||
- cloud-init для быстрых VM;
|
|
||||||
- web-console/noVNC;
|
|
||||||
- управление storage pools;
|
|
||||||
- backup/snapshot manager;
|
|
||||||
- сетевой менеджер bridge/VLAN;
|
|
||||||
- роли и права пользователей;
|
|
||||||
- журнал событий;
|
|
||||||
- автообновление;
|
|
||||||
- кластеризация.
|
|
||||||
|
|
||||||
---
|
| Переменная | Назначение | Значение по умолчанию |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `VIRTUALITY_AUTH_USER` | Linux-логин, который принимает форма входа | `viktor` |
|
||||||
|
| `VIRTUALITY_SESSION_SECRET` | Ключ подписи cookie-сессии | `dev-secret-change-me` — при установке генерируется и кладётся в `/var/lib/virtuality/config/session_secret` |
|
||||||
|
| `VIRTUALITY_SOURCE_DIR` | Каталог исходников для центра обновлений | `/opt/virtuality/source` |
|
||||||
|
| `VIRTUALITY_UPDATE_REMOTE` / `VIRTUALITY_UPDATE_BRANCH` | Git-remote и ветка обновлений | `origin` / `main` |
|
||||||
|
| `VIRTUALITY_UPDATE_ZIP_URL` | Резервный zip-источник обновления | архив ветки `main` на GitHub |
|
||||||
|
|
||||||
## Лицензия
|
Пароль пользователя нигде не хранится — проверяется напрямую по системному shadow. Профиль хоста пишется в `/var/lib/virtuality/config/host_profile.json`.
|
||||||
|
|
||||||
Рекомендуемая лицензия: **MIT License**.
|
## Состояние
|
||||||
|
|
||||||
|
Рабочий проект в активной разработке, доведённый до практического применения, но с сырой архитектурой (см. ниже). Версия по `VERSION` — `0.9.6`. 451 коммит, последний — 2026-05-07. С мая 2026 года работа в репозитории остановлена.
|
||||||
|
|
||||||
|
Разработка шла очень интенсивно двое суток (2026-05-06 — 2026-05-07): от «Initial commit» до 0.9.6. Значительная часть коммитов — механические bump-версии и правки вёрстки панели.
|
||||||
|
|
||||||
|
## Что не доделано
|
||||||
|
|
||||||
|
- Патч-архитектура вместо нормального кода. Функциональность панели разложена по ~28 скриптам `scripts/patch_*.py`, которые текстовым поиском/вставкой правят установленный `app.py`. Репозиторный `web/app.py` неполон, порядок применения патчей критичен, повторная сборка хрупкая. Это главный технический долг проекта.
|
||||||
|
- Тесты и CI отсутствуют полностью: нет ни тестов, ни `.github/workflows`, ни линтеров.
|
||||||
|
- Ролевой модели нет: один Linux-пользователь = полный доступ к панели.
|
||||||
|
- HTTPS для панели не настраивается — только HTTP на порту 8088 (у Cockpit свой TLS).
|
||||||
|
- Кластеризация, backup/snapshot, cloud-init/cloud-image шаблоны заявлены в `docs/ROADMAP.md`, но в коде отсутствуют.
|
||||||
|
- Каталог `/var/lib/virtuality/backups` создаётся, но функций резервного копирования в панели нет.
|
||||||
|
- Явных `TODO`/`FIXME` в коде нет; незавершённость выражена в расхождении между ROADMAP и реализацией.
|
||||||
|
- Версия 0.9.6 так и не доведена до 1.0.
|
||||||
|
|||||||
@@ -0,0 +1,432 @@
|
|||||||
|
# Virtuality
|
||||||
|
|
||||||
|
**Virtuality** — лёгкая серверная платформа виртуализации на базе **KVM**, **QEMU**, **libvirt**, **Cockpit** и собственной web-панели.
|
||||||
|
|
||||||
|
Цель проекта — собрать понятную, компактную и расширяемую систему для управления виртуальными машинами, ISO-образами, NAT/bridge-сетью, пробросом портов, диагностикой, web-console/noVNC, backup/snapshot-функциями и будущей кластеризацией.
|
||||||
|
|
||||||
|
> Текущий статус: ранняя стадия разработки. Уже есть one-command установка, автоопределение профиля хоста, web-панель, авторизация через Linux-пользователя, ISO-менеджер, создание VM из интерфейса, журнал операций, NAT Router для VPS/ARM edge nodes и port forwarding.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Поддерживаемые профили хоста
|
||||||
|
|
||||||
|
Virtuality автоматически определяет профиль сборки во время установки:
|
||||||
|
|
||||||
|
```text
|
||||||
|
x86_64 # обычный сервер, домашний сервер, VPS
|
||||||
|
raspberry-arm64 # Raspberry Pi ARM64 edge node
|
||||||
|
orangepi5-arm64 # Orange Pi 5 / RK3588 ARM64 edge node
|
||||||
|
generic-arm64 # другая ARM64-плата
|
||||||
|
```
|
||||||
|
|
||||||
|
Профиль сохраняется здесь:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/var/lib/virtuality/config/host_profile.json
|
||||||
|
```
|
||||||
|
|
||||||
|
В web-панели профиль виден на странице:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/host
|
||||||
|
```
|
||||||
|
|
||||||
|
Для ARM64-плат правильный сценарий — **ARM64-гости**, NAT-сеть и позже cloud-image/cloud-init шаблоны. x86_64 ISO на Raspberry/Orange Pi не являются целевым режимом.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Быстрая установка одной командой
|
||||||
|
|
||||||
|
Одна команда работает и под `root`, и под обычным пользователем с `sudo`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Как выбирается пользователь для входа в web-панель:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Если запуск под root → login: root
|
||||||
|
Если запуск через sudo → login: текущий sudo-пользователь
|
||||||
|
Если задан VIRTUALITY_USER → login: указанный Linux-пользователь
|
||||||
|
```
|
||||||
|
|
||||||
|
Принудительно выбрать пользователя:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_USER=<linux_user> bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Пример:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_USER=admin bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Установка с авторизацией под `root`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_USER=root bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Если пароль выбранного Linux-пользователя не задан:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo passwd <linux_user>
|
||||||
|
```
|
||||||
|
|
||||||
|
Для root:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
passwd root
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Что уже есть
|
||||||
|
|
||||||
|
- универсальная one-command установка через `install.sh`;
|
||||||
|
- автоопределение профиля хоста: x86_64, Raspberry Pi ARM64, Orange Pi 5 ARM64, generic ARM64;
|
||||||
|
- установка разных пакетных наборов под x86 и ARM64;
|
||||||
|
- красивый пошаговый installer с live-status и логами;
|
||||||
|
- preflight-проверка системных требований;
|
||||||
|
- установка KVM/QEMU/libvirt;
|
||||||
|
- установка Cockpit и Cockpit Machines;
|
||||||
|
- рабочая директория `/opt/virtuality/source`;
|
||||||
|
- libvirt storage pools `virtuality-images` и `virtuality-iso`;
|
||||||
|
- firewall-правила для SSH, Cockpit, VNC и web-панели;
|
||||||
|
- безопасная ручная настройка bridge `br0` через `netplan try`;
|
||||||
|
- NAT Router `virtuality-nat` для VPS/ARM edge nodes;
|
||||||
|
- port forwarding через nftables;
|
||||||
|
- автоматическое определение IP VM для проброса портов;
|
||||||
|
- healthcheck одной командой `vhealth`;
|
||||||
|
- консольный dashboard для физического монитора;
|
||||||
|
- web-панель Virtuality на FastAPI;
|
||||||
|
- авторизация web-панели через системного Linux-пользователя;
|
||||||
|
- `/host` — профиль хоста и проверки готовности;
|
||||||
|
- `/network` — NAT, DHCP leases, port forwarding, nftables preview;
|
||||||
|
- `/iso` — ISO-менеджер;
|
||||||
|
- `/operations` — журнал фоновых операций;
|
||||||
|
- список VM;
|
||||||
|
- управление VM: Start, Shutdown, Reboot, Power off, Autostart on/off, Delete VM with disks;
|
||||||
|
- создание VM из web-интерфейса;
|
||||||
|
- выбор сетевого режима при создании VM: `virtuality-nat` или `br0`;
|
||||||
|
- прогресс создания VM и live-лог `virt-install`;
|
||||||
|
- страница деталей VM: `dominfo`, VNC display, IP, диски, сетевые интерфейсы.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Системные требования
|
||||||
|
|
||||||
|
Минимально для x86_64 тестового стенда:
|
||||||
|
|
||||||
|
```text
|
||||||
|
CPU: 2 ядра с Intel VT-x / AMD-V
|
||||||
|
RAM: 4 GB
|
||||||
|
/: минимум 8 GB свободно
|
||||||
|
/var/lib: минимум 20 GB свободно
|
||||||
|
OS: Ubuntu Server 24.04 LTS / Debian-like с apt
|
||||||
|
Network: один проводной интерфейс
|
||||||
|
```
|
||||||
|
|
||||||
|
Рекомендуемо для x86_64:
|
||||||
|
|
||||||
|
```text
|
||||||
|
CPU: 4+ ядра
|
||||||
|
RAM: 16+ GB
|
||||||
|
Storage: 100+ GB SSD/NVMe под /var/lib/virtuality
|
||||||
|
Network: 1 Gbit/s+
|
||||||
|
OS: Ubuntu Server 24.04 LTS
|
||||||
|
```
|
||||||
|
|
||||||
|
ARM64 edge nodes:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Raspberry Pi 4/5 ARM64: желательно 8 GB RAM
|
||||||
|
Orange Pi 5 ARM64: желательно 8/16/32 GB RAM и NVMe
|
||||||
|
Гости: ARM64 Linux VM
|
||||||
|
Сеть: virtuality-nat по умолчанию
|
||||||
|
```
|
||||||
|
|
||||||
|
Подробнее: [`docs/REQUIREMENTS.md`](docs/REQUIREMENTS.md)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Порты
|
||||||
|
|
||||||
|
```text
|
||||||
|
Cockpit: https://SERVER_IP:9090
|
||||||
|
Virtuality UI: http://SERVER_IP:8088
|
||||||
|
VNC: 5900-5999/tcp
|
||||||
|
SSH: 22/tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
Изменить порт web-панели:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -fsSL https://raw.githubusercontent.com/viktor138irk/virtuality/main/install.sh | VIRTUALITY_WEB_PORT=8089 bash
|
||||||
|
```
|
||||||
|
|
||||||
|
Для VPS/ARM NAT-сценария входящие сервисы VM открываются через port forwarding в разделе `/network`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Директории
|
||||||
|
|
||||||
|
```text
|
||||||
|
/opt/virtuality/source # исходники проекта из GitHub
|
||||||
|
/opt/virtuality/web # установленная web-панель
|
||||||
|
/opt/virtuality/venv # Python virtualenv web-панели
|
||||||
|
/opt/virtuality/virtuality.env # базовый env ноды
|
||||||
|
/var/lib/virtuality/config # конфиги Virtuality
|
||||||
|
/var/lib/virtuality/config/host_profile.json
|
||||||
|
/var/lib/virtuality/iso # ISO-образы
|
||||||
|
/var/lib/virtuality/images # qcow2-диски VM
|
||||||
|
/var/lib/virtuality/network # port_forwards.json
|
||||||
|
/var/lib/virtuality/backups # backups
|
||||||
|
/var/log/virtuality # логи установки и диагностики
|
||||||
|
/var/log/virtuality/operations # JSON/log фоновых операций
|
||||||
|
/etc/virtuality/nftables/virtuality.nft # nftables-правила Virtuality
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Диагностика
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo vhealth
|
||||||
|
```
|
||||||
|
|
||||||
|
Дополнительно:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat /var/lib/virtuality/config/host_profile.json
|
||||||
|
systemctl status virtuality-web --no-pager
|
||||||
|
journalctl -u virtuality-web -n 120 --no-pager
|
||||||
|
virsh list --all
|
||||||
|
virsh pool-list --all
|
||||||
|
virsh net-list --all
|
||||||
|
virsh net-dhcp-leases virtuality-nat
|
||||||
|
ip -br a
|
||||||
|
ip route
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Web-панель
|
||||||
|
|
||||||
|
URL:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://SERVER_IP:8088
|
||||||
|
```
|
||||||
|
|
||||||
|
Основные разделы:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/ # дашборд
|
||||||
|
/host # профиль хоста и проверки
|
||||||
|
/iso # ISO-менеджер
|
||||||
|
/network # NAT Router и проброс портов
|
||||||
|
/operations # журнал операций
|
||||||
|
/vm/create # создание VM
|
||||||
|
```
|
||||||
|
|
||||||
|
Переустановка web-панели:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/virtuality/source
|
||||||
|
sudo bash scripts/install_web_panel.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Статус:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl status virtuality-web --no-pager
|
||||||
|
```
|
||||||
|
|
||||||
|
Логи:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
journalctl -u virtuality-web -f
|
||||||
|
```
|
||||||
|
|
||||||
|
Вход:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Login: выбранный Linux-пользователь
|
||||||
|
Pass: пароль этого Linux-пользователя
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Сеть: Bridge и NAT Router
|
||||||
|
|
||||||
|
### Bridge br0
|
||||||
|
|
||||||
|
Подходит для домашнего/офисного сервера, где VM должны получать IP из локальной сети.
|
||||||
|
|
||||||
|
По умолчанию one-command установщик **не включает `br0` автоматически**, чтобы не уронить SSH-сессию.
|
||||||
|
|
||||||
|
Сначала нужно посмотреть сетевой интерфейс:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ip -br a
|
||||||
|
ip route
|
||||||
|
```
|
||||||
|
|
||||||
|
Затем запустить bridge setup, например для `enp2s0`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/virtuality/source
|
||||||
|
sudo bash scripts/setup_bridge_br0.sh enp2s0 static
|
||||||
|
```
|
||||||
|
|
||||||
|
Ожидаемый результат:
|
||||||
|
|
||||||
|
```text
|
||||||
|
enp2s0 UP
|
||||||
|
br0 UP SERVER_IP/24
|
||||||
|
default via GATEWAY dev br0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Virtuality NAT Router
|
||||||
|
|
||||||
|
Подходит для VPS, Raspberry Pi, Orange Pi 5 и других ARM64 edge nodes.
|
||||||
|
|
||||||
|
Схема:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Интернет / LAN
|
||||||
|
↓
|
||||||
|
Хост Virtuality
|
||||||
|
↓
|
||||||
|
virtuality-nat / virbr100
|
||||||
|
↓
|
||||||
|
VM 192.168.100.x
|
||||||
|
```
|
||||||
|
|
||||||
|
Создать или починить NAT-сеть можно в web-панели:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/network → Создать / починить NAT-сеть
|
||||||
|
```
|
||||||
|
|
||||||
|
Параметры по умолчанию:
|
||||||
|
|
||||||
|
```text
|
||||||
|
Network: virtuality-nat
|
||||||
|
Bridge: virbr100
|
||||||
|
Subnet: 192.168.100.0/24
|
||||||
|
Gateway: 192.168.100.1
|
||||||
|
DHCP: 192.168.100.50–192.168.100.200
|
||||||
|
```
|
||||||
|
|
||||||
|
Проброс порта добавляется в `/network`. IP VM определяется автоматически через `virsh domifaddr`, а если не получилось — через DHCP leases и MAC-адрес VM.
|
||||||
|
|
||||||
|
Пример SSH-проброса:
|
||||||
|
|
||||||
|
```text
|
||||||
|
VM: ubuntu-test
|
||||||
|
Внешний порт сервера: 2222
|
||||||
|
Порт внутри VM: 22
|
||||||
|
Протокол: tcp
|
||||||
|
```
|
||||||
|
|
||||||
|
Подключение:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh user@SERVER_IP -p 2222
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ISO и создание VM
|
||||||
|
|
||||||
|
Загрузка ISO через web-панель:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/iso
|
||||||
|
```
|
||||||
|
|
||||||
|
Создание VM:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/vm/create
|
||||||
|
```
|
||||||
|
|
||||||
|
При создании VM можно выбрать сеть:
|
||||||
|
|
||||||
|
```text
|
||||||
|
VPS NAT Router — virtuality-nat
|
||||||
|
Bridge — br0 / локальная сеть
|
||||||
|
```
|
||||||
|
|
||||||
|
Для x86_64 можно использовать обычные x86_64 ISO. Для Raspberry Pi / Orange Pi 5 нужны ARM64 ISO или, в будущем, ARM64 cloud images.
|
||||||
|
|
||||||
|
Пример загрузки Alpine x86_64 ISO:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo wget -O /var/lib/virtuality/iso/alpine-standard-x86_64.iso https://dl-cdn.alpinelinux.org/alpine/v3.20/releases/x86_64/alpine-standard-3.20.3-x86_64.iso
|
||||||
|
sudo virsh pool-refresh virtuality-iso
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Обновление
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/virtuality/source
|
||||||
|
sudo git pull
|
||||||
|
sudo bash scripts/install_web_panel.sh
|
||||||
|
sudo systemctl restart virtuality-web
|
||||||
|
```
|
||||||
|
|
||||||
|
Полная повторная установка компонентов ноды:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/virtuality/source
|
||||||
|
sudo bash install_virtuality_node.sh
|
||||||
|
sudo bash scripts/install_web_panel.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Полезные команды
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo vhealth
|
||||||
|
virsh list --all
|
||||||
|
virsh pool-list --all
|
||||||
|
virsh net-list --all
|
||||||
|
virsh net-dhcp-leases virtuality-nat
|
||||||
|
ip -br a
|
||||||
|
ip route
|
||||||
|
sudo nft list ruleset
|
||||||
|
sudo ufw status
|
||||||
|
systemctl status libvirtd --no-pager
|
||||||
|
systemctl status cockpit.socket --no-pager
|
||||||
|
systemctl status virtuality-web --no-pager
|
||||||
|
journalctl -u virtuality-web -f
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
- ARM64 cloud-image templates;
|
||||||
|
- cloud-init для быстрых VM;
|
||||||
|
- web-console/noVNC;
|
||||||
|
- управление storage pools;
|
||||||
|
- backup/snapshot manager;
|
||||||
|
- сетевой менеджер bridge/VLAN;
|
||||||
|
- роли и права пользователей;
|
||||||
|
- журнал событий;
|
||||||
|
- автообновление;
|
||||||
|
- кластеризация.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
Рекомендуемая лицензия: **MIT License**.
|
||||||
Ссылка в новой задаче
Block a user