You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sub-issue of #95. Not named in ADR-0008 — proposed here as an addition to the tier the ADR created, on the grounds that it is the same kind of data in the same place.
Audiobook and podcast server with its own Android and iOS apps, and the property that matters for audiobooks specifically: progress syncs across devices. Jellyfin can serve audiobook files, but it tracks position the way it tracks a film, which is not how anyone listens to a twenty-hour book across a phone, a car and a kitchen speaker.
Why the media tier is the right place
ADR-0008's test is the trust of the data, not the function. An audiobook library is replaceable media, identical in consequence to the film library sitting next to it — losing it is annoying, not catastrophic. It belongs on 40 for exactly the reasons Jellyfin does, reaches the same clients, and needs no new rule beyond the 50→40 that #138 already adds.
It is also genuinely small: no transcoding, no ML, minimal CPU. This adds very little to a box being bought anyway.
A decision on podcast auto-download, which is the one feature that makes this service reach outward on a schedule. Fine on a terminal VLAN with egress, worth being aware of.
Status, 2026-09-17. The host exists and the tier has a shape; the storage
does not.
smaug — the NAS, named by ADR-0038
and running TrueNAS by ADR-0040
— has held 10.0.40.30 since 2026-09-16, with four inbound passes created and
verified in position. The 50→40 rule this issue inherits from #138 is among
them, so no new firewall rule is needed here and none was ever going to be.
stacks/media/ is
authored and CI-validated, with Jellyfin alone in it. It is not deployed — docs/runbooks/build-the-nas.md §6 deploys it, after the two Exos X20 drives
land and the pool erebor and its erebor/media dataset exist.
The storage decision §4 made applies here too: erebor/media is not backed up
and erebor/apps — where a service's database and config go — is.
Depends on #413, not #95, which
closed on 2026-09-04.
stacks/media/compose.yaml already names this service as a future one in its
own comments — "Audiobookshelf (#140) and Navidrome (#141) land here later, in
the shape this file already has" — so the shape to add it to exists: pinned by
digest, non-root, read_only, cap_drop: ALL, a healthcheck that works with
what the image actually ships, and a memory limit set from a measured idle RSS
rather than from a guess.
Corrected 2026-09-19
The 2026-09-17 note is wrong in two places now: the storage exists (erebor, ONLINE since 2026-09-19) and the stack is deployed (stacks/media on smaug, #522, Jellyfin live, #138 closed). stacks/media/compose.yaml holds jellyfin and node-exporter and nothing else, so this is straightforwardly addable in the shape the file already has. Re-sequenced to seq/2: with #484 first, these are the unblocked builds in this milestone. The admin credential question is #528, and it applies here too.
Sub-issue of #95. Not named in ADR-0008 — proposed here as an addition to the tier the ADR created, on the grounds that it is the same kind of data in the same place.
What and why
Audiobookshelf
GPL-3.0Docker/deb/Nodejs— awesome-selfhostedREADME.md:1357.Audiobook and podcast server with its own Android and iOS apps, and the property that matters for audiobooks specifically: progress syncs across devices. Jellyfin can serve audiobook files, but it tracks position the way it tracks a film, which is not how anyone listens to a twenty-hour book across a phone, a car and a kitchen speaker.
Why the media tier is the right place
ADR-0008's test is the trust of the data, not the function. An audiobook library is replaceable media, identical in consequence to the film library sitting next to it — losing it is annoying, not catastrophic. It belongs on 40 for exactly the reasons Jellyfin does, reaches the same clients, and needs no new rule beyond the 50→40 that #138 already adds.
It is also genuinely small: no transcoding, no ML, minimal CPU. This adds very little to a box being bought anyway.
What it needs
secrets/*.sops.yaml.Which VLAN this touches
🟡 40 — CasaBonita (media)
Security review
secrets/*.sops.yamldocs/network.mdwith an OUI-truncated MAC — n/aDepends on
#95 (the NAS). Sensible to deploy alongside #138.
Note
Status, 2026-09-17. The host exists and the tier has a shape; the storage
does not.
smaug— the NAS, named byADR-0038
and running TrueNAS by
ADR-0040
— has held
10.0.40.30since 2026-09-16, with four inbound passes created andverified in position. The 50→40 rule this issue inherits from #138 is among
them, so no new firewall rule is needed here and none was ever going to be.
stacks/media/isauthored and CI-validated, with Jellyfin alone in it. It is not deployed —
docs/runbooks/build-the-nas.md§6 deploys it, after the two Exos X20 drivesland and the pool
ereborand itserebor/mediadataset exist.The storage decision §4 made applies here too:
erebor/mediais not backed upand
erebor/apps— where a service's database and config go — is.Depends on #413, not #95, which
closed on 2026-09-04.
stacks/media/compose.yamlalready names this service as a future one in itsown comments — "Audiobookshelf (#140) and Navidrome (#141) land here later, in
the shape this file already has" — so the shape to add it to exists: pinned by
digest, non-root,
read_only,cap_drop: ALL, a healthcheck that works withwhat the image actually ships, and a memory limit set from a measured idle RSS
rather than from a guess.
Corrected 2026-09-19
The 2026-09-17 note is wrong in two places now: the storage exists (
erebor, ONLINE since 2026-09-19) and the stack is deployed (stacks/mediaonsmaug, #522, Jellyfin live, #138 closed).stacks/media/compose.yamlholdsjellyfinandnode-exporterand nothing else, so this is straightforwardly addable in the shape the file already has. Re-sequenced toseq/2: with #484 first, these are the unblocked builds in this milestone. The admin credential question is #528, and it applies here too.