add navidrome and music share

This commit is contained in:
2026-08-29 19:15:20 -04:00
parent 747a0208e7
commit 32b1f095fe
5 changed files with 62 additions and 2 deletions
+2
View File
@@ -16,6 +16,7 @@ docker/ Docker app configs (compose files, nginx confs)
nextcloud/ Nextcloud + PostgreSQL nextcloud/ Nextcloud + PostgreSQL
gitea/ Gitea + CI runner gitea/ Gitea + CI runner
jellyfin/ Media server jellyfin/ Media server
navidrome/ Music server (Subsonic API), reads the [music] SMB share
garage/ S3-compatible storage garage/ S3-compatible storage
minecraft/ MCSManager minecraft/ MCSManager
immich/ Immich photo server + PostgreSQL immich/ Immich photo server + PostgreSQL
@@ -104,5 +105,6 @@ See [RUNBOOK.md](RUNBOOK.md) for full disaster recovery steps.
| Immich DB (PostgreSQL) | `pg_dumpall` + USB | | Immich DB (PostgreSQL) | `pg_dumpall` + USB |
| Garage S3 data | 2-node replication + USB | | Garage S3 data | 2-node replication + USB |
| Gitea repos + DB | SQLite `.backup` + USB | | Gitea repos + DB | SQLite `.backup` + USB |
| Navidrome DB (ratings, playlists) | SQLite `.backup` + USB |
| Secrets (.env files) | USB backup + Bitwarden | | Secrets (.env files) | USB backup + Bitwarden |
| SSL certificates | Re-issued from Let's Encrypt | | SSL certificates | Re-issued from Let's Encrypt |
+11 -2
View File
@@ -128,6 +128,12 @@ for u in yireh isaac; do
chmod 2770 "/opt/argento/smb/$u" chmod 2770 "/opt/argento/smb/$u"
done done
# Shared music dir. Lives inside the media dataset (so it rides the media
# snapshot policy) but is exported as its own writable [music] share.
# setgid so files dropped in over SMB inherit sambagroup and stay readable
# by the Navidrome container.
install -d -o timothykim -g sambagroup -m 2775 /opt/argento/smb/media/Music
# SELinux contexts for samba — fresh ZFS datasets get unlabeled_t and samba # SELinux contexts for samba — fresh ZFS datasets get unlabeled_t and samba
# refuses to serve them. Persistent rules (semanage) survive full relabels; # refuses to serve them. Persistent rules (semanage) survive full relabels;
# restorecon applies them now. # restorecon applies them now.
@@ -232,7 +238,8 @@ docker compose up -d
# Issue certs (add any new domains that have been added since this was written) # Issue certs (add any new domains that have been added since this was written)
/opt/argento/scripts/issue-cert.sh \ /opt/argento/scripts/issue-cert.sh \
nextcloud.timothykim.net git.timothykim.net jellyfin.timothykim.net \ nextcloud.timothykim.net git.timothykim.net jellyfin.timothykim.net \
argento.timothykim.net garage.timothykim.net photos.thekims.family argento.timothykim.net garage.timothykim.net photos.thekims.family \
music.thekims.family
# Restore SSL confs now that certs exist # Restore SSL confs now that certs exist
mv conf.d/.hold/*.conf conf.d/ mv conf.d/.hold/*.conf conf.d/
@@ -258,7 +265,7 @@ Deploy each app (nginx is already running and will return 502 until they start):
```bash ```bash
# Add any new apps that have been added since this was written # Add any new apps that have been added since this was written
for app in nextcloud gitea jellyfin garage minecraft immich beszel-agent; do for app in nextcloud gitea jellyfin navidrome garage minecraft immich beszel-agent; do
cd /opt/argento/docker/$app cd /opt/argento/docker/$app
docker compose pull docker compose pull
docker compose build docker compose build
@@ -291,6 +298,7 @@ CNAME records pointing to the DDNS hostname. These don't need updating when the
| `garage.timothykim.net` | CNAME | `argento.ddns.net` | | `garage.timothykim.net` | CNAME | `argento.ddns.net` |
| `minecraft.thekims.family` | CNAME | `argento.ddns.net` | | `minecraft.thekims.family` | CNAME | `argento.ddns.net` |
| `photos.thekims.family` | CNAME | `argento.ddns.net` | | `photos.thekims.family` | CNAME | `argento.ddns.net` |
| `music.thekims.family` | CNAME | `argento.ddns.net` |
## 14. Verify ## 14. Verify
@@ -301,6 +309,7 @@ curl -I https://jellyfin.timothykim.net
curl -I https://argento.timothykim.net curl -I https://argento.timothykim.net
curl -I https://garage.timothykim.net curl -I https://garage.timothykim.net
curl -I https://photos.thekims.family curl -I https://photos.thekims.family
curl -I https://music.thekims.family
curl -I http://minecraft.thekims.family curl -I http://minecraft.thekims.family
# Verify SMART, ZFS, and disk space are healthy # Verify SMART, ZFS, and disk space are healthy
+1
View File
@@ -0,0 +1 @@
data/
@@ -0,0 +1,43 @@
server {
listen 80;
listen [::]:80;
server_name music.thekims.family;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
server {
listen 443 ssl;
listen [::]:443 ssl;
http2 on;
server_name music.thekims.family;
ssl_certificate /etc/letsencrypt/live/music.thekims.family/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/music.thekims.family/privkey.pem;
include /etc/nginx/conf.d/security-headers.inc;
# Use a variable so nginx starts even if the upstream is down
set $upstream_navidrome http://navidrome:4533;
location / {
proxy_pass $upstream_navidrome;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# Navidrome streams scan progress and now-playing state over
# Server-Sent Events on /api/events. Buffering holds those messages
# until the response ends (it never does), and HTTP/1.0 to the upstream
# can't carry the chunked response the stream needs.
proxy_http_version 1.1;
proxy_buffering off;
}
}
+5
View File
@@ -40,6 +40,11 @@ for db in jellyfin library; do
|| FAILURES+=("jellyfin ${db} sqlite backup") || FAILURES+=("jellyfin ${db} sqlite backup")
done done
# Dump Navidrome SQLite for consistency
sqlite3 /opt/argento/docker/navidrome/data/navidrome.db \
".backup /opt/argento/docker/navidrome/data/navidrome.db.bak" \
|| FAILURES+=("navidrome sqlite backup")
# Single rsync covers everything: configs, app data, media, DB dumps, # Single rsync covers everything: configs, app data, media, DB dumps,
# and the samba passdb (mirrored into /opt/argento/system/samba-private/ # and the samba passdb (mirrored into /opt/argento/system/samba-private/
# by sync-system.sh, gitignored) # by sync-system.sh, gitignored)