Развёртывание
Деплой через Makefile
# Первый раз: сгенерировать пароли
make generate-passwords
# Деплой всего стека (QMServer Cloud, QMAdmin, QMWeb, QMDocs)
make deploy
Синхронизация каталогов проекта на сервер в $(DEPLOY_PATH) (по умолчанию /opt/qmserver) выполняется через rsync с --delete: файлы и папки, которые вы удалили в репозитории, удаляются и на хосте (внутри зеркалируемого дерева). Исключение — копирование конфигов в /etc/nginx/: там --delete не используется, чтобы не трогать сторонние файлы в conf.d и sites-available.
QMServer в Docker: образ ghcr.io/<GHCR_OWNER>/qmserver (Cloud-сборка, -tags cloud), подставляется из .env.cloud / .env (GHCR_OWNER — владелец пакетов на GitHub). При таргете make deploy на сервер зеркалируются исходники QMServer/ (и др.) для отладки и Swagger, а контейнер qmserver поднимается с уже собранного образа (make build-all-cloud делает pull для QMServer и build для QMAdmin/QMWeb/QMDocs). Платформа образа — Linux x86_64 (amd64) (platform: linux/amd64).
Публичная сборка в Docker: docker-compose.yaml → образ ghcr.io/<GHCR_OWNER>/qmserver:free-latest (тот же пакет qmserver, что и Cloud; workflow build-qmserver-public-image).
Без Docker: один исполняемый qmserver и systemd — см. QMServer — Запуск и deploy/systemd/ в репозитории QMServer. Сценарий install.sh (нативно или Docker Compose): QMServer.
Репозиторий mindevis/QMServer — единый код; варианты сборки описаны в BUILD.md в том репозитории. Один пакет GHCR ghcr.io/<owner>/qmserver: теги latest (Cloud) и free-latest (публичная сборка).
Только QMAdmin без монорепозитория: образ ghcr.io/<owner>/qmadmin, релизы со статикой qmadmin-*-dist.tar.gz, сценарий install.sh (QMAdmin) — репозиторий mindevis/QMAdmin.
Только QMWeb без монорепозитория: образ ghcr.io/<owner>/qmweb, релизы qmweb-*-dist.tar.gz, install.sh (QMWeb) — mindevis/QMWeb.
Отдельные цели deploy-qmadmin, deploy-qmweb, deploy-qmserver, deploy-qmdocs, deploy-images используют тот же принцип для своих деревьев под DEPLOY_PATH.
QMDocs — статический сайт: в каталоге QMDocs выполняется npm ci (или npm install) и npm run build; артефакты каталога build/ отдаются через Nginx на хосте (порт 8243 в таблице ниже). Для Kubernetes используйте образ со статикой, например ghcr.io/<owner>/qmdocs:<tag>, собранный из Dockerfile в репозитории QMDocs — манифесты deploy/k3s/ в корневом монорепозитории (09-qmdocs.yaml, render.py, хост DOCS_HOST).
Фронтенды QMAdmin и QMWeb (Vite): базовый URL API задаётся переменной QMSERVER_API_URL на этапе npm run build / docker build (вшивается в статику). В docker-compose.cloud.yaml в оба образа передаётся build-arg QMSERVER_API_URL=${QMSERVER_PUBLIC_URL}/api/v1 (см. env.cloud.example). Локально — файлы .env в каталогах QMAdmin и QMWeb (образцы: .env.example). В vite.config у обоих приложений указано envPrefix: ['VITE_', 'QMSERVER_'], поэтому QMSERVER_* и прежние VITE_* (например ссылки QMClient, лаунчер в QMWeb) доступны в import.meta.env.
Стек согласован так: QMAdmin, QMWeb и (при облачных настройках) QMLauncher обращаются к QMServer по одному базовому URL API. После развёртывания в QMAdmin обычно включают нужные модули (в Cloud — в т.ч. QMBilling; во Free — без биллинга) и интеграции (QMLauncher, QMWeb; в Cloud при необходимости Removed auth stack). Иначе часть API для клиентов будет недоступна (см. QMServer). Синхронизация инвентаря (POST /api/v1/inventory, QXSync, coming soon) на QMServer действует при модуле Minecraft и интеграции QMWeb — см. Синхронизация инвентаря. В env.cloud.example кратко описаны флаги по умолчанию.
Компоненты на сервере
| Сервис | Порт | Домен |
|---|---|---|
| QMServer | 8240 | api.qx-dev.ru |
| QMAdmin | 8241 | admin.qx-dev.ru |
| QMWeb | 8242 | web.qx-dev.ru |
| QMDocs | 8243 | qm.qx-dev.ru |
| Removed auth stack (Auth) | (Ingress) | auth.qx-dev.ru — отдельный сервис OAuth2/JWKS в стеке k3s; см. AUTH_HOST в deploy/k3s/ |
| Nginx (на хосте) | 80, 443 | Reverse proxy → 127.0.0.1:8240–8243 |
Nginx (на хосте)
Nginx устанавливается на хост, не в Docker. При деплое конфиги из nginx/sites-available/ копируются в /etc/nginx/sites-available/, в /etc/nginx/sites-enabled/ создаются симлинки на них.
api.qx-dev.ru.conf→ 127.0.0.1:8240admin.qx-dev.ru.conf→ 127.0.0.1:8241web.qx-dev.ru.conf→ 127.0.0.1:8242qm.qx-dev.ru.conf→ 127.0.0.1:8243
Kubernetes (K3s)
В корневом монорепозитории каталог deploy/k3s/: QMServer, QMAdmin, QMWeb, QMDocs, MySQL в кластере (обязателен для QMServer), Ingress (Traefik). Скрипт render.py подставляет образы (ghcr.io/<GHCR_OWNER>/…) и хосты; задайте GHCR_OWNER, API_HOST, ADMIN_HOST, WEB_HOST, DOCS_HOST (и при необходимости QMDOCS_IMAGE и др.). Автоматическая установка K3s (если ещё нет) и выкладка стека — install_k3s_qm.py (--cloud или --free); токен для worker-нод выводится в конце. Для --cloud обязателен лицензионный ключ и привязка к окружению (внешние IP без маски на интерфейсе сервера, hostNetwork у qmserver в K8s; machine-id и/или имена нод) — см. deploy/k3s/README.md. Пошагово — deploy/k3s/README.md в корне монорепозитория qm-project.
Helm
Альтернатива render.py + kubectl apply — чарт deploy/helm/qm-project: те же манифесты (Namespace, MySQL, QMServer, QMAdmin, QMWeb, QMDocs, Ingress), параметры задаются через values.yaml или helm upgrade … -f / --set. Полная инструкция — deploy/helm/README.md в монорепозитории.
- Установка с нуля:
helm upgrade --install qm ./deploy/helm/qm-project -n qm --create-namespace -f my-values.yaml - Секреты
qm-mysqlиqm-appчарт не создаёт — их нужно завести так же, как для плоских манифестов (раздел «Секреты» вdeploy/k3s/README.mdили скриптinstall_k3s_qm.py). - Приватный GHCR: в values укажите
imagePullSecrets(и при необходимости создайтеdocker-registrysecret на кластере).
Миграция на Helm при уже работающем кластере
Если стек уже развёрнут через render.py и работает, управление можно передать Helm без удаления данных БД и файлов:
- Подготовьте
valuesс теми же хостами Ingress и образами, что сейчас в кластере. - Запустите
deploy/helm/migrate-from-kubectl.py(из каталогаdeploy/helm): скрипт сохраняет дамп ресурсов, удаляет только Ingress, Deployments, StatefulSet MySQL, Services и ConfigMaps; Secrets и PVC не трогает; затем выполняетhelm upgrade --installсpersistence.create=false, чтобы не пересоздавать существующиеqmserver-dataиqmweb-uploads. Пример values —deploy/helm/values-migrate.example.yaml.
На время пересоздания подов возможен краткий простой. Откат релиза Helm: helm rollback qm -n qm. Подробности — снова deploy/helm/README.md.
Обновление образов в k3s (например QMWeb)
Без Helm (как в deploy/k3s/README.md):
kubectl -n qm set image deployment/qmweb nginx=ghcr.io/<GHCR_OWNER>/qmweb:<тег>
kubectl -n qm rollout status deployment/qmweb
С Helm:
helm upgrade qm ./deploy/helm/qm-project -n qm --reuse-values --set imageTag=<тег>
# или полный ref:
helm upgrade qm ./deploy/helm/qm-project -n qm --reuse-values --set images.qmweb=ghcr.io/<GHCR_OWNER>/qmweb:<тег>
Образы должны быть доступны в реестре (для приватного GHCR — pull-secret на ноде).
Релизы QMWeb и текст из CHANGELOG на GitHub
В репозитории QMWeb workflow CI подставляет в описание GitHub Release содержимое секции ## [<версия>] из CHANGELOG.md (номер версии совпадает с package.json). Автогенерация заметок только по коммитам для этого шага отключена. Как задаётся версия и теги образов — см. QMWeb/CHANGELOG.md и комментарии в workflow .github/workflows/build-qmweb-image.yml.
DNS
Настроить A-записи для доменов на IP сервера:
- api.qx-dev.ru
- admin.qx-dev.ru
- web.qx-dev.ru
- qm.qx-dev.ru
- auth.qx-dev.ru (портал Removed auth stack в k3s, см.
AUTH_HOSTвdeploy/k3s/install_k3s_qm.pyи README)
Removed auth stack Auth
Публичный URL портала Removed auth stack в продакшене (пример): https://auth.qx-dev.ru. Он не заменяет redirect_uri для PKCE у QMAdmin/QMWeb/QMDocs: те URL задаются при сборке (VITE_LEGACY_ENV_) и должны быть перечислены в LEGACY_ENV_ на QMServer. Подробности — QMServer — Removed auth stack OAuth2 PKCE.
Swagger / ReDoc
Документация API доступна по адресам:
- Swagger UI: https://api.qx-dev.ru/docs (редирект на /swagger) или https://api.qx-dev.ru/swagger/index.html
- ReDoc: https://api.qx-dev.ru/redoc
SSL и CloudFlare
Nginx настроен для работы с CloudFlare:
- Редирект HTTP → HTTPS
- Real IP из заголовка CF-Connecting-IP
- Gzip сжатие
- Кэширование статики (JS, CSS, изображения)
Сертификаты Let's Encrypt в /etc/letsencrypt/live/DOMAIN/:
fullchain.pem,privkey.pem
Выпустите сертификаты заранее (certbot) для каждого домена. В каждом конфиге указан путь по имени домена.
Ely.by OAuth (привязка аккаунта Ely.by)
Для использования скинов Ely.by пользователям нужно привязать аккаунт Ely.by. Настройка:
- Зарегистрировать приложение на account.ely.by/dev/applications/new (тип: Website).
- Указать Redirect URI:
https://api.qx-dev.ru/api/v1/auth/ely/callback(или ваш домен API). - Добавить в
.env.cloud(передаётся в QMServer при deploy):ELY_CLIENT_ID— Client ID из приложенияELY_CLIENT_SECRET— Client SecretELY_REDIRECT_URI— тот же URL, что в п.2 (напримерhttps://api.qx-dev.ru/api/v1/auth/ely/callback)ELY_FRONTEND_REDIRECT—https://web.qx-dev.ru(куда редиректить после OAuth)