Phase 7: deployment, data import, UI hardening and security fixes
Docker/prod deployment:
- multi-stage Dockerfile (JDK21 build, JRE21 run), docker-compose.prod.yml,
nginx config for lms.our-place.ru, deploy.sh; DEPLOY/IMPORT guides (UI flow)
- Fix Docker 401: LMS_JWT_JWK_SET_URI for academic/progress; forward-headers
Variant distribution (lab page only):
- round-robin by student level, shared random queue across selected groups,
least-used variants, manual pins always preserved; occupied/dup labels
- setup page: single form + one «Сохранить всё», batch level/variant for
selected students (checkboxes)
Grades, defense, materials:
- publication gate + comment lists; defense CSV import (2/3 cols, quotes)
- additional task after defense ("начать заново"); enroll/unenroll students
from group page; temporary-password lock (no navigation until changed) and
persistent "Смена пароля"; forced change once
- chapter page /learn/{c}; header: LMS home, Войти, user -> dashboard,
compact theme toggle; responsive mobile header
- markdown: single newlines are soft breaks; highlight.js with light/dark themes
- lab/content imports ZIP-only (lab.yaml+README+variants/assets,
chapters tree+assets); duplicate lab numbers rejected; variant ordering
and date defaults honored
Fixes:
- 500 on student create (@MapsId set before persist); broken dialogs/JS refs in group page
This commit is contained in:
145
deploy/DEPLOY.md
Normal file
145
deploy/DEPLOY.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# Деплой LMS на сервер `lms.our-place.ru`
|
||||
|
||||
Стек целиком запускается в Docker. **Java на сервере не устанавливается** — приложение
|
||||
собирается и работает внутри контейнеров (multi-stage `Dockerfile`: сборка на JDK 21,
|
||||
запуск на JRE 21).
|
||||
|
||||
Компоненты:
|
||||
|
||||
| Сервис | Контейнер | Наружу |
|
||||
|---|---|---|
|
||||
| web (Thymeleaf UI) | `lms-web` | `127.0.0.1:8090` (проксирует nginx) |
|
||||
| gateway | `lms-gateway` | нет |
|
||||
| identity / academic / progress | `lms-*` | нет |
|
||||
| PostgreSQL 18 | `lms-postgres` | нет |
|
||||
|
||||
Данные лежат в именованных volume: `lms_pgdata` (БД), `lms_submissions` (решения),
|
||||
`lms_assets` (картинки материалов).
|
||||
|
||||
---
|
||||
|
||||
## 0. Что нужно
|
||||
|
||||
- Сервер с Ubuntu 22.04/24.04 (или другим Linux с Docker), sudo/root.
|
||||
- Домен `lms.our-place.ru`, A-запись которого указывает на IP сервера.
|
||||
- Открытые порты 80 и 443 (443 — если настраиваете HTTPS).
|
||||
|
||||
## 1. Установка Docker
|
||||
|
||||
```bash
|
||||
curl -fsSL https://get.docker.com | sudo sh
|
||||
sudo usermod -aG docker "$USER" # перелогиньтесь, чтобы работать без sudo
|
||||
docker compose version # нужна версия v2
|
||||
```
|
||||
|
||||
## 2. Получить код
|
||||
|
||||
```bash
|
||||
sudo mkdir -p /opt/lms && sudo chown "$USER" /opt/lms
|
||||
git clone <URL-репозитория> /opt/lms
|
||||
cd /opt/lms
|
||||
```
|
||||
|
||||
## 3. Настроить окружение
|
||||
|
||||
```bash
|
||||
cp .env.prod.example .env.prod
|
||||
nano .env.prod
|
||||
```
|
||||
|
||||
Обязательно задайте надёжный `LMS_DB_PASSWORD`. Остальные значения по умолчанию подходят.
|
||||
|
||||
## 4. Собрать и запустить
|
||||
|
||||
```bash
|
||||
./deploy/deploy.sh up
|
||||
```
|
||||
|
||||
Скрипт соберёт образы (первый раз ~5–15 минут: скачиваются Gradle и зависимости)
|
||||
и поднимет контейнеры. Проверка:
|
||||
|
||||
```bash
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.prod ps
|
||||
curl -fsS http://127.0.0.1:8090/actuator/health # {"status":"UP",...}
|
||||
```
|
||||
|
||||
## 5. Nginx + HTTPS
|
||||
|
||||
```bash
|
||||
sudo apt-get update && sudo apt-get install -y nginx certbot python3-certbot-nginx
|
||||
sudo mkdir -p /var/www/certbot
|
||||
|
||||
sudo cp deploy/nginx/lms.our-place.ru.conf /etc/nginx/sites-available/lms.our-place.ru.conf
|
||||
sudo ln -sf /etc/nginx/sites-available/lms.our-place.ru.conf /etc/nginx/sites-enabled/lms.our-place.ru.conf
|
||||
sudo rm -f /etc/nginx/sites-enabled/default
|
||||
|
||||
sudo nginx -t && sudo systemctl reload nginx
|
||||
sudo certbot --nginx -d lms.our-place.ru --redirect -m admin@our-place.ru --agree-tos
|
||||
```
|
||||
|
||||
`certbot --nginx` сам добавит TLS-блок и редирект с HTTP на HTTPS. Автопродление
|
||||
уже настроено пакетом (`systemctl status certbot.timer`).
|
||||
|
||||
## 6. Первый запуск приложения
|
||||
|
||||
Откройте `https://lms.our-place.ru` → откроется `/setup` → создайте администратора.
|
||||
|
||||
## 6a. Наполнение данными
|
||||
|
||||
Дальше всё через интерфейс: импорт групп (`.xls`), импорт лабораторной ZIP'ом,
|
||||
раздача вариантов, оценки и защита, материалы. Подробный порядок с проверками —
|
||||
в [`IMPORT.md`](IMPORT.md). Файлы со списками студентов и выгрузками паролей —
|
||||
персональные данные, держите их вне репозитория.
|
||||
|
||||
## 7. Обновление версии
|
||||
|
||||
```bash
|
||||
cd /opt/lms
|
||||
git pull
|
||||
./deploy/deploy.sh up # пересоберёт изменённые образы и перезапустит
|
||||
```
|
||||
|
||||
Миграции БД (Flyway) применяются автоматически при старте сервисов.
|
||||
|
||||
## 8. Резервное копирование
|
||||
|
||||
```bash
|
||||
# БД
|
||||
docker compose -f docker-compose.prod.yml --env-file .env.prod exec -T postgres \
|
||||
pg_dump -U "$LMS_DB_USER" "$LMS_DB_NAME" | gzip > lms-$(date +%F).sql.gz
|
||||
|
||||
# Файлы (решения и материалы)
|
||||
docker run --rm -v lms_lms_submissions:/sub -v lms_lms_assets:/assets -v "$PWD":/backup alpine \
|
||||
tar czf /backup/lms-files-$(date +%F).tar.gz -C / sub assets
|
||||
```
|
||||
|
||||
Восстановление БД: `gunzip -c backup.sql.gz | docker compose ... exec -T postgres psql -U lms lms`.
|
||||
|
||||
## 9. Диагностика
|
||||
|
||||
```bash
|
||||
./deploy/deploy.sh ps
|
||||
./deploy/deploy.sh logs web
|
||||
./deploy/deploy.sh logs gateway
|
||||
./deploy/deploy.sh logs identity
|
||||
```
|
||||
|
||||
Типичные проблемы:
|
||||
|
||||
- **web отдаёт 502 через nginx** — контейнер `web` не поднялся: смотрите `logs web`.
|
||||
Часто причина — занят порт 8090 или не задан `LMS_DB_PASSWORD` (compose не стартует).
|
||||
- **Страница входа открывается, но запросы падают** — проверьте `logs gateway` и
|
||||
`logs identity`; gateway должен получить JWKS от identity.
|
||||
- **401 на страницах после входа (Docker)** — у backend-сервисов не задан адрес
|
||||
JWKS: должно быть `LMS_JWT_JWK_SET_URI=http://identity:8081/api/v1/auth/jwks.json`
|
||||
(уже прописано в `docker-compose.prod.yml` для academic/progress/gateway).
|
||||
Внутри контейнера `localhost:8081` недоступен, поэтому токен не проверяется.
|
||||
- **Не проходят загрузки больших ZIP** — увеличьте `client_max_body_size` в nginx
|
||||
(сейчас 120 МБ) и `spring.servlet.multipart.max-request-size`.
|
||||
|
||||
## Замечания по безопасности
|
||||
|
||||
- PostgreSQL наружу не публикуется; связь между контейнерами — по внутренней сети `lms`.
|
||||
- Публикуется только `127.0.0.1:8090`, доступ снаружи — исключительно через nginx/TLS.
|
||||
- `.env.prod` содержит пароль БД и не коммитится (в `.gitignore`).
|
||||
- Пароль администратора задаётся вами на шаге 6; хранение — BCrypt.
|
||||
Reference in New Issue
Block a user