LibrePortal/containers/navidrome/docker-compose.yml
librelad 9f6ebfa37a feat(containers): add Navidrome music streaming server
New self-hosted app following the standard container layout (config +
docker-compose template + icon), modelled on the Jellyfin media app:

- navidrome.config — media-category metadata, single webui port (random:4533),
  served on the `music` subdomain via Traefik.
- docker-compose.yml — deluan/navidrome:latest with a ./data volume (DB/config/
  cache) and a read-only ./music library mount; declares its SQLite DB
  (libreportal.backup.db) + data dir for live, zero-downtime backups; gluetun
  markers included so it can optionally be VPN-routed.
- navidrome.svg — brand-blue equalizer icon.

Auto-discovered by the container scan / apps.json generator, so it appears in
the App Center as an installable Media app. Like Jellyfin, the first admin
account is created in Navidrome's own web UI on first run, so no auth tools are
needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
2026-07-06 19:38:02 +01:00

52 lines
2.6 KiB
YAML

networks:
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
external: true
services:
# Navidrome Music Server
navidrome-service: #LIBREPORTAL|SERVICE_TAG_1|navidrome-service
container_name: navidrome-service
image: deluan/navidrome:latest
# GLUETUN_OFF_BEGIN
ports:
- "PORTS_DATA_1" #LIBREPORTAL|PORTS_TAG_1|PORTS_DATA_1
# GLUETUN_OFF_END
volumes:
# Navidrome's own state: SQLite DB, config and cache.
- ./data:/data
# The music library — read-only; Navidrome only ever reads from it.
- ./music:/music:ro
environment:
- TZ:TIMEZONE_DATA #LIBREPORTAL|TIMEZONE_TAG|TIMEZONE_DATA
- ND_MUSICFOLDER=/music
- ND_DATAFOLDER=/data
- ND_SCANSCHEDULE=1h
- ND_LOGLEVEL=info
- ND_SESSIONTIMEOUT=24h
labels:
libreportal.category: "CATEGORY_DATA" #LIBREPORTAL|CATEGORY_TAG|CATEGORY_DATA
libreportal.title: "TITLE_DATA" #LIBREPORTAL|TITLE_TAG|TITLE_DATA
libreportal.backup.db: "sqlite:::data/navidrome.db"
libreportal.backup.files: "navidrome-service:/data:data"
traefik.enable: TRAEFIK_ENABLE_DATA #LIBREPORTAL|TRAEFIK_ENABLE_TAG|TRAEFIK_ENABLE_DATA
# TRAEFIK_PORT_1_BEGIN
traefik.http.routers.navidrome-service.entrypoints: web,websecure
traefik.http.routers.navidrome-service.rule: Host(`DOMAINSUBNAME_DATA_1`) #LIBREPORTAL|DOMAINSUBNAME_TAG_1|DOMAINSUBNAME_DATA_1
traefik.http.routers.navidrome-service.tls: true
traefik.http.routers.navidrome-service.tls.certresolver: production
traefik.http.services.navidrome-service.loadbalancer.server.port: PORT_INTERNAL_DATA_1 #LIBREPORTAL|PORT_INTERNAL_TAG_1|PORT_INTERNAL_DATA_1
traefik.http.routers.navidrome-service.middlewares: MIDDLEWARE_DATA_1 #LIBREPORTAL|MIDDLEWARE_TAG_1|MIDDLEWARE_DATA_1
# TRAEFIK_PORT_1_END
traefik.docker.network: DOCKER_NETWORK_DATA #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
healthcheck:
disable: HEALTHCHECK_DATA #LIBREPORTAL|HEALTHCHECK_TAG|HEALTHCHECK_DATA
restart: 'unless-stopped'
# GLUETUN_OFF_BEGIN
networks:
DOCKER_NETWORK_DATA: #LIBREPORTAL|DOCKER_NETWORK_TAG|DOCKER_NETWORK_DATA
ipv4_address: IP_DATA_1 #LIBREPORTAL|IP_TAG_1|IP_DATA_1
# GLUETUN_OFF_END
# GLUETUN_ON_BEGIN
# network_mode: "container:gluetun-service"
# GLUETUN_ON_END