ci / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 47s
ci / api (push) Successful in 53s
ci / recommender (push) Successful in 37s
ci / ts (packages + web) (push) Successful in 38s
ci / mobile (Metro-бандл Android) (push) Successful in 52s
- docs/install-guide.md: step-by-step server setup (DNS, Docker, install.sh, .env, launch, checks), web and Android client setup, own reverse proxy variant, updates, backups and troubleshooting - deploy/compose.tls.yaml + Caddyfile: optional Caddy with automatic Let's Encrypt in front of nginx (enabled via COMPOSE_FILE in .env) - nginx: honour X-Forwarded-Proto/For from private networks - .env.example: DOMAIN, ACME_EMAIL, COMPOSE_FILE, bootstrap admin vars - install.sh: create caddy data dirs; release.yml: ship TLS files as assets - deployment.md, docs index and README link to the guide Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
7.9 KiB
7.9 KiB
Развёртывание
Пошаговая инструкция «с нуля до работающего сервера на домене» — 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
├── cache/
│ ├── transcode/
│ └── covers/
├── postgres/
├── meili/
├── redis/
├── models/ # модели Essentia (скачиваются при первом старте analyzer)
├── updates/ # кэш APK релизов
├── uploads/ # staging очереди на добавление (размер ≈ лимит очереди, по умолчанию 10 ГБ)
├── backups/
└── caddy/ # сертификаты Let's Encrypt (если используется compose.tls.yaml)
Перед первым запуском: 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 (сокращённо)
x-library-ro: &library-ro
type: bind
source: /srv/pipu/library
target: /library
read_only: true
bind: { propagation: rslave }
services:
nginx:
image: ${REGISTRY}/pipu-music-web:${PIPU_VERSION}
ports: ["443:443", "80:80"]
volumes:
- *library-ro
- /srv/pipu/cache:/cache:ro
- /srv/pipu/uploads:/uploads:ro # прослушивание очереди админом (internal location)
- ./certs:/etc/nginx/certs:ro
depends_on: [api]
api:
image: ${REGISTRY}/pipu-music-api:${PIPU_VERSION}
env_file: .env
volumes:
- *library-ro
- /srv/pipu/cache:/cache
- /srv/pipu/updates:/updates
- /srv/pipu/uploads:/uploads
depends_on: [postgres, redis, meilisearch, storage-agent]
storage-agent:
image: ${REGISTRY}/pipu-music-storage-agent:${PIPU_VERSION}
cap_add: [SYS_ADMIN]
security_opt: ["apparmor:unconfined"]
volumes:
- type: bind
source: /srv/pipu/library
target: /library
bind: { propagation: rshared }
- /srv/pipu/uploads:/uploads:ro # читает staging при импорте
# /library-rw/<id> монтируется агентом внутри своего контейнера, наружу не пробрасывается
environment: [INTERNAL_TOKEN, DATABASE_URL, PIPU_FILE_UID, PIPU_FILE_GID]
recommender:
image: ${REGISTRY}/pipu-music-recommender:${PIPU_VERSION}
command: ["serve"]
env_file: .env
depends_on: [postgres, redis]
analyzer:
image: ${REGISTRY}/pipu-music-recommender:${PIPU_VERSION}
command: ["analyze", "--workers", "4"]
env_file: .env
volumes: [*library-ro, /srv/pipu/models:/models]
deploy: { resources: { limits: { cpus: "4" } } }
postgres:
image: pgvector/pgvector:pg17
volumes: [/srv/pipu/postgres:/var/lib/postgresql/data]
redis:
image: redis:7-alpine
command: ["redis-server", "--appendonly", "yes"]
volumes: [/srv/pipu/redis:/data]
meilisearch:
image: getmeili/meilisearch:v1.11
environment: [MEILI_MASTER_KEY, MEILI_ENV=production]
volumes: [/srv/pipu/meili:/meili_data]
Наружу открыт только nginx. Все остальные — во внутренней сети compose.
Конфигурация (.env)
| Переменная | Пример / по умолчанию | Описание |
|---|---|---|
PIPU_VERSION |
1.0.0 |
Версия образов |
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_FILE |
/run/secrets/jwt_ed25519.pem |
Генерируется install.sh |
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.
Бэкапы
pg_dumpежедневно (cron-контейнерbackup), хранить 14 дней + еженедельные 8 недель →/srv/pipu/backups.- Meilisearch, кэши и модели не бэкапятся — восстанавливаются (
reindex, повторный транскод / анализ). - Признаки анализа хранятся в Postgres — после восстановления из бэкапа повторный многочасовой анализ не нужен.
- Сама музыка — на NFS, вне зоны ответственности приложения.
Обновление
cd /opt/pipu && ./update.sh 1.3.0 # pull образов, up -d, миграции при старте api, проверка /readyz
Откат: ./update.sh 1.2.4 (миграции пишутся обратно-совместимыми в пределах минорной версии: сначала добавить,
потом — в следующем релизе — удалить).