Files
pipu-music/docs/install-guide.md
T
mrleo1nidandClaude Opus 5.5 66f5749fc1
ci / api / api (push) Successful in 22s
ci / db / db (push) Successful in 2m4s
release / release (версия и заметки) (push) Successful in 5s
release / android (APK в релиз) (push) Successful in 4m11s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m33s
fix(deploy): take the Gitea address for Android updates from git remote
The server kept the git.example.lan placeholder from .env.example, so the
/android page and in-app updates had no release. install.sh and update.sh now
fill GITEA_URL and GITEA_REPO from the clone's origin (https, ssh and scp
forms, credentials stripped) when they are empty or still the placeholder,
and the API treats the placeholder as not configured.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-21 00:23:28 +03:00

20 KiB
Raw Blame History

Установка сервера и подключение приложений

Пошаговая инструкция: от чистого Linux-сервера до работающего Pipu Music на своём домене с HTTPS, плюс подключение веб- и Android-клиента. Справочник по устройству развёртывания — deployment.md.

В примерах:

  • домен — music.example.com, замените на свой;
  • репозиторий — gitea.hsrv.site/mrleo1nid/pipu-music, клонируется в /opt/pipu-music;
  • диск с музыкой смонтирован в /mnt/music;
  • данные сервиса (БД, кэши, сертификаты) — в /srv/pipu.

Готовые Docker-образы не публикуются: сервер клонирует репозиторий и собирает образы сам (docker compose build). Релизы в Gitea содержат только APK для Android.

Что умеет текущая версия. В v0.1.0 (этап M0) работают развёртывание, HTTPS и проверка связи клиентов с сервером. Вход, библиотека и плеер появятся в следующих версиях (см. roadmap.md). Шаги, которые зависят от версии, помечены.


1. Что нужно заранее

Что Требование
Сервер Linux x86_64 (Debian 12 / Ubuntu 22.04+), 4+ ядра, 8+ ГБ RAM, 30+ ГБ на системном диске (система, образы, кэш сборки, данные)
Доступ root или пользователь с sudo
Домен Поддомен, которым вы управляете, например music.example.com
Сеть Входящие 80/tcp и 443/tcp (+ 443/udp для HTTP/3) из интернета на сервер
Музыка Отдельный диск с библиотекой, подключённый к серверу (шаг 4). NFS-хранилища можно добавить позже из админки
Интернет на сервере Нужен при сборке: скачиваются базовые образы и зависимости Go / npm / Python
Gitea Доступ к репозиторию на чтение (если он приватный — токен или SSH-ключ)

2. DNS

Создайте у регистратора или в DNS-панели запись:

Тип Имя Значение
A music публичный IPv4 сервера
AAAA music публичный IPv6 (если есть; если нет — запись не создавайте)

Если сервер стоит дома за роутером, пробросьте на роутере порты 80 и 443 на внутренний IP сервера.

Проверка — команда должна вернуть IP вашего сервера:

dig +short music.example.com

Сертификат Let's Encrypt выдаётся, только когда домен уже указывает на сервер и порт 80 доступен из интернета. Не запускайте шаг 7, пока эта проверка не проходит.


3. Docker

curl -fsSL https://get.docker.com | sudo sh

Добавьте своего пользователя в группу docker, чтобы запускать сборку без sudo (после этого перелогиньтесь):

sudo usermod -aG docker "$USER"

И git, если его нет:

sudo apt-get install -y git

Проверьте, что есть Docker Compose v2.24 или новее (нужен для compose.tls.yaml):

docker compose version

Откройте порты в файрволе, если он включён (пример для ufw):

sudo ufw allow 80/tcp && sudo ufw allow 443/tcp && sudo ufw allow 443/udp

4. Диск с музыкой

Музыка лежит на отдельном диске, смонтированном в /mnt/music. Если диск уже смонтирован — проверьте его командой из конца шага и переходите к шагу 5.

Найдите диск и его UUID (раздел с музыкой — например, /dev/sdb1):

lsblk -f

Создайте точку монтирования:

sudo mkdir -p /mnt/music

Добавьте в /etc/fstab строку (подставьте свой UUID и файловую систему из вывода lsblk -f):

UUID=1234abcd-0000-0000-0000-000000000000  /mnt/music  ext4  defaults,nofail,noatime  0  2

nofail нужен, чтобы сервер загружался, даже если диск не подключён. Смонтируйте и проверьте:

sudo mount -a && findmnt /mnt/music && ls /mnt/music | head

Сервисы Pipu работают в контейнерах не от root, поэтому музыка должна быть доступна на чтение всем: файлы — 644, каталоги — 755. Если раньше права были закрытыми:

sudo chmod -R a+rX /mnt/music

Для дисков с NTFS / exFAT права задаются опциями монтирования, а не chmod: добавьте в fstab uid=0,gid=0,umask=022 вместо defaults.

Pipu только читает этот диск. Записывать в него будет лишь импорт одобренных треков из очереди на добавление, и только если в админке разрешить это для хранилища (uploads.md).


