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>
This commit is contained in:
librelad 2026-07-06 19:38:02 +01:00
parent c5f75425ac
commit 9f6ebfa37a
3 changed files with 128 additions and 0 deletions

View File

@ -0,0 +1,51 @@
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

View File

@ -0,0 +1,61 @@
#
# =============================================================================
# GENERAL CONFIGURATION
# =============================================================================
# APP_NAME = name of application for use in scripts
# COMPOSE_FILE = default for no app_name in docker-compose file name, app if there is
# BACKUP = if true, include this application in backup operations
# HEALTHCHECK = if true, default docker health checks for that container will be enabled
# AUTHELIA = if true, use Authelia authentication, if false turned off.
# HEADSCALE = options : false, local, remote (see general config). e.g false or local,remote
#
CFG_NAVIDROME_APP_NAME=navidrome
CFG_NAVIDROME_BACKUP=true
CFG_NAVIDROME_BACKUP_STRATEGY=auto
CFG_NAVIDROME_COMPOSE_FILE=default
CFG_NAVIDROME_HEALTHCHECK=true
CFG_NAVIDROME_AUTHELIA=false
CFG_NAVIDROME_HEADSCALE=false
#
# =============================================================================
# METADATA
# =============================================================================
# CATEGORY = application category for grouping
# TITLE = display name for the application
# DESCRIPTION = short description of the application
# LONG_DESCRIPTION = detailed description of the application
# URL = source repository or documentation URL
# ACTIONS = available actions for this application
#
CFG_NAVIDROME_CATEGORY="media"
CFG_NAVIDROME_TITLE="Navidrome"
CFG_NAVIDROME_DESCRIPTION="Music Server"
CFG_NAVIDROME_LONG_DESCRIPTION="Navidrome is a self-hosted, open-source music streaming server with a Subsonic-compatible API — stream your personal music collection to any device from a fast, modern web player."
CFG_NAVIDROME_URL="https://github.com/navidrome/navidrome"
CFG_NAVIDROME_ACTIONS="configure|install|restart|shutdown|uninstall"
#
# =============================================================================
# NETWORK CONFIGURATION
# =============================================================================
# DOMAIN = number of domain from the general config, useful when using multiple domains
# WHITELIST = if true only allow whitelisted ips (see general config), if false allow all
#
CFG_NAVIDROME_DOMAIN=1
CFG_NAVIDROME_WHITELIST=false
CFG_NAVIDROME_NETWORK=default
#
# =============================================================================
# PORT CONFIGURATION
# =============================================================================
# PORT_ = port configuration: app|name|external:internal|access|protocol|login|traefik|webui|description|paths|subdomain
# - app: application name
# - name: service identifier (webui, dns, ssh, etc.)
# - external:internal: port mapping (external can be 'random' for auto-allocation)
# - access: 'public' (internet accessible), 'private' (local network only), 'disabled' (not running)
# - protocol: 'tcp' or 'udp'
# - login: if true, this port requires basic-auth via Traefik (only meaningful when traefik=true)
# - traefik: if true, Traefik handles this port (reverse proxy)
# - webui: if true, this port serves the main web interface
# - description: human-readable description of the service
#
CFG_NAVIDROME_PORT_1="navidrome-service|webui|random:4533|public|tcp|false|true|true|Music Server||music"

View File

@ -0,0 +1,16 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<defs>
<linearGradient id="navidrome_svg__a" x1="64" y1="48" x2="448" y2="464" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#57a0e8"/>
<stop offset="1" style="stop-color:#2960a8"/>
</linearGradient>
</defs>
<rect width="512" height="512" rx="112" fill="url(#navidrome_svg__a)"/>
<g fill="#fff">
<rect x="96" y="191" width="44" height="130" rx="22"/>
<rect x="165" y="141" width="44" height="230" rx="22"/>
<rect x="234" y="106" width="44" height="300" rx="22"/>
<rect x="303" y="156" width="44" height="200" rx="22"/>
<rect x="372" y="196" width="44" height="120" rx="22"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 722 B