# Развёртывание > Пошаговая инструкция «с нуля до работающего сервера на домене» — [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 ГБ) ├── backups/ └── 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` | `https://git.home.lan`, `owner/pipu-music`, read-only токен | Для самообновления 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). ## Бэкапы - `pg_dump` ежедневно (cron-контейнер `backup`), хранить 14 дней + еженедельные 8 недель → `/srv/pipu/backups`. - Meilisearch, кэши и модели **не бэкапятся** — восстанавливаются (`reindex`, повторный транскод / анализ). - Признаки анализа хранятся в Postgres — после восстановления из бэкапа повторный многочасовой анализ не нужен. - Сама музыка — на NFS, вне зоны ответственности приложения. ## Обновление ```bash cd /opt/pipu-music/deploy && ./update.sh # последний релизный тег ``` Скрипт: `git fetch` → checkout тега → `docker compose build --pull` → `up -d` → удаление старых образов → ожидание `/readyz`; миграции применяются при старте api. Конкретная версия или откат: `./update.sh v1.2.4` (миграции пишутся обратно-совместимыми в пределах минорной версии: сначала добавить, потом — в следующем релизе — удалить).