5. Клонирование репозитория

sudo mkdir -p /opt/pipu-music && sudo chown "$USER" /opt/pipu-music
git clone https://gitea.hsrv.site/mrleo1nid/pipu-music.git /opt/pipu-music && cd /opt/pipu-music/deploy

Если репозиторий приватный: клонируйте по SSH (git@gitea.hsrv.site:mrleo1nid/pipu-music.git) с ключом, добавленным в Gitea, или по HTTPS с токеном (право read:repository) — Git спросит логин и токен вместо пароля. Сохраните доступ (git config credential.helper store или SSH-ключ): update.sh делает git fetch при каждом обновлении.

Все дальнейшие команды выполняются из /opt/pipu-music/deploy.


6. Подготовка сервера

sudo LIBRARY_HOST=/mnt/music ./install.sh

Скрипт:

  • создаёт каталоги данных в /srv/pipu (БД, кэши, загрузки, сертификаты);
  • делает /srv/pipu/library точкой монтирования с shared propagation, чтобы NFS-хранилища, которые потом подключит админ, были видны всем контейнерам, и ставит systemd-юнит, повторяющий это после перезагрузки;
  • проверяет, что /mnt/music существует, и записывает его в .env как LIBRARY_HOST — эту папку получат контейнеры api, nginx и analyzer (внутри они видят её как /library-host);
  • создаёт .env со случайными паролями БД, ключом поиска и межсервисным токеном.

Заполните в /opt/pipu-music/deploy/.env:

COMPOSE_FILE=compose.yaml:compose.tls.yaml
DOMAIN=music.example.com
ACME_EMAIL=you@example.com

Проверьте, что там же стоит путь к музыке (его вписал install.sh):

LIBRARY_HOST=/mnt/music

Если диск смонтирован в другое место — поправьте путь здесь и перезапустите сервисы (./update.sh).

ACME_EMAIL — адрес, на который Let's Encrypt пишет, если с сертификатом что-то не так. Остальные значения менять не нужно; PIPU_VERSION проставляет update.sh.

.env не хранится в git (он в .gitignore), поэтому обновления репозитория его не трогают.


7. Сборка и запуск

./update.sh

Скрипт переключает репозиторий на последний релизный тег (например, v0.1.1), собирает образы, запускает все сервисы и ждёт готовности API (до 2 минут). Первая сборка занимает 5–15 минут, следующие — быстрее за счёт кэша Docker. Конкретная версия: ./update.sh v0.1.1.

Локальная сборка поддерживается начиная с v0.1.1: в теге v0.1.0 compose.yaml ещё ссылается на реестр образов. Пока v0.1.1 не вышел, запускайте ./update.sh main. При первом запуске Caddy сам получит сертификат для DOMAIN, обычно за 10–30 секунд.

Проверка с любого компьютера:

curl -s https://music.example.com/api/v1/server-info

Ожидаемый ответ: {"name":"pipu-music","version":"0.1.0",...}. Проверка всех зависимостей:

curl -s https://music.example.com/readyz

Должно вернуться "status":"ok" и ok для postgres и redis.


8. Веб-клиент

Откройте https://music.example.com в браузере.

  • v0.1.0: карточка «Сервер 0.1.0 на связи» и переключатель языка RU / EN.

  • С версии 0.2 (M1): экран входа. Первый вход — логин admin и пароль, который сервер один раз выводит в лог при первом запуске:

    docker compose logs api | grep -i bootstrap
    

    Сразу после входа приложение попросит сменить логин и пароль администратора (auth-and-roles.md). Чтобы задать пароль заранее, впишите BOOTSTRAP_ADMIN_PASSWORD в .env до первого запуска.

  • С версии 0.3 (M2): Админка → Хранилища → «Добавить хранилище» → тип «Локальная папка» → выберите подпапку на диске /mnt/music (в списке она видна как /library-host/...) → «Проверить» → шаблоны путей → «Сохранить и пересканировать» (library-and-storage.md). Там же можно добавить NFS-хранилище: адрес сервера и путь экспорта.


