The app no longer dumps Postgres, restores it, or checks copies in CI. Co-authored-by: Cursor <cursoragent@cursor.com>
106 lines
8.1 KiB
Markdown
106 lines
8.1 KiB
Markdown
# Развёртывание
|
||
|
||
> Пошаговая инструкция «с нуля до работающего сервера на домене» — [install-guide.md](install-guide.md).
|
||
> Здесь — справочник: требования, каталоги, сервисы, переменные.
|
||
|
||
## Требования к серверу
|
||
|
||
- Linux x86_64 (нужен mount propagation для storage-agent), Docker 24+, Docker Compose v2.
|
||
- 4+ ядра, 8+ ГБ RAM (аудиоанализ при первом запуске ест CPU; TensorFlow-модели ~1–2 ГБ RAM).
|
||
- Диск: ~5 ГБ под систему и БД + кэш транскодов (по умолчанию 50 ГБ) + обложки (~1 ГБ на 10k альбомов).
|
||
- Сетевой доступ к NFS-серверам.
|
||
|
||
## Каталоги на хосте
|
||
|
||
```
|
||
/srv/pipu/
|
||
├── library/ # точки монтирования источников (storage-agent, rshared)
|
||
├── library-host/ # папка для type=local по умолчанию; обычно вместо неё LIBRARY_HOST=/mnt/music
|
||
├── cache/
|
||
│ ├── transcode/
|
||
│ └── covers/
|
||
├── postgres/
|
||
├── meili/
|
||
├── redis/
|
||
├── models/ # модели Essentia (скачиваются при первом старте analyzer)
|
||
├── updates/ # кэш APK релизов
|
||
├── uploads/ # staging очереди на добавление (размер ≈ лимит очереди, по умолчанию 10 ГБ)
|
||
└── caddy/ # сертификаты Let's Encrypt (если используется compose.tls.yaml)
|
||
```
|
||
|
||
Музыка на локальном диске сервера подключается через `LIBRARY_HOST` в `.env` (например, `/mnt/music`):
|
||
каталог хоста монтируется во все сервисы, включая `storage-agent`, только на чтение (запись появится вместе
|
||
с импортом одобренных загрузок), внутри контейнеров он виден как `/library-host`.
|
||
|
||
Перед первым запуском: `mkdir -p /srv/pipu/library && mount --bind /srv/pipu/library /srv/pipu/library && mount --make-rshared /srv/pipu/library`
|
||
(делает `deploy/install.sh`, плюс systemd-unit для повторения после перезагрузки).
|
||
|
||
## `deploy/compose.yaml`
|
||
|
||
Актуальная конфигурация — сам файл [`deploy/compose.yaml`](../deploy/compose.yaml); здесь — как он устроен.
|
||
|
||
- **Образы собираются на сервере** из клонированного репозитория (`build:` у каждого сервиса, контекст — корень репо),
|
||
в реестр ничего не публикуется. Теги локальные: `pipu-music-<сервис>:<версия>`, версия — `git describe` текущего тега
|
||
(её проставляет `update.sh` в `PIPU_VERSION`).
|
||
|
||
| Сервис | Собирается из | Особенности |
|
||
|---|---|---|
|
||
| `nginx` | `apps/web/Dockerfile` | SPA + конфиг nginx; единственный открытый порт (`HTTP_PORT`) или за Caddy |
|
||
| `api` | `services/api/Dockerfile`, target `api` | Миграции при старте |
|
||
| `storage-agent` | `services/api/Dockerfile`, target `storage-agent` | `CAP_SYS_ADMIN`, `apparmor:unconfined`, библиотека с `propagation: rshared` |
|
||
| `recommender`, `analyzer` | `services/recommender/Dockerfile` (один образ) | Команды `serve` и `analyze --workers 4` |
|
||
| `postgres` | `pgvector/pgvector:0.8.7-pg17` | Healthcheck `pg_isready` |
|
||
| `redis` | `redis:7.4-alpine` | AOF |
|
||
| `meilisearch` | `getmeili/meilisearch:v1.11` | |
|
||
| `caddy` (из `compose.tls.yaml`) | `caddy:2.10-alpine` | HTTPS на `DOMAIN`, nginx тогда без открытых портов |
|
||
|
||
- Библиотека монтируется в `nginx`, `api`, `analyzer` только на чтение с `propagation: rslave`.
|
||
- Наружу открыт только `nginx` (или `caddy`). Все остальные — во внутренней сети compose.
|
||
|
||
## Конфигурация (`.env`)
|
||
|
||
| Переменная | Пример / по умолчанию | Описание |
|
||
|---|---|---|
|
||
| `PIPU_VERSION` | проставляет `update.sh` | Версия собранных образов (`git describe`) |
|
||
| `PUBLIC_URL` | `https://music.home.lan` | Внешний адрес |
|
||
| `DATABASE_URL` | `postgres://pipu:…@postgres:5432/pipu` | |
|
||
| `REDIS_URL` | `redis://redis:6379/0` | |
|
||
| `MEILI_URL`, `MEILI_MASTER_KEY` | | |
|
||
| `JWT_PRIVATE_KEY` | base64 от 32 байт (seed Ed25519) | Подпись access-токенов. Создают `install.sh` / `update.sh`, если его нет; пусто — случайный ключ до перезапуска |
|
||
| `JWT_PREVIOUS_KEYS` | пусто | Прежние ключи через запятую — токены, подписанные ими, ещё принимаются (ротация) |
|
||
| `ACCESS_TOKEN_TTL` | `15m` | Срок access-токена |
|
||
| `COOKIE_SECURE` | `true` | Флаг `Secure` у refresh-cookie; `false` — только для разработки по http не на localhost |
|
||
| `STREAM_SIGNING_KEY` | 32 байта base64 | HMAC подписанных ссылок |
|
||
| `INTERNAL_TOKEN` | случайный | Межсервисная аутентификация |
|
||
| `BOOTSTRAP_ADMIN_USERNAME` | `admin` | |
|
||
| `BOOTSTRAP_ADMIN_PASSWORD` | пусто → сгенерировать и вывести в лог | |
|
||
| `TRANSCODE_CACHE_LIMIT_GB` | `50` | |
|
||
| `TRANSCODE_CONCURRENCY` | `2` | |
|
||
| `GITEA_URL`, `GITEA_REPO`, `GITEA_TOKEN` | пусто — из `git remote` (`install.sh`, `update.sh`); токен — для закрытого репозитория | Самообновление Android и страница `/android` |
|
||
| `PIPU_FILE_UID`, `PIPU_FILE_GID` | `1000` | Владелец файлов, которые агент записывает в принимающие хранилища |
|
||
| `UPLOADS_DIR` | `/uploads` | Staging очереди на добавление (лимит очереди задаётся в админке) |
|
||
| `LOG_LEVEL` | `info` | |
|
||
|
||
## TLS
|
||
|
||
- **Свой домен (рекомендуется)** — `deploy/compose.tls.yaml` добавляет Caddy, который получает и продлевает сертификат
|
||
Let's Encrypt для `DOMAIN` и проксирует на nginx; nginx тогда наружу не открыт. Включается строкой
|
||
`COMPOSE_FILE=compose.yaml:compose.tls.yaml` в `.env`.
|
||
- **Свой reverse proxy** (Traefik, NPM, nginx) — без `compose.tls.yaml`, прокси направляется на `HTTP_PORT`
|
||
(например `127.0.0.1:8081`); нужны `X-Forwarded-*`, тело до 16 МБ, без буферизации ответов.
|
||
- nginx внутри образа `web` берёт схему и IP клиента из `X-Forwarded-Proto` / `X-Forwarded-For`, если запрос пришёл
|
||
из частной сети (docker, LAN).
|
||
- Локальная сеть без домена — свой CA; сертификат CA нужно установить на устройства или включить пиннинг в мобильном (см. mobile.md).
|
||
|
||
Пошаговая установка на домен — [install-guide.md](install-guide.md).
|
||
|
||
## Обновление
|
||
|
||
```bash
|
||
cd /opt/pipu-music/deploy && ./update.sh # последний релизный тег
|
||
```
|
||
Скрипт: `git fetch` → checkout тега → `docker compose build --pull` → `up -d` → удаление старых образов →
|
||
ожидание `/readyz`; миграции применяются при старте api.
|
||
Конкретная версия или откат: `./update.sh v1.2.4` (миграции пишутся обратно-совместимыми в пределах минорной версии: сначала добавить,
|
||
потом — в следующем релизе — удалить).
|