deploy: compose.truenas.yml + инструкция под SCALE/сборку-на-NAS
- compose.truenas.yml: готовый host-path compose (build на NAS / или image), env с JWT_SECRET/CLIENT_ORIGIN, healthcheck start_period 40s (запас на первичные миграции). - DEPLOY-TRUENAS.md: переписан под реальный кейс (TrueNAS SCALE, сборка образа на NAS, без Docker на ПК): датасет → код по SMB → docker build → правка JWT/пути → docker compose up / Custom App → проверка → домен/HTTPS/бэкапы. PC-сборка и CORE — в конце. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+89
-90
@@ -1,118 +1,117 @@
|
||||
# Запуск LearnSpace на TrueNAS
|
||||
# Установка LearnSpace на TrueNAS SCALE
|
||||
|
||||
Коротко: **TrueNAS SCALE** (Linux) запускает приложение как **Docker-контейнер** — в репозитории уже
|
||||
есть `Dockerfile` и `docker-compose.yml`. **TrueNAS CORE** (FreeBSD) Docker не умеет — там нужен Linux-VM
|
||||
или jail с Node (см. конец). Ниже — путь для **SCALE** (рекомендуемый).
|
||||
Пошаговая инструкция под **твой случай: TrueNAS SCALE, сборка образа прямо на NAS**
|
||||
(на рабочем ПК Docker не нужен). В репозитории уже есть `Dockerfile`, `docker-entrypoint.sh`
|
||||
и готовый `compose.truenas.yml`.
|
||||
|
||||
Контейнер **самоинициализируется**: при старте применяет миграции БД и при первом запуске засевает права
|
||||
(`docker-entrypoint.sh`). Данные (SQLite-БД, загрузки, бэкапы) хранятся в томах, переживают пересоздание.
|
||||
Контейнер **самоинициализируется**: при старте применяет миграции БД, при первом запуске засевает права.
|
||||
Данные (SQLite-БД, загрузки, бэкапы) лежат на датасете и переживают пересоздание/обновление контейнера.
|
||||
|
||||
> CORE (FreeBSD) Docker не умеет — см. раздел в конце. Если у тебя CORE — скажи, распишу отдельно.
|
||||
|
||||
---
|
||||
|
||||
## 1. Подготовка хранилища (dataset)
|
||||
## Шаг 1. Датасет под данные
|
||||
|
||||
В TrueNAS создайте датасет под приложение и в нём подпапки для постоянных данных:
|
||||
TrueNAS → **Datasets → Add Dataset**: создай `tank/apps/learnspace` (вместо `tank` — имя своего пула).
|
||||
Затем создай в нём три папки (через **System → Shell** или по SMB):
|
||||
```sh
|
||||
mkdir -p /mnt/tank/apps/learnspace/{data,uploads,backups}
|
||||
```
|
||||
Здесь будут жить БД, загрузки и бэкапы. Их защищают снапшоты/репликация TrueNAS.
|
||||
|
||||
```
|
||||
Datasets → Add Dataset: tank/apps/learnspace
|
||||
```
|
||||
Внутри (через Shell или по SMB) создайте три папки — БД, загрузки, бэкапы:
|
||||
```
|
||||
/mnt/tank/apps/learnspace/data
|
||||
/mnt/tank/apps/learnspace/uploads
|
||||
/mnt/tank/apps/learnspace/backups
|
||||
```
|
||||
Они монтируются в контейнер; их защищают снапшоты/репликация TrueNAS.
|
||||
## Шаг 2. Положить код проекта на NAS
|
||||
|
||||
## 2. Доставить образ на NAS (3 варианта)
|
||||
Самое простое — по SMB скопировать папку репозитория в датасет, например в
|
||||
`/mnt/tank/apps/learnspace/src` (нужны `Dockerfile`, `compose.truenas.yml`, `backend/`, `frontend/`, `js/`,
|
||||
`docker-entrypoint.sh`). Папку `node_modules` копировать НЕ нужно — образ ставит зависимости сам.
|
||||
|
||||
**A. Собрать на машине с Docker и перенести** (без реестра):
|
||||
```bash
|
||||
# на ПК с Docker, в корне репозитория:
|
||||
Либо, если у NAS есть доступ к git-серверу:
|
||||
```sh
|
||||
cd /mnt/tank/apps/learnspace
|
||||
git clone <адрес-репозитория> src
|
||||
```
|
||||
|
||||
## Шаг 3. Включить SSH и собрать образ
|
||||
|
||||
System → **Services → SSH** → включить. Зайти в шелл NAS (ssh root@IP_NAS) и собрать:
|
||||
```sh
|
||||
cd /mnt/tank/apps/learnspace/src
|
||||
docker build -t learnspace:latest .
|
||||
docker save learnspace:latest | gzip > learnspace.tar.gz
|
||||
# скопировать learnspace.tar.gz на NAS (SMB/scp), затем в Shell TrueNAS:
|
||||
docker load < /mnt/tank/apps/learnspace/learnspace.tar.gz
|
||||
```
|
||||
(Сборка скачает зависимости и займёт пару минут.)
|
||||
|
||||
## Шаг 4. Настроить параметры запуска
|
||||
|
||||
Открой `compose.truenas.yml` (в папке src) и поправь **три вещи**:
|
||||
1. Пути `/mnt/tank/apps/learnspace/...` — под свой пул, если он не `tank`.
|
||||
2. `JWT_SECRET` — длинная случайная строка. Сгенерируй прямо на NAS:
|
||||
```sh
|
||||
openssl rand -hex 32
|
||||
```
|
||||
и вставь значение.
|
||||
3. `CLIENT_ORIGIN` — адрес, по которому будешь открывать сайт (пока `http://IP_NAS:3000`, позже домен с https).
|
||||
|
||||
## Шаг 5. Запустить
|
||||
|
||||
**Способ 1 — командой (просто):**
|
||||
```sh
|
||||
cd /mnt/tank/apps/learnspace/src
|
||||
docker compose -f compose.truenas.yml up -d
|
||||
```
|
||||
|
||||
**B. Через реестр** (Docker Hub / GHCR / локальный): `docker push <registry>/learnspace:latest`,
|
||||
а в compose указать этот `image:`.
|
||||
**Способ 2 — через UI TrueNAS (интегрированно, app виден в Apps):**
|
||||
Apps → **Discover Apps → Custom App → Install via YAML** → вставь содержимое `compose.truenas.yml`
|
||||
(этот способ — для SCALE 24.10 «ElectricEel» и новее; на 24.04 «Dragonfish» и старше используй Способ 1).
|
||||
|
||||
**C. Собрать прямо на NAS** (SCALE ElectricEel 24.10+ имеет Docker CLI): склонировать репозиторий в
|
||||
датасет и `docker compose build` (см. ниже).
|
||||
Первый старт сам накатит миграции и засеет права — отдельных команд не нужно.
|
||||
|
||||
## 3. Развернуть как Custom App (Compose YAML)
|
||||
## Шаг 6. Проверить
|
||||
|
||||
TrueNAS SCALE → **Apps → Discover Apps → Custom App → Install via YAML** (на ElectricEel+ это нативный
|
||||
docker-compose). Вставьте (правьте пути пула, порт и **обязательно JWT_SECRET**):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
image: learnspace:latest # из шага 2 (или build: . если собираете на NAS)
|
||||
container_name: learnspace
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000" # снаружи:внутри. Поменяйте левую часть при конфликте
|
||||
volumes:
|
||||
- /mnt/tank/apps/learnspace/data:/app/backend/data
|
||||
- /mnt/tank/apps/learnspace/uploads:/app/backend/uploads
|
||||
- /mnt/tank/apps/learnspace/backups:/app/backups
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- PORT=3000
|
||||
- JWT_SECRET=ЗАМЕНИТЕ_на_длинную_случайную_строку # обязательно! напр. `openssl rand -hex 32`
|
||||
- JWT_EXPIRES_IN=7d
|
||||
- DB_PATH=/app/backend/data/learnspace.db
|
||||
- UPLOADS_DIR=/app/backend/uploads
|
||||
- CLIENT_ORIGIN=https://learn.example.com # публичный адрес (для CORS); или http://<ip>:3000
|
||||
# необязательно — TURN для видеосвязи за NAT (классы/доска):
|
||||
# - TURN_URL=turn:turn.example.com:3478
|
||||
# - TURN_USER=...
|
||||
# - TURN_PASS=...
|
||||
# необязательно — LLM «Спроси» (Groq и т.п.):
|
||||
# - ASSISTANT_LLM_URL=https://api.groq.com/openai/v1/chat/completions
|
||||
# - ASSISTANT_LLM_KEY=...
|
||||
# - ASSISTANT_LLM_MODEL=llama-3.3-70b-versatile
|
||||
```sh
|
||||
docker logs -f learnspace
|
||||
```
|
||||
Ожидаемо: `applying migrations...` → (на первом старте) `seeding permissions...` → `starting server...`
|
||||
→ `Server running on port 3000`. Через ~30–40 с healthcheck станет «healthy».
|
||||
|
||||
Сгенерировать секрет: в Shell TrueNAS `openssl rand -hex 32`.
|
||||
Открой в браузере **http://IP_NAS:3000** и зарегистрируй первого пользователя.
|
||||
(Нужен сразу админ — скажи, добавлю команду/скрипт создания админа.)
|
||||
|
||||
## 4. Первый запуск
|
||||
## Шаг 7. Домен и HTTPS (рекомендуется)
|
||||
|
||||
При старте entrypoint сам накатит миграции и засеет права — отдельных команд не нужно. Проверьте:
|
||||
- **Apps → learnspace → Logs**: должно быть `applying migrations...` → `starting server...` → `Server running on port 3000`.
|
||||
- Healthcheck (`/api/health`) станет «healthy» через ~10–30 с.
|
||||
Порт 3000 — внутренний. Для домена с HTTPS поставь reverse-proxy (TrueNAS app **Nginx Proxy Manager**
|
||||
или **Traefik**, либо внешний nginx) → проксировать на `IP_NAS:3000`. В `CLIENT_ORIGIN` укажи итоговый
|
||||
публичный URL (иначе CORS заблокирует фронт). Для видеосвязи в классах за CGNAT/симметричным NAT нужен
|
||||
TURN-сервер (coturn) — пропиши `TURN_URL/TURN_USER/TURN_PASS`.
|
||||
|
||||
Откройте `http://<IP_NAS>:3000`. Создайте первого пользователя через регистрацию (или заведите админа —
|
||||
скажите, добавлю команду/скрипт сидинга админа).
|
||||
## Обновление версии
|
||||
|
||||
## 5. HTTPS и домен (рекомендуется)
|
||||
1. Обнови код в `src` (git pull или перекопируй).
|
||||
2. Пересобери и перезапусти:
|
||||
```sh
|
||||
cd /mnt/tank/apps/learnspace/src
|
||||
docker compose -f compose.truenas.yml up -d --build
|
||||
```
|
||||
Данные сохранятся (тома на датасете), новые миграции применятся автоматически.
|
||||
|
||||
Порт 3000 — внутренний. Для доступа по домену с HTTPS поставьте reverse-proxy:
|
||||
- TrueNAS app **Traefik**/**Nginx Proxy Manager**, либо внешний nginx → проксировать на `<IP_NAS>:3000`.
|
||||
- В `CLIENT_ORIGIN` укажите итоговый публичный URL (иначе CORS заблокирует фронт).
|
||||
- Для классов/доски (WebRTC) за CGNAT/симметричным NAT нужен TURN-сервер (coturn) — иначе p2p может не подняться.
|
||||
## Бэкапы
|
||||
|
||||
## 6. Обновление версии
|
||||
|
||||
1. Пересоберите образ новой версии (шаг 2) с тем же тегом или новым.
|
||||
2. Apps → learnspace → **Edit** (обновите `image:` если тег сменился) → **Update**, либо пересоздайте app.
|
||||
3. Данные сохранятся (тома на датасете). Миграции применятся автоматически при старте.
|
||||
|
||||
## 7. Бэкапы
|
||||
|
||||
Данные в `/mnt/tank/apps/learnspace/{data,uploads}`. Настройте **снапшоты датасета** + при желании
|
||||
**репликацию**. SQLite-файл — `data/learnspace.db` (консистентный бэкап лучше делать при остановленном app
|
||||
или через снапшот ZFS).
|
||||
Данные — в `/mnt/tank/apps/learnspace/{data,uploads}`. Настрой **снапшоты датасета** (+ репликацию при желании).
|
||||
SQLite-файл — `data/learnspace.db`; консистентный бэкап лучше делать снапшотом ZFS или при остановленном app.
|
||||
|
||||
---
|
||||
|
||||
## Альтернатива: собрать на ПК (если поставишь Docker Desktop)
|
||||
|
||||
```bash
|
||||
docker build -t learnspace:latest .
|
||||
docker save learnspace:latest | gzip > learnspace.tar.gz # перенести файл на NAS
|
||||
```
|
||||
На NAS: `docker load < learnspace.tar.gz`, затем в `compose.truenas.yml` заменить `build: .` на
|
||||
`image: learnspace:latest` и выполнить Шаги 4–6.
|
||||
|
||||
## TrueNAS CORE (FreeBSD) — без Docker
|
||||
|
||||
CORE не запускает Docker-контейнеры. Варианты:
|
||||
- **Linux-VM** в TrueNAS CORE (если включён bhyve) → внутри VM поставить Docker и следовать инструкции SCALE выше.
|
||||
- **Jail** с Node 22+: установить node, `npm ci --omit=dev` в `backend/`, прописать env, `npm run migrate &&
|
||||
npm run seed:permissions`, запускать `node src/server.js` под supervisor (pm2/rc.d). node:sqlite требует Node ≥ 22.
|
||||
|
||||
> Какой у вас TrueNAS (SCALE или CORE) и версия — подскажу точные шаги под конкретный вариант.
|
||||
CORE контейнеры не запускает. Варианты: **Linux-VM** (bhyve) с Docker внутри → следовать инструкции выше;
|
||||
либо **jail** с Node ≥ 22: `npm ci --omit=dev` в `backend/`, прописать env, `npm run migrate &&
|
||||
npm run seed:permissions`, запускать `node src/server.js` под supervisor (pm2/rc.d).
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# LearnSpace — деплой на TrueNAS SCALE (host-path тома на датасет).
|
||||
# Запуск из папки с кодом на NAS: docker compose -f compose.truenas.yml up -d
|
||||
# ⚠️ Перед запуском поправь:
|
||||
# 1) пути /mnt/tank/apps/learnspace/... под свой пул/датасет;
|
||||
# 2) JWT_SECRET — длинная случайная строка (на NAS: openssl rand -hex 32);
|
||||
# 3) CLIENT_ORIGIN — публичный адрес, по которому открываешь сайт.
|
||||
services:
|
||||
app:
|
||||
build: . # собрать образ из этого репозитория прямо на NAS
|
||||
# image: learnspace:latest # ← вместо build: ., если образ уже собран/загружен (docker load)
|
||||
container_name: learnspace
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "3000:3000" # внешний:внутренний — поменяй левую часть при конфликте порта
|
||||
volumes:
|
||||
- /mnt/tank/apps/learnspace/data:/app/backend/data # SQLite-БД (learnspace.db)
|
||||
- /mnt/tank/apps/learnspace/uploads:/app/backend/uploads # загрузки (картинки и т.п.)
|
||||
- /mnt/tank/apps/learnspace/backups:/app/backups # бэкапы
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- PORT=3000
|
||||
- JWT_SECRET=ЗАМЕНИ_НА_СЛУЧАЙНУЮ_СТРОКУ # openssl rand -hex 32 — обязательно!
|
||||
- JWT_EXPIRES_IN=7d
|
||||
- DB_PATH=/app/backend/data/learnspace.db
|
||||
- UPLOADS_DIR=/app/backend/uploads
|
||||
- CLIENT_ORIGIN=http://NAS_IP:3000 # публичный URL (для CORS); потом — домен с https
|
||||
# --- необязательно ---
|
||||
# TURN для видеосвязи (классы/доска) за NAT:
|
||||
# - TURN_URL=turn:turn.example.com:3478
|
||||
# - TURN_USER=user
|
||||
# - TURN_PASS=pass
|
||||
# LLM «Спроси» (Groq и т.п.):
|
||||
# - ASSISTANT_LLM_URL=https://api.groq.com/openai/v1/chat/completions
|
||||
# - ASSISTANT_LLM_KEY=
|
||||
# - ASSISTANT_LLM_MODEL=llama-3.3-70b-versatile
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/health"]
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
start_period: 40s # запас на первичные миграции при первом старте
|
||||
retries: 3
|
||||
Reference in New Issue
Block a user