9. Android-приложение

  1. На телефоне откройте страницу релизов https://gitea.hsrv.site/mrleo1nid/pipu-music/releases и скачайте pipu-music-<версия>.apk.
  2. Откройте файл. Android попросит разрешить установку из этого источника (браузера или файлового менеджера) — разрешите и вернитесь к установке.
  3. Запустите Pipu Music, на экране подключения введите адрес сервера: music.example.com (https:// подставится сам) → «Проверить».
  4. Ожидаемый результат — «Сервер 0.1.0 на связи». Если версия приложения слишком старая для сервера, приложение попросит обновиться.

Дальше приложение обновляется само: с версии M5 оно проверяет новые релизы через ваш сервер и предлагает обновиться (mobile.md). Адрес Gitea и репозиторий (GITEA_URL, GITEA_REPO) install.sh и update.sh берут из git remote клона; GITEA_TOKEN (только на чтение) нужен, если репозиторий закрытый. Если сервер не видит Gitea по внешнему адресу — впишите внутренний в GITEA_URL. Раздать приложение — ссылка https://<ваш-домен>/android.

Приложению нужен настоящий сертификат. С самоподписанным сертификатом и голым IP-адресом подключиться не получится. Поэтому нужен домен с Let's Encrypt, как в этой инструкции.


10. Вариант: свой reverse proxy вместо Caddy

Если на сервере уже есть Traefik, Nginx Proxy Manager или свой nginx с сертификатами:

  1. В .env закомментируйте COMPOSE_FILE и задайте порт, на котором Pipu будет слушать только локально:

    #COMPOSE_FILE=compose.yaml:compose.tls.yaml
    HTTP_PORT=127.0.0.1:8081
    
  2. Направьте прокси для music.example.com на http://127.0.0.1:8081 с такими настройками:

    • передавать заголовки Host, X-Forwarded-For, X-Forwarded-Proto;
    • лимит тела запроса не меньше 16 МБ (загрузка треков идёт чанками по 8 МБ);
    • без буферизации ответов (стриминг аудио), длинные таймауты чтения (≥ 1 ч).

    Пример для nginx:

    server {
        listen 443 ssl http2;
        server_name music.example.com;
        # ssl_certificate / ssl_certificate_key — как у остальных ваших сайтов
    
        client_max_body_size 16m;
    
        location / {
            proxy_pass http://127.0.0.1:8081;
            proxy_set_header Host $host;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header X-Forwarded-Proto $scheme;
            proxy_buffering off;
            proxy_read_timeout 1h;
        }
    }
    
  3. Запуск и проверки — как в шагах 7–9.

Если прокси работает на другой машине, укажите в HTTP_PORT внутренний адрес сервера (192.168.1.10:8081) и закройте этот порт от интернета файрволом.


11. Обновление, бэкапы, удаление

Обновление до последнего релиза:

cd /opt/pipu-music/deploy && ./update.sh

Конкретная версия или откат: ./update.sh v0.2.0. Скрипт делает git fetch, переключается на тег, пересобирает образы и перезапускает сервисы; старые образы удаляются. Миграции БД применяются автоматически при старте API.

Бэкапы базы делаются сами: каждую ночь в /srv/pipu/backups, раз в неделю копия проверяется восстановлением, перед каждым update.sh — внеочередная копия. Всё остальное восстанавливается само — см. deployment.md. Копия сейчас и восстановление:

cd /opt/pipu-music/deploy && docker compose run --rm backup once
cd /opt/pipu-music/deploy && ./restore.sh

Без аргумента restore.sh показывает список копий; с именем файла (./restore.sh daily/pipu-20261020-033000.dump) восстанавливает базу, сохранив прежнюю рядом.

Остановить сервис, сохранив данные:

cd /opt/pipu-music/deploy && docker compose down

12. Если что-то не работает

Симптом Что проверить
Сертификат не выдаётся, браузер ругается на HTTPS dig +short music.example.com указывает на сервер; порт 80 открыт снаружи; docker compose logs caddy
502 Bad Gateway API ещё запускается или упал: docker compose ps, docker compose logs api
/readyz отвечает degraded Какая зависимость не ok — её логи: docker compose logs postgres / redis
update.sh: ошибка git fetch Нет доступа к репозиторию: проверьте SSH-ключ или сохранённый токен (git fetch вручную)
Сборка падает на скачивании зависимостей Нет интернета или DNS на сервере; повторите ./update.sh — уже собранные слои берутся из кэша
Сборка падает: «no space left on device» Очистите кэш сборки: docker builder prune
permission denied … docker.sock Пользователь не в группе docker (шаг 3) или вы не перелогинились
Сервисы не стартуют: … is not a shared or slave mount sudo mount --make-rshared / (и добавьте в автозагрузку); на systemd-системах корень и так shared
update.sh: «LIBRARY_HOST … пуст» Диск с музыкой не смонтирован: findmnt /mnt/music, sudo mount -a; если папка и должна быть пустой — PIPU_ALLOW_EMPTY_LIBRARY=1 ./update.sh
Сервисы не стартуют: bind source path does not exist: /mnt/music Диск не смонтирован: findmnt /mnt/music, sudo mount -a; путь в LIBRARY_HOST в .env
Хранилище «Локальная папка» пустое или ошибка доступа Диск смонтирован (ls /mnt/music); права на чтение для всех — sudo chmod -R a+rX /mnt/music (шаг 4)
storage-agent не стартует, ошибка про propagation / shared mount Ещё раз sudo ./install.sh; на хосте findmnt -o TARGET,PROPAGATION /srv/pipu/library должно показать shared
Android: «Сервер не отвечает» Тот же адрес открывается в браузере телефона; в адресе нет опечатки; телефон в сети с доступом к серверу
Android: «Эта версия приложения слишком старая» Установите APK из последнего релиза

Логи всех сервисов сразу:

cd /opt/pipu-music/deploy && docker compose logs -f --tail=100