Files
pipu-music/docs/deployment.md
T
mrleo1nidandClaude Opus 5.5 1633b28c1a
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(deploy): add install guide for a domain with HTTPS
- 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>
2026-10-20 00:03:26 +03:00

7.9 KiB
Raw Blame History

Развёртывание

Пошаговая инструкция «с нуля до работающего сервера на домене» — 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 (миграции пишутся обратно-совместимыми в пределах минорной версии: сначала добавить, потом — в следующем релизе — удалить).