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.
In Navidrome → Personal → change password: this is the password the phone app uses (SSO doesn't reach the Subsonic API).
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")).
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)
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>
🤖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 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Navidrome as the Spotify replacement: a Subsonic server that phone apps (Symfonium, Substreamer, Tempo, Amperfy, play:Sub, …) stream from, with offline downloads.
What
navidrome-music-bulkonceph-filesystem-bulk(RWX, 300Gi, mounted read-only into the pod). SQLite + cache onnavidrome-data(ceph-block, RWO, 10Gi): upstream v0.64.2 fixeddatabase is lockederrors on remote/slow storage, so the DB stays off CephFS.navidrome.renner.uno→ dedicatednavidrome-gateAuthentik proxy outpost (same shape as wiki-gate). Navidrome ExtAuth trustsX-Authentik-Usernamefrom 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./restand/shareroute straight to Navidrome through a Traefik middleware that blanksX-Authentik-Username(same as wiki-api), so a client can't inject an identity. Subsonic clients authenticate with their Navidrome password.deluan/navidrome,>=0.64.0), Veleronavidrome-dailyat 09:15, bootstrap wait.0 * * * *). Insights telemetry off.Post-merge steps (per user, not infra)
https://navidrome.renner.uno, your username + that password.Open points
skip_path_regexyet. 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 kustomizebuilds for apps/navidrome, apps/authentik, network-policies, image-automation; blueprint YAML parses with all three navidrome-gate entries.deluan/navidrome:0.64.2confirmed on Docker Hub;/pingis registered by the server (middleware.Heartbeat("/ping")).🤖 Generated with Claude Code
🤖 Automated review — model
CLI default(complexity: unknown), commit222d0263a45c82c7b2611d131a7ac455da48e20f.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 blanksX-Authentik-Usernameon the ungated/rest+/shareroutes, 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 againstwordpress's documented same-host dual-Ingress pattern andai-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_TRUSTEDSOURCESare the env var names this PR relies on for Navidrome to trust theX-Authentik-Usernameheader 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 asReverseProxyUserHeader/ReverseProxyWhitelist(env:ND_REVERSEPROXYUSERHEADER/ND_REVERSEPROXYWHITELIST), not anExtAuth-prefixed pair — I'm not aware of Navidrome ever renaming this section. If the env var names are wrong, Navidrome silently ignores them (unknownND_*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 --helpor the config reference for 0.64.x, and fix the ConfigMap keys if they differ.🟡 Suggestions
kubernetes/apps/navidrome/deployment.yaml— noreadOnlyRootFilesystem: trueon the container'ssecurityContext, unlikewiki'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 anemptyDirfor it the way other pods do, rather than leaving the root fs writable by default.kubernetes/infrastructure/post-crds/velero-schedules.yaml—navidrome-dailybacks up all PVCs in the namespace, including the 300Ginavidrome-music-bulklibrary, daily withsnapshotMoveData: trueand 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 kustomizebuilds 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 theND_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).