docs: add jellyfin-services.md with arr-stack and Watchtower lscr.io auth fix
This commit is contained in:
@@ -0,0 +1,75 @@
|
|||||||
|
# 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
|
||||||
|
- **Compose files**: managed via Portainer (stack IDs below); source of truth is Gitea `jgitta/homelab-configs`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Stacks
|
||||||
|
|
||||||
|
| Stack | Portainer 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 | — |
|
||||||
|
| watchtower | containrrr/watchtower | — | see below |
|
||||||
|
|
||||||
|
Media volume: `/mnt/media` on jellyfin host → mounted as `/data` in radarr/sonarr.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Watchtower
|
||||||
|
|
||||||
|
- Runs inside arr-stack on jellyfin (Portainer stack 35)
|
||||||
|
- Schedule: `0 0 4 * * *` — runs at 4:00 AM daily
|
||||||
|
- Notifications: email via Fastmail SMTP to jgitta@jgitta.com
|
||||||
|
- Cleanup: enabled (removes old images after update)
|
||||||
|
- Rolling restarts: enabled with 30s timeout, 60s wait before stopping
|
||||||
|
|
||||||
|
### lscr.io Authentication (fix applied 2026-05-11)
|
||||||
|
|
||||||
|
**Problem**: Watchtower was hitting lscr.io's rate limiter on unauthenticated pulls. radarr,
|
||||||
|
sonarr, and prowlarr all use `lscr.io/linuxserver/` images; when Watchtower checks them
|
||||||
|
concurrently at 4 AM the burst briefly exceeded the anonymous quota. Error appeared in
|
||||||
|
email notifications as:
|
||||||
|
```
|
||||||
|
Unable to update container "/radarr": Error response from daemon: toomanyrequests:
|
||||||
|
retry-after: 835.12µs, allowed: 44000/minute. Proceeding to next.
|
||||||
|
```
|
||||||
|
Observed on: 2026-05-08 and 2026-05-11.
|
||||||
|
|
||||||
|
**Fix**:
|
||||||
|
1. Logged in to lscr.io on the jellyfin host using the GitHub PAT (credentials.md):
|
||||||
|
```
|
||||||
|
echo <github_pat> | docker login lscr.io -u jgitta --password-stdin
|
||||||
|
```
|
||||||
|
Creates `/home/jgitta/.docker/config.json` with lscr.io auth token.
|
||||||
|
|
||||||
|
2. Mounted that config into the Watchtower container (in docker-compose.yml):
|
||||||
|
```yaml
|
||||||
|
volumes:
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /home/jgitta/.docker/config.json:/config.json:ro
|
||||||
|
```
|
||||||
|
Watchtower reads `/config.json` inside the container for registry credentials.
|
||||||
|
|
||||||
|
3. Updated Gitea (`jellyfin/arr-stack/docker-compose.yml`) and redeployed via Portainer.
|
||||||
|
|
||||||
|
**If GitHub PAT expires**: Re-run the `docker login lscr.io` command on jellyfin with the
|
||||||
|
new token. No compose changes needed — the mounted file updates automatically.
|
||||||
|
The PAT expiry date is tracked in credentials.md / github.com/settings/tokens.
|
||||||
Reference in New Issue
Block a user