Files
homelab-configs/jellyfin/jellyfin-services.md
T

2.9 KiB

Jellyfin Server — Docker Services

Host

  • VM / alias: jellyfin
  • IP: 192.168.88.10
  • SSH: jgitta@192.168.88.10 (alias: jellyfin)
  • Portainer endpoint ID: 4

Stacks (Portainer)

Stack ID Gitea Path
arr-stack 35 jellyfin/arr-stack/docker-compose.yml
portainer-agent 36 jellyfin/portainer-agent/
node-exporter 44 jellyfin/node-exporter/

arr-stack Services

Container Image Port Config Path
radarr lscr.io/linuxserver/radarr:latest 7878 /srv/docker/radarr/config
sonarr lscr.io/linuxserver/sonarr:latest 8989 /srv/docker/sonarr/config
prowlarr lscr.io/linuxserver/prowlarr:latest 9696 /srv/docker/prowlarr/config
flaresolverr ghcr.io/flaresolverr/flaresolverr:latest 8191

Media volume: /mnt/media → mounted as /data in radarr/sonarr.


Auto-Updates — Cron + Watchtower run-once

Watchtower is NOT run as a persistent container. Instead, cron jobs on the jellyfin host invoke Watchtower in --run-once mode, one container at a time, at staggered 3-minute intervals. This serializes all lscr.io registry checks and eliminates the CDN burst rate limit errors that occurred with concurrent requests.

Schedule (jgitta crontab on jellyfin)

Time Container Command
4:00 AM radarr watchtower-update.sh radarr
4:03 AM sonarr watchtower-update.sh sonarr
4:06 AM prowlarr watchtower-update.sh prowlarr
4:09 AM flaresolverr + others watchtower-update.sh (no scope)

Update script

Location: /usr/local/bin/watchtower-update.sh on jellyfin host.

To view: ssh jellyfin cat /usr/local/bin/watchtower-update.sh To edit cron: ssh jellyfin crontab -e

Each run spins up a temporary containrrr/watchtower container with --run-once, checks for updates, sends an email notification if anything changed, and exits. The container is automatically removed after each run (--rm).

Scope labels

radarr, sonarr, and prowlarr each carry a com.centurylinklabs.watchtower.scope=<name> label in the compose file. This tells Watchtower to only check the matching container when that scope is set. flaresolverr has no scope label and is handled by the unscoped (4:09 AM) run.


Registry Authentication

Credentials are stored in /home/jgitta/.docker/config.json on the jellyfin host. The update script mounts this file into each Watchtower container.

Both lscr.io and ghcr.io are authenticated (lscr.io proxies to ghcr.io for the actual registry API, so both need credentials).

Token: no-expiry read:packages GitHub PAT — see credentials.md.

To re-authenticate (e.g. after rotating token):

ssh jellyfin
echo <new_token> | docker login lscr.io -u jgitta --password-stdin
echo <new_token> | docker login ghcr.io -u jgitta --password-stdin

No script or compose changes needed — the config.json is read at runtime.