feat(navidrome): self-hosted music streaming on the bulk pool #964

Merged
k.renner merged 1 commits from feat/navidrome into master 2026-09-25 09:19:19 +00:00
Member

Navidrome as the Spotify replacement: a Subsonic server that phone apps (Symfonium, Substreamer, Tempo, Amperfy, play:Sub, …) stream from, with offline downloads.

What

  • Storage: library PVC navidrome-music-bulk on ceph-filesystem-bulk (RWX, 300Gi, mounted read-only into the pod). SQLite + cache on navidrome-data (ceph-block, RWO, 10Gi): upstream v0.64.2 fixed database is locked errors on remote/slow storage, so the DB stays off CephFS.
  • Auth (zero-touch): navidrome.renner.uno → dedicated navidrome-gate Authentik proxy outpost (same shape as wiki-gate). Navidrome ExtAuth trusts X-Authentik-Username from pod CIDRs; the namespace CNP admits only the outpost and Traefik. Navidrome auto-creates the user on first SSO login, and the first user is admin (docs), so there's no open setup page.
  • Phone apps: /rest and /share route straight to Navidrome through a Traefik middleware that blanks X-Authentik-Username (same as wiki-api), so a client can't inject an identity. Subsonic clients authenticate with their Navidrome password.
  • Namespace, baseline CNP, gate egress CNP, Flux ImageRepository/ImagePolicy (deluan/navidrome, >=0.64.0), Velero navidrome-daily at 09:15, bootstrap wait.
  • Hourly library scan (0 * * * *). Insights telemetry off.

Post-merge steps (per user, not infra)

  1. Open https://navidrome.renner.uno and log in via Authentik. This creates your Navidrome user (admin).
  2. In Navidrome → Personal → change password: this is the password the phone app uses (SSO doesn't reach the Subsonic API).
  3. Phone app: server https://navidrome.renner.uno, your username + that password.

Open points

  • No music in the library yet. Navidrome has no upload feature by design (FAQ). Loading music is a follow-up: a one-time copy into the PVC and/or an ongoing ingest path (FileBrowser, Syncthing, Lidarr/beets).
  • Gate access: no group binding. Any Authentik user passes and gets a Navidrome account. Add a policy binding if it should be restricted.
  • PWA: no skip_path_regex yet. Check after deploy whether the web UI's manifest/service worker loops through the gate (as ESPHome/Z2M did); the phone path (/rest) is unaffected either way.

Verification done

  • kubectl kustomize builds for apps/navidrome, apps/authentik, network-policies, image-automation; blueprint YAML parses with all three navidrome-gate entries.
  • Server-side dry-run of the CNPs, image automation, and Flux Kustomization (the namespace-scoped CNP awaits the namespace).
  • Image tag deluan/navidrome:0.64.2 confirmed on Docker Hub; /ping is registered by the server (middleware.Heartbeat("/ping")).

🤖 Generated with Claude Code

Navidrome as the Spotify replacement: a Subsonic server that phone apps (Symfonium, Substreamer, Tempo, Amperfy, play:Sub, …) stream from, with offline downloads. ## What - **Storage:** library PVC `navidrome-music-bulk` on `ceph-filesystem-bulk` (RWX, 300Gi, mounted read-only into the pod). SQLite + cache on `navidrome-data` (`ceph-block`, RWO, 10Gi): upstream v0.64.2 fixed `database is locked` errors on remote/slow storage, so the DB stays off CephFS. - **Auth (zero-touch):** `navidrome.renner.uno` → dedicated `navidrome-gate` Authentik proxy outpost (same shape as wiki-gate). Navidrome ExtAuth trusts `X-Authentik-Username` from pod CIDRs; the namespace CNP admits only the outpost and Traefik. Navidrome auto-creates the user on first SSO login, and the first user is admin ([docs](https://www.navidrome.org/docs/usage/integration/authentication/)), so there's no open setup page. - **Phone apps:** `/rest` and `/share` route straight to Navidrome through a Traefik middleware that blanks `X-Authentik-Username` (same as wiki-api), so a client can't inject an identity. Subsonic clients authenticate with their Navidrome password. - Namespace, baseline CNP, gate egress CNP, Flux ImageRepository/ImagePolicy (`deluan/navidrome`, `>=0.64.0`), Velero `navidrome-daily` at 09:15, bootstrap wait. - Hourly library scan (`0 * * * *`). Insights telemetry off. ## Post-merge steps (per user, not infra) 1. Open https://navidrome.renner.uno and log in via Authentik. This creates your Navidrome user (admin). 2. In Navidrome → Personal → change password: this is the password the phone app uses (SSO doesn't reach the Subsonic API). 3. Phone app: server `https://navidrome.renner.uno`, your username + that password. ## Open points - **No music in the library yet.** Navidrome has no upload feature by design ([FAQ](https://www.navidrome.org/docs/faq/)). Loading music is a follow-up: a one-time copy into the PVC and/or an ongoing ingest path (FileBrowser, Syncthing, Lidarr/beets). - **Gate access:** no group binding. Any Authentik user passes and gets a Navidrome account. Add a policy binding if it should be restricted. - **PWA:** no `skip_path_regex` yet. Check after deploy whether the web UI's manifest/service worker loops through the gate (as ESPHome/Z2M did); the phone path (`/rest`) is unaffected either way. ## Verification done - `kubectl kustomize` builds for apps/navidrome, apps/authentik, network-policies, image-automation; blueprint YAML parses with all three navidrome-gate entries. - Server-side dry-run of the CNPs, image automation, and Flux Kustomization (the namespace-scoped CNP awaits the namespace). - Image tag `deluan/navidrome:0.64.2` confirmed on Docker Hub; `/ping` is registered by the server (`middleware.Heartbeat("/ping")`). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
claude-bot added 1 commit 2026-09-25 09:12:32 +00:00
feat(navidrome): self-hosted music streaming on the bulk pool
ci/woodpecker/pr/ci-scripts-test Pipeline was successful
ci/woodpecker/pr/ci-manifests-test Pipeline was successful
ci/woodpecker/pr/pr-review Pipeline was successful
222d0263a4
Navidrome (Subsonic API) as the Spotify replacement for phone apps.

- Library PVC on ceph-filesystem-bulk (RWX, 300Gi, mounted read-only);
  SQLite data on ceph-block (RWO).
- Web UI behind a dedicated navidrome-gate Authentik proxy outpost;
  Navidrome trusts X-Authentik-Username (ExtAuth) and auto-creates the
  user on first SSO login (first user = admin).
- /rest and /share routed straight to Navidrome with the identity header
  stripped, so Subsonic clients use their Navidrome password.
- Namespace baseline CNP, gate egress CNP, Flux image automation,
  Velero daily schedule (09:15), bootstrap wait.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
review-bot left a comment
Member

🤖 Automated review — model CLI default (complexity: unknown), commit 222d0263a45c82c7b2611d131a7ac455da48e20f.

Advisory review by the review-bot pipeline. It never approves; a human merges. Push new commits to get a fresh review.


Summary

Adds Navidrome as a self-hosted Subsonic music server, following the repo's established "gate" pattern very closely (mirrors wiki-gate/wordpress-gate: Authentik proxy outpost for the web UI, a Traefik middleware that blanks X-Authentik-Username on the ungated /rest + /share routes, matching CiliumNetworkPolicies, PVCs, Flux Kustomization, image automation, Velero schedule, bootstrap wait). The network-policy and Ingress-splitting design checks out against precedent elsewhere in the repo (verified against wordpress's documented same-host dual-Ingress pattern and ai-ns.yaml's CNP shape). One item needs verification before merge because it underpins the PR's central "zero-touch SSO" claim.

🔴 Blocking

  • kubernetes/apps/navidrome/deployment.yaml:12-13 — ND_EXTAUTH_USERHEADER / ND_EXTAUTH_TRUSTEDSOURCES are the env var names this PR relies on for Navidrome to trust the X-Authentik-Username header from the outpost. I could not reach the network from this sandbox to confirm against Navidrome 0.64.2's actual config reference, but my best recollection of Navidrome's config schema is that this feature is exposed as ReverseProxyUserHeader / ReverseProxyWhitelist (env: ND_REVERSEPROXYUSERHEADER / ND_REVERSEPROXYWHITELIST), not an ExtAuth-prefixed pair — I'm not aware of Navidrome ever renaming this section. If the env var names are wrong, Navidrome silently ignores them (unknown ND_* vars aren't rejected), so there's no crash or error — you just get a normal Navidrome login page instead of the described auto-provisioned-admin-on-first-SSO-login flow, and the whole "zero-touch" premise in the PR body silently doesn't hold. Please confirm the exact keys against the running image before merging, e.g. docker run --rm deluan/navidrome:0.64.2 --help or the config reference for 0.64.x, and fix the ConfigMap keys if they differ.

🟡 Suggestions

  • kubernetes/apps/navidrome/deployment.yaml — no readOnlyRootFilesystem: true on the container's securityContext, unlike wiki's deployment which sets it. If Navidrome doesn't need to write outside /data (cache/artwork live there per the PR description) this is free hardening; if ffmpeg-based transcoding needs scratch space, add an emptyDir for it the way other pods do, rather than leaving the root fs writable by default.
  • kubernetes/infrastructure/post-crds/velero-schedules.yaml — navidrome-daily backs up all PVCs in the namespace, including the 300Gi navidrome-music-bulk library, daily with snapshotMoveData: true and a 30-day TTL. Once the library is actually populated (per the PR's own "Open points"), that's a lot of data movement for content that's re-derivable from source and changes rarely. Worth a second look at whether the bulk library needs daily data-mover backups at all, versus a longer interval or excluding it and relying on the source copy.

🟢 Nits

None beyond the above.

Tests

This is a GitOps/Kubernetes manifests repo; "tests" here means kubectl kustomize builds and dry-run validation, which the PR description says was done and which CI (.woodpecker) should also enforce. No manifest-level issues found that would fail a kustomize build. The one thing that can't be validated by a build — whether Navidrome actually honors the ND_EXTAUTH_* env vars — is exactly the Blocking item above; it will only surface at runtime as "SSO doesn't auto-login," so it's worth a manual check before merge rather than discovering it post-merge.

Recommendation

Request changes — 1 blocking issue (verify the reverse-proxy trust env var names against the actual Navidrome 0.64.2 config before merging).

🤖 **Automated review** — model `CLI default` (complexity: unknown), commit `222d0263a45c82c7b2611d131a7ac455da48e20f`. > Advisory review by the `review-bot` pipeline. It never approves; a human merges. Push new commits to get a fresh review. --- ## Summary Adds Navidrome as a self-hosted Subsonic music server, following the repo's established "gate" pattern very closely (mirrors `wiki-gate`/`wordpress-gate`: Authentik proxy outpost for the web UI, a Traefik middleware that blanks `X-Authentik-Username` on the ungated `/rest` + `/share` routes, matching CiliumNetworkPolicies, PVCs, Flux Kustomization, image automation, Velero schedule, bootstrap wait). The network-policy and Ingress-splitting design checks out against precedent elsewhere in the repo (verified against `wordpress`'s documented same-host dual-Ingress pattern and `ai-ns.yaml`'s CNP shape). One item needs verification before merge because it underpins the PR's central "zero-touch SSO" claim. ## 🔴 Blocking - **`kubernetes/apps/navidrome/deployment.yaml:12-13`** — `ND_EXTAUTH_USERHEADER` / `ND_EXTAUTH_TRUSTEDSOURCES` are the env var names this PR relies on for Navidrome to trust the `X-Authentik-Username` header from the outpost. I could not reach the network from this sandbox to confirm against Navidrome 0.64.2's actual config reference, but my best recollection of Navidrome's config schema is that this feature is exposed as `ReverseProxyUserHeader` / `ReverseProxyWhitelist` (env: `ND_REVERSEPROXYUSERHEADER` / `ND_REVERSEPROXYWHITELIST`), not an `ExtAuth`-prefixed pair — I'm not aware of Navidrome ever renaming this section. If the env var names are wrong, Navidrome silently ignores them (unknown `ND_*` vars aren't rejected), so there's no crash or error — you just get a normal Navidrome login page instead of the described auto-provisioned-admin-on-first-SSO-login flow, and the whole "zero-touch" premise in the PR body silently doesn't hold. Please confirm the exact keys against the running image before merging, e.g. `docker run --rm deluan/navidrome:0.64.2 --help` or the config reference for 0.64.x, and fix the ConfigMap keys if they differ. ## 🟡 Suggestions - **`kubernetes/apps/navidrome/deployment.yaml`** — no `readOnlyRootFilesystem: true` on the container's `securityContext`, unlike `wiki`'s deployment which sets it. If Navidrome doesn't need to write outside `/data` (cache/artwork live there per the PR description) this is free hardening; if ffmpeg-based transcoding needs scratch space, add an `emptyDir` for it the way other pods do, rather than leaving the root fs writable by default. - **`kubernetes/infrastructure/post-crds/velero-schedules.yaml`** — `navidrome-daily` backs up all PVCs in the namespace, including the 300Gi `navidrome-music-bulk` library, daily with `snapshotMoveData: true` and a 30-day TTL. Once the library is actually populated (per the PR's own "Open points"), that's a lot of data movement for content that's re-derivable from source and changes rarely. Worth a second look at whether the bulk library needs daily data-mover backups at all, versus a longer interval or excluding it and relying on the source copy. ## 🟢 Nits None beyond the above. ## Tests This is a GitOps/Kubernetes manifests repo; "tests" here means `kubectl kustomize` builds and dry-run validation, which the PR description says was done and which CI (`.woodpecker`) should also enforce. No manifest-level issues found that would fail a kustomize build. The one thing that can't be validated by a build — whether Navidrome actually honors the `ND_EXTAUTH_*` env vars — is exactly the Blocking item above; it will only surface at runtime as "SSO doesn't auto-login," so it's worth a manual check before merge rather than discovering it post-merge. ## Recommendation Request changes — 1 blocking issue (verify the reverse-proxy trust env var names against the actual Navidrome 0.64.2 config before merging). <!-- pr-review:sha=222d0263a45c82c7b2611d131a7ac455da48e20f -->
k.renner merged commit 8d98acb3a4 into master 2026-09-25 09:19:19 +00:00
Sign in to join this conversation.