docs: rename frank-default-large/small/sightsound to frank-large/small/npu across vault
Mechanical identity rename across the knowledge base, AGENTS.md, README, the
hermes config example, and homepage services.json. No behavior change; served
aliases on the LLM endpoints change with the deploy of commit 69f87c8.
This commit is contained in:
@@ -1,8 +1,24 @@
|
||||
---
|
||||
type: reference
|
||||
title: *arr Stack
|
||||
description: The *arr automation stack (Prowlarr, Sonarr, Radarr, Lidarr, Readarr, qBittorrent) on FrankBook-Pro — topology, wiring, auth posture, and gotchas.
|
||||
tags: [arr-stack, prowlarr, sonarr, radarr, lidarr, readarr, qbittorrent, frankbook-pro]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# *arr Stack
|
||||
|
||||
The *arr suite is a collection of automated media management tools for Usenet and BitTorrent. For Dankserver — which runs Copyparty, Calibre-Web, RomM, and Jellyfin — the *arr stack provides automatic downloading and library management that Copyparty alone does not cover: quality profile enforcement, series/movie discovery, metadata enrichment, and automated file organization.
|
||||
The *arr suite is a collection of automated media management tools for Usenet
|
||||
and BitTorrent. The stack runs on **FrankBook-Pro** — the Mac mini that fronts
|
||||
this household's downloads — as quadlet units inside its podman machine, not on
|
||||
Dankserver. It provides automatic downloading and library management that
|
||||
Copyparty alone does not cover: quality profile enforcement, series/movie
|
||||
discovery, metadata enrichment, and automated file organization.
|
||||
|
||||
The core chain is: **Prowlarr** (indexer API aggregator) → **Sonarr/Radarr/Lidarr/Readarr** (media-specific managers) → **qBittorrent** (download client) → **Jellyfin** (media server scan → auto-refresh).
|
||||
The core chain is: **Prowlarr** (indexer API aggregator) →
|
||||
**Sonarr/Radarr/Lidarr/Readarr** (media-specific managers) → **qBittorrent**
|
||||
(download client, sharing the [[Gluetun]] WireGuard tunnel netns) →
|
||||
**Jellyfin** (media server scan → auto-refresh).
|
||||
|
||||
## Service Overview
|
||||
|
||||
@@ -12,334 +28,59 @@ The core chain is: **Prowlarr** (indexer API aggregator) → **Sonarr/Radarr/Lid
|
||||
| Radarr | Movie management | `lscr.io/linuxserver/radarr:latest` | 7878 | 512 MB |
|
||||
| Sonarr | TV show management | `lscr.io/linuxserver/sonarr:latest` | 8989 | 512 MB |
|
||||
| Lidarr | Music management | `lscr.io/linuxserver/lidarr:latest` | 8686 | 256 MB |
|
||||
| Readarr | Ebook/audiobook management | `lscr.io/linuxserver/readarr:latest` | 8787 | 256 MB |
|
||||
| qBittorrent | Torrent download client | `lscr.io/linuxserver/qbittorrent:latest` | 8080 | 512 MB |
|
||||
| Jackett | Indexer proxy (optional) | `lscr.io/linuxserver/jackett:latest` | 9117 | 256 MB |
|
||||
| Whisparr | NSFW movie management (optional) | `lscr.io/linuxserver/whisparr:latest` | 6969 | 256 MB |
|
||||
| Readarr | Ebook/audiobook management | `lscr.io/linuxserver/readarr:amd64-1.0.980` (pinned — LSIO ships no untagged `latest` for readarr) | 8787 | 256 MB |
|
||||
| qBittorrent | Torrent download client | `lscr.io/linuxserver/qbittorrent:4.6.7` (pinned; see [[qBittorrent]]) | 8080 (published by the gluetun unit) | 512 MB |
|
||||
|
||||
**Minimum total RAM:** ~3 GB for full stack (headroom recommended).
|
||||
Jackett and Whisparr were evaluated as optional extras but never deployed
|
||||
(no unit, no vhost, no live container).
|
||||
|
||||
## Architecture
|
||||
## Deployment shape (current)
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
I[Indexers<br/>Torrents, Usenet] --> P[Prowlarr<br/>Indexer Manager]
|
||||
P --> S[Sonarr<br/>TV]
|
||||
P --> R[Radarr<br/>Movies]
|
||||
P --> L[Lidarr<br/>Music]
|
||||
P --> Rd[Readarr<br/>Books]
|
||||
S --> Q[qBittorrent]
|
||||
R --> Q
|
||||
L --> Q
|
||||
Rd --> Q
|
||||
Q --> M1[/tv/]
|
||||
Q --> M2[/movies/]
|
||||
Q --> M3[/music/]
|
||||
Q --> M4[/books/]
|
||||
M1 --> J[Jellyfin]
|
||||
M2 --> J
|
||||
M3 --> J
|
||||
M4 --> CW[Calibre-Web]
|
||||
```
|
||||
Each service is a quadlet `.container` unit in this repo under
|
||||
`frankbook-pro/<svc>/quadlet/`, installed inside the podman machine at
|
||||
`/home/core/.config/containers/systemd/<svc>.service` by the frankbook-pro
|
||||
handler in `scripts/deploy-remote.sh`. Every unit runs with
|
||||
`PUID=0 PGID=0 TZ=America/Los_Angeles UMASK_SET=022`, mounts its config root at
|
||||
`/Volumes/COMPLETE/<svc>-data:/config`, publishes its API port on the host, and
|
||||
runs `Restart=always` with `TimeoutStartSec=900`.
|
||||
|
||||
## Docker Compose
|
||||
qBittorrent is special: it shares the [[Gluetun]] container's network namespace
|
||||
(`Network=gluetun.container`) so torrent egress never touches the residential
|
||||
IP. A netns-sharer publishes no ports of its own — qB's WebUI (8080) and
|
||||
BitTorrent port (6881 TCP+UDP) are published on the gluetun unit instead.
|
||||
|
||||
```yaml
|
||||
networks:
|
||||
appnet:
|
||||
driver: bridge
|
||||
## Historical design-era compose (retired)
|
||||
|
||||
services:
|
||||
prowlarr:
|
||||
image: lscr.io/linuxserver/prowlarr:latest
|
||||
container_name: prowlarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/prowlarr/config:/config
|
||||
- /mnt/media/downloads:/downloads:ro
|
||||
ports:
|
||||
- "9696:9696"
|
||||
networks: [appnet]
|
||||
The original design deployed the stack on Dankserver via
|
||||
`dankserver/compose.yaml` with `/opt/<svc>/config` data roots and
|
||||
`TZ=America/New_York`. That layout is retired; `dankserver/compose.yaml` is
|
||||
kept as reference only. Reality (unit files above) wins: data roots are the
|
||||
Mac's `/Volumes/COMPLETE` (completed media) and `/Volumes/INCOMPLETE`
|
||||
(in-flight downloads) volumes, mounted into qB at identical paths, and every
|
||||
unit runs `TZ=America/Los_Angeles`.
|
||||
|
||||
radarr:
|
||||
image: lscr.io/linuxserver/radarr:latest
|
||||
container_name: radarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/radarr/config:/config
|
||||
- /mnt/media/movies:/movies
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "7878:7878"
|
||||
networks: [appnet]
|
||||
## Access / auth posture
|
||||
|
||||
sonarr:
|
||||
image: lscr.io/linuxserver/sonarr:latest
|
||||
container_name: sonarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/sonarr/config:/config
|
||||
- /mnt/media/tv:/tv
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "8989:8989"
|
||||
networks: [appnet]
|
||||
There is **no Caddy vhost for any arr app** — the *arr stack is exempt by
|
||||
construction from the Anubis guard chain (its own auth). The stack is reached
|
||||
directly by IP:port on the LAN (`http://<frankbook-pro>:8989` etc.).
|
||||
|
||||
lidarr:
|
||||
image: lscr.io/linuxserver/lidarr:latest
|
||||
container_name: lidarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/lidarr/config:/config
|
||||
- /mnt/media/music:/music
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "8686:8686"
|
||||
networks: [appnet]
|
||||
Auth-config history (verified live 2026-08-29): all five arrs shipped with
|
||||
`AuthenticationMethod=None` **plus** `AuthenticationRequired=Enabled`. On the
|
||||
v1 (.NET) apps that combo is self-contradictory — UI Save is permanently
|
||||
disabled and any settings save throws `DryIoc.ScopedItemException` inside
|
||||
`AuthorizationMiddleware` (500 sprawl on every page after restart). The valid
|
||||
representation of "no auth" in v1 is **absence of the `<AuthenticationRequired>`
|
||||
key**, not the literal string `Disabled` — readarr's config (key absent) booted
|
||||
clean while its three siblings (key=`Disabled`) 500-sprawled, which is how it
|
||||
was caught. Fix applied live: key deleted on sonarr/radarr/lidarr/prowlarr,
|
||||
containers restarted, all five verified serving. Posture = zero-auth arrs on
|
||||
LAN and WAN; the Anubis wall guards homepage/search/hermes/prometheus/romm/files
|
||||
but **not** the arrs — first-account-wins is the current race condition if that
|
||||
ever flips to `External` auth (needs an IdP first; auth method choice remains an
|
||||
operator decision).
|
||||
|
||||
readarr:
|
||||
image: lscr.io/linuxserver/readarr:latest
|
||||
container_name: readarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/readarr/config:/config
|
||||
- /mnt/media/books:/books
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "8787:8787"
|
||||
networks: [appnet]
|
||||
|
||||
qbittorrent:
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
container_name: qbittorrent
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/qbittorrent/config:/config
|
||||
- /mnt/media/downloads:/downloads
|
||||
- /mnt/media/downloads/incomplete:/downloads/incomplete
|
||||
ports:
|
||||
- "8080:8080"
|
||||
networks: [appnet]
|
||||
|
||||
# Optional: Jackett for niche indexers
|
||||
jackett:
|
||||
image: lscr.io/linuxserver/jackett:latest
|
||||
container_name: jackett
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/jackett/config:/config
|
||||
- /opt/jackett/torrences:/torrences
|
||||
ports:
|
||||
- "9117:9117"
|
||||
networks: [appnet]
|
||||
|
||||
# Optional: Whisparr for adult content
|
||||
whisparr:
|
||||
image: lscr.io/linuxserver/whisparr:latest
|
||||
container_name: whisparr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/whisparr/config:/config
|
||||
- /mnt/media/whisparr-movies:/whisparr-movies
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "6969:6969"
|
||||
networks: [appnet]
|
||||
```
|
||||
|
||||
## Caddy Configuration
|
||||
|
||||
```caddy
|
||||
radarr.dankserver.local {
|
||||
reverse_proxy localhost:7878
|
||||
}
|
||||
|
||||
sonarr.dankserver.local {
|
||||
reverse_proxy localhost:8989
|
||||
}
|
||||
|
||||
lidarr.dankserver.local {
|
||||
reverse_proxy localhost:8686
|
||||
}
|
||||
|
||||
readarr.dankserver.local {
|
||||
reverse_proxy localhost:8787
|
||||
}
|
||||
|
||||
prowlarr.dankserver.local {
|
||||
reverse_proxy localhost:9696
|
||||
}
|
||||
|
||||
qbittorrent.dankserver.local {
|
||||
reverse_proxy localhost:8080
|
||||
}
|
||||
|
||||
# Optional: Jackett
|
||||
jackett.dankserver.local {
|
||||
reverse_proxy localhost:9117
|
||||
}
|
||||
|
||||
# Optional: Whisparr
|
||||
whisparr.dankserver.local {
|
||||
reverse_proxy localhost:6969
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Steps
|
||||
|
||||
### Phase 1: Download Client
|
||||
|
||||
1. Deploy qBittorrent first (or Transmission).
|
||||
2. In the qBittorrent Web UI, set **No auth mode** for LAN (Settings → Web UI).
|
||||
3. Create download categories: `movies`, `tv`, `music`, `books`.
|
||||
4. Change the default Web UI password.
|
||||
|
||||
### Phase 2: Indexer Management
|
||||
|
||||
1. Deploy Prowlarr.
|
||||
2. Add indexers (3–5 recommended for testing). Use the **Test** button on each.
|
||||
3. Add qBittorrent as a download client in Prowlarr.
|
||||
4. Verify search from the Prowlarr web UI.
|
||||
|
||||
### Phase 3: Arr Apps (one at a time)
|
||||
|
||||
1. Deploy Sonarr first (TV shows are the most common use case).
|
||||
2. Add Prowlarr as the indexer source (Settings → Indexers → Add Prowlarr).
|
||||
3. Add qBittorrent as the download client with categories.
|
||||
4. Add a test series. Wait for the episode to download. Verify in `/tv/`.
|
||||
5. Repeat for Radarr, Lidarr, Readarr.
|
||||
|
||||
### Phase 4: Media Server Integration
|
||||
|
||||
1. Configure Jellyfin libraries pointing to `/movies`, `/tv`, `/music`, `/books`.
|
||||
2. Set **On Download** notifications in each arr app → Jellyfin webhook URL.
|
||||
3. Test end-to-end: Add a movie in Radarr → download → verify in Jellyfin.
|
||||
|
||||
## Quality Profiles
|
||||
|
||||
Each arr app uses a hierarchical quality system:
|
||||
|
||||
1. **Quality Profile** — Defines tiers (e.g., 2160p → 1080p BluRay → 720p).
|
||||
2. **Cutoff** — The quality target. Downloads at or above cutoff are accepted.
|
||||
3. **Custom Formats** — Additional filters (e.g., "Has HDR", "Is Director's Cut").
|
||||
4. **Search on Grab** — When content becomes available, all indexers are queried.
|
||||
|
||||
### Radarr (Movies)
|
||||
|
||||
```
|
||||
Profile: Movies 4K
|
||||
Tiers:
|
||||
1. 2160p BluRay REMUX
|
||||
2. 2160p BluRay
|
||||
3. 2160p WEB-DL
|
||||
4. 1080p BluRay
|
||||
5. 1080p WEB-DL
|
||||
6. 720p
|
||||
Cutoff: 1080p BluRay
|
||||
```
|
||||
|
||||
### Sonarr (TV)
|
||||
|
||||
```
|
||||
Profile: TV - Standard
|
||||
Tiers: 2160p → 1080p → 720p
|
||||
Min Size: 500 MB
|
||||
Max Size: 50 GB
|
||||
Cutoff: 1080p
|
||||
Language Profile: English audio preferred
|
||||
```
|
||||
|
||||
### Lidarr (Music)
|
||||
|
||||
```
|
||||
Profile: Music - Standard
|
||||
Tiers: Lossless (FLAC) → 320 kbps → 192 kbps
|
||||
Cutoff: 320 kbps (or Lossless)
|
||||
```
|
||||
|
||||
## Metadata Sources
|
||||
|
||||
| App | Primary Source | Secondary |
|
||||
|-----|---------------|-----------|
|
||||
| Radarr | TMDB | TheMovieDB API |
|
||||
| Sonarr | TMDB | TVDB |
|
||||
| Lidarr | MusicBrainz | — |
|
||||
| Readarr | Goodreads, StoryGraph | — |
|
||||
| Whisparr | XH | TMDB |
|
||||
|
||||
## *arr Stack vs Copyparty
|
||||
|
||||
| Feature | Copyparty | *arr Stack |
|
||||
|---------|-----------|------------|
|
||||
| Auto-download from torrents | Basic (RSS + scripts) | Native, integrated |
|
||||
| Quality profiles | No | Multi-tier, custom formats |
|
||||
| Series/movie tracking | No | Watch lists, air dates |
|
||||
| Manual library management | Yes | Yes, metadata-driven |
|
||||
| Multi-user watchlists | No | Yes |
|
||||
| Complexity | Low | Medium |
|
||||
| Resource usage | Minimal | Moderate |
|
||||
|
||||
Use Copyparty for curated file collections. Use *arr for automatic downloads. Use both together for maximum functionality — point *arr download directories at Copyparty's watched folders.
|
||||
## Live State (as-built, verified 2026-08-29)
|
||||
|
||||
Deployed shape differs from the design compose above — reality wins:
|
||||
|
||||
- Mounts are the real array paths (`/mnt/entropy/downloads`, case-exact dirs
|
||||
like `Movies`/`TVShows`), not `/mnt/media/*`; TZ is `America/Los_Angeles`.
|
||||
- Readarr runs `lscr.io/linuxserver/readarr:amd64-1.0.980` — LSIO ships no
|
||||
untagged `latest` for readarr; the tag was pinned after a manifest probe.
|
||||
- Prowlarr's `/config` mount was missing mid-deploy (off-by-one in an edit);
|
||||
restored in commit `67695cf`.
|
||||
- **Auth posture: every arr runs `AuthenticationMethod=None` +
|
||||
`AuthenticationRequired=Enabled`** — verified live via each config.xml and by
|
||||
probing `/api/v3/system/status` unauthenticated (401 on all five, local and
|
||||
through the vhost). Net effect: a login screen with **zero users defined**;
|
||||
whoever creates the first account owns the instance. Decide the auth method
|
||||
(`None` behind the Anubis wall vs `External` via authentik) *before* WAN
|
||||
exposure — first-account-wins is the current race condition.
|
||||
- API keys live in each `/config/config.xml` (`<ApiKey>`); they are local-only
|
||||
secrets and stop being secret the moment a vhost serves the API unauthenticated.
|
||||
### Chain wiring (verified live 2026-08-29)
|
||||
## Chain wiring (verified live 2026-08-30)
|
||||
|
||||
The download chain is wired and test-first verified: **indexers → Prowlarr →
|
||||
per-arr qBittorrent clients (category = app name) → import**.
|
||||
@@ -364,72 +105,46 @@ per-arr qBittorrent clients (category = app name) → import**.
|
||||
and hand off to their own qB download client (category routing). Mappings
|
||||
materialize at grab time — zero mappings right after wiring is expected,
|
||||
not a fault.
|
||||
**Chain complete (same day):** all four arr roots live — Sonarr `/tv`,
|
||||
Radarr `/movies` (201), and Lidarr `/music` + Readarr `/books` created via
|
||||
API after the v1 validator layers peeled back one at a time
|
||||
(`defaultQualityProfileId`/`defaultMetadataProfileId` must reference an
|
||||
*existing* profile id on v1 apps; v1 has no `/api/v1/profile` endpoint —
|
||||
probe endpoints by status code, empty body = absent).
|
||||
|
||||
**Auth-config pitfall (found same day):** all five arrs shipped with
|
||||
`AuthenticationMethod=None` **plus** `AuthenticationRequired=Enabled`. On the
|
||||
v1 (.NET) apps that combo is self-contradictory — UI Save is permanently
|
||||
disabled and any settings save throws
|
||||
`DryIoc.ScopedItemException` inside `AuthorizationMiddleware` (500 sprawl on
|
||||
every page after restart). The valid representation of "no auth" in v1 is
|
||||
**absence of the `<AuthenticationRequired>` key**, not the literal string
|
||||
`Disabled` — readarr's config (key absent) booted clean while its three
|
||||
siblings (key=`Disabled`) 500-sprawled, which is how it was caught. Fix
|
||||
applied live: key deleted on sonarr/radarr/lidarr/prowlarr, containers
|
||||
restarted, all five verified serving. Posture = zero-auth arrs on LAN and
|
||||
WAN; the Anubis wall guards homepage/search/hermes/prometheus/romm/files
|
||||
but **not** the arrs — if WAN exposure of `/sonarr`, `/radarr` etc. is
|
||||
undesired, guard them in the Anubis policy or flip auth to `External`
|
||||
(needs an IdP first; auth method choice remains an operator decision).
|
||||
|
||||
## Disk Layout
|
||||
## Disk layout (current)
|
||||
|
||||
```
|
||||
/mnt/media/
|
||||
├── movies/ → Radarr root
|
||||
├── tv/ → Sonarr root
|
||||
├── music/ → Lidarr root
|
||||
├── books/ → Readarr root
|
||||
├── whisparr-movies/ → Whisparr root
|
||||
├── downloads/ → qBittorrent download dir
|
||||
│ ├── movies/
|
||||
│ ├── tv/
|
||||
│ ├── music/
|
||||
│ └── books/
|
||||
└── incomplete/ → qBittorrent incomplete downloads
|
||||
/Volumes/COMPLETE <- completed-media volume (Mac volume)
|
||||
├── sonarr-data:/config <- per-app config roots, one per unit
|
||||
├── radarr-data:/config
|
||||
├── lidarr-data:/config
|
||||
├── readarr-data:/config
|
||||
├── qbittorrent-data:/config
|
||||
└── <movie/tv/music/books roots> <- arr import roots live here
|
||||
/Volumes/INCOMPLETE <- qB in-flight downloads (same path inside qB)
|
||||
```
|
||||
|
||||
qB mounts both volumes at their identical host paths
|
||||
(`Volume=/Volumes/COMPLETE:/Volumes/COMPLETE`,
|
||||
`Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE`), so a category's download path
|
||||
is the same string on every container that touches it — no remapping between
|
||||
download and import.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Timezone mismatch:** All containers should use the same TZ. Sonarr's scheduler is timezone-sensitive.
|
||||
- **File permissions:** Set `umask=022` in qBittorrent. Ensure arr apps can read/move downloaded files.
|
||||
- **Network conflicts:** *arr apps use many ports. Check for conflicts with existing Dankserver services.
|
||||
- **Prowlarr API key rotation:** If rotated, update it in every arr app.
|
||||
- **qBittorrent Web UI password:** Change default on first run.
|
||||
- **Readarr stability:** Readarr is still in development. Do not rely on it for mission-critical collections.
|
||||
- **Whisparr separate Jellyfin library:** Keep adult content separate from regular media.
|
||||
- **RSS feed in qBittorrent:** Can auto-add torrents matching a pattern. Useful for podcast-like series.
|
||||
- **Timezone:** every unit runs `TZ=America/Los_Angeles`; Sonarr's scheduler is timezone-sensitive — keep them uniform.
|
||||
- **File permissions:** `UMASK_SET=022` on qBittorrent; arr apps run PUID=0 so they can read/move qB downloads.
|
||||
- **Network conflicts:** *arr apps use many ports. On the machine VM, only the API ports (8989/7878/8686/8787/9696) and gluetun's published 8080 + 6881 are host-published; netns-sharers (qB) publish none of their own.
|
||||
- **Prowlarr API key rotation:** If rotated, update it in every arr app (`Applications` table rows carry the real keys).
|
||||
- **qBittorrent WebUI password:** generated at first boot, not a default — persist it via the PBKDF2 conf recipe in [[qBittorrent]] before any restart.
|
||||
- **Readarr stability:** abandoned upstream (retired May 2026); its qB download client is parked pending a successor image. Do not rely on it for mission-critical collections.
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. Use tags to route content to specific download clients or categories.
|
||||
2. Enable the Blocklist in arr apps to prevent re-downloading failed torrents.
|
||||
3. Set download limits in qBittorrent to avoid bandwidth saturation.
|
||||
4. Back up arr configs regularly (they are small SQLite DBs + JSON).
|
||||
4. Back up arr configs regularly (they are small SQLite DBs + JSON) — each lives at `/Volumes/COMPLETE/<svc>-data/config`.
|
||||
5. Monitor Prowlarr indexer health — broken indexers hide new content.
|
||||
6. Start with default quality profiles. Add custom formats gradually.
|
||||
7. Back up arr configs: `./radarr/config`, `./sonarr/config`, etc.
|
||||
|
||||
## See Also
|
||||
|
||||
- [[Dankserver Stack]]
|
||||
- [[Sonarr]] · [[Radarr]] · [[Lidarr]] · [[Readarr]] · [[Prowlarr]] · [[qBittorrent]] — per-service pages
|
||||
- [[Jellyfin]] — media server that consumes *arr downloads
|
||||
- [[Copyparty]] — alternative file viewer
|
||||
- [[Calibre-Web]] — manual ebook management (Readarr auto-downloads into the same library)
|
||||
- [Sonarr Wiki](https://wiki.servarr.com/sonarr)
|
||||
- [Radarr Wiki](https://wiki.servarr.com/radarr)
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
Calibre-Web is a web application that browses, reads, and downloads eBooks from an existing Calibre library database. It serves as the web frontend for the Calibre e-book manager.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `books.dankserver.local` — **Docs:** https://github.com/linuxserver/docker-calibre-web
|
||||
**Host:** Dankserver — **Access:** `books.franksdank.cloud` (unguarded Caddy
|
||||
vhost — Calibre-Web serves its own login; direct proxy to
|
||||
`192.168.0.235:8083`) — **Docs:** https://github.com/linuxserver/docker-calibre-web
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Latest version | 0.6.25-ls365 (live); 0.6.27-ls397 upstream |
|
||||
| Image | `lscr.io/linuxserver/calibre-web:latest` (live: 0.6.25-ls365) |
|
||||
| Running image | `lscr.io/linuxserver/calibre-web:0.6.27-ls397` — **pinned** (verified from the live quadlet unit; the pin was chosen so the cutover changed zero bits of application code) |
|
||||
| Network | `pasta` (the default rootless-podman userslide network); only 8083 is host-published |
|
||||
| Base OS | Ubuntu Noble (24.04 LTS, since 2024-12-05) |
|
||||
| Port | 8083 (host) → 8083 (container) |
|
||||
| Default login | `admin` / `admin123` |
|
||||
@@ -34,7 +36,7 @@ Additional packages added: `libxfixes3` and `libasound2t64` to support epub-to-p
|
||||
|----------|-------|-------------|
|
||||
| `PUID` | `1000` | User ID |
|
||||
| `PGID` | `1000` | Group ID |
|
||||
| `TZ` | `Etc/UTC` | Timezone |
|
||||
| `TZ` | `America/Vancouver` (live unit value — not `Etc/UTC`) |
|
||||
| `DOCKER_MODS` | `linuxserver/mods:universal-calibre` | Optional: enables ebook conversion tools |
|
||||
| `OAUTHLIB_RELAX_TOKEN_SCOPE` | `1` | Required for Google OAuth |
|
||||
|
||||
|
||||
@@ -25,16 +25,21 @@ Calibre 9.2.1 is the version on the live host (9.9.0 is the upstream latest). Ma
|
||||
|
||||
## Library Directory
|
||||
|
||||
| Purpose | Host path (convention) |
|
||||
|---------|------------------------|
|
||||
| Calibre library | `/opt/calibre-web/books` (bind-mounted to `/books` in the Calibre-Web container) |
|
||||
The live Calibre-Web container bind-mounts the library at `/books`:
|
||||
|
||||
| Purpose | Host path (live) |
|
||||
|---------|------------------|
|
||||
| Calibre library | `/home/dank/Containers/calibre-web/books` → `/books` in the Calibre-Web container |
|
||||
|
||||
(The older `/opt/calibre-web/books` path was the compose-era location and is
|
||||
gone; the quadlet unit mounts the Containers data root.)
|
||||
|
||||
## What the Container Needs
|
||||
|
||||
- Read/write access to the library directory. Calibre-Web edits metadata through the database file.
|
||||
- Ownership matching `PUID=1000` / `PGID=1000` (the `dank` user on Dankserver).
|
||||
|
||||
## Optional: Calibre Content Server
|
||||
## Optional: Calibre Content Server (not running)
|
||||
|
||||
Calibre includes a built-in HTTP content server (`calibre-server`) that can serve the library via OPDS feeds and a mobile-friendly web interface. This enables:
|
||||
- OPDS feeds for mobile reading apps (FBReader, Moon+ Reader)
|
||||
|
||||
@@ -2,14 +2,16 @@
|
||||
|
||||
Copyparty is a lightweight file server and media streamer that runs as a single Python binary. It handles large payloads, media streaming, resumable uploads, directory browsing, and WebDAV from one process.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `files.dankserver.local` — **Docs:** https://github.com/9001/copyparty
|
||||
**Host:** Dankserver — **Access:** `files.franksdank.cloud` guarded by the
|
||||
Anubis → Authentik chain ([[Caddy]] routes it post-auth to
|
||||
`192.168.0.235:3923`); the published port itself stays unauthenticated on the
|
||||
LAN — **Docs:** https://github.com/9001/copyparty
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Latest version | v1.20.21 (2026-08) |
|
||||
| Image | `ghcr.io/9001/copyparty-ac:latest` (ac = full edition; the bare `copyparty:latest` tag does not exist — ghcr answers 403 on the token request for nonexistent repos) |
|
||||
| Running image | `ghcr.io/9001/copyparty-ac:latest` (ac = full edition; the bare `copyparty:latest` tag does not exist — ghcr answers 403 on the token request for nonexistent repos). Version at research time (2026-08): v1.20.21 |
|
||||
| Port | 3923 (host) → 3923 (container) |
|
||||
| Volume | bind mount the shared root directory |
|
||||
| Auth | Per-directory `.cpy` config files, HTTP basic auth, `dirkeys`, `filekeys` |
|
||||
@@ -72,13 +74,12 @@ The `iv` edition is no longer available for arm32/armv6. Use `dj` for maximum co
|
||||
|
||||
## Volumes
|
||||
|
||||
Live deployment: the whole LUKS array is served at URL `/w` (the ac edition
|
||||
takes its volume roots from argv plus `chdir: /w` in `/z/initcfg`, not from a
|
||||
`/data` convention). Access is **read-only since 2026-08-31** (`-v /w::r:ra,dank`
|
||||
— see [[#Command-line interface (ac edition)]] above). The compose bind mount is
|
||||
`/mnt/entropy:/w` (host path → container path). Note the bind itself is still
|
||||
rw on disk — copyparty enforces read-only at the application layer, so local
|
||||
services (Jellyfin, Calibre) keep writing into the array directly.
|
||||
Live deployment: the whole LUKS array is served at URL `/w` via
|
||||
`Volume=/mnt/entropy:/w:ro` in the quadlet unit ([[Entropy Volume]]) —
|
||||
read-only **at the mount level**, so no containerized consumer can write into
|
||||
the array through this path regardless of account permissions. The ac edition
|
||||
takes its volume roots from argv (`-v /w::r:ra,dank`), not from a `/data`
|
||||
convention; see [[#Command-line interface (ac edition)]] above.
|
||||
|
||||
## Docker Compose (reference — retired 2026-09-01; live deployment is the quadlet unit below)
|
||||
|
||||
@@ -146,13 +147,15 @@ Upgrade to v1.20.19+ to cover all known CVEs. The dirkey fix (v1.20.17) matters
|
||||
- **Large transfers:** Disable TLS inside the app and let Caddy terminate TLS. This avoids double encryption overhead.
|
||||
- **Dedicated share directory:** Do not give Copyparty the whole disk. Mount only the intended share path.
|
||||
- **Whole-disk share (live choice):** this deployment *does* serve the whole
|
||||
91 T array from `/w`. Since 2026-08-31 the volume is application-level
|
||||
read-only for every account, so no remote write path exists. But note:
|
||||
~91 T array from `/w`. The volume is mounted `:ro` in the unit AND the
|
||||
permission flags grant anonymous only `r`, so no remote write path exists at
|
||||
all now. But note:
|
||||
**LAN-direct `:3923` is unauthenticated browse/download** (anonymous holds
|
||||
`r`) — Caddy + Anubis + authentik guard only `files.franksdank.cloud`, not
|
||||
the published port. Tighten to `-v /w::r,dank` if anonymous LAN reads become
|
||||
unacceptable. (Before 2026-08-31, `-v /w::A` made the array world-writable
|
||||
on the LAN — see [[#Command-line interface (ac edition)]].)
|
||||
on the LAN — see [[#Command-line interface (ac edition)]] — and the mount
|
||||
was rw.)
|
||||
- **Upload tokens scoped per folder:** Prevents accidental global write access.
|
||||
- **CSP nonces (v1.20.17+):** Security hardening for JavaScript execution. May break third-party JS plugins (`--js-browser` / `--html-head`).
|
||||
- **Custom thumbnail extractors (v1.20.19+):** New `thumbex` framework. Requires configuration in `initcfg`.
|
||||
|
||||
@@ -1,45 +1,40 @@
|
||||
# Dankserver Stack
|
||||
|
||||
Dankserver (192.168.0.235) runs the media and library stack. Every service is reachable by hostname through the Caddy reverse proxy on the host.
|
||||
Dankserver (192.168.0.235) runs the media and library stack. Public access
|
||||
goes through the Caddy reverse proxy on Dankclaw; the *arr stack is exempt by
|
||||
construction — it has no vhost and is reached directly by IP:port on the LAN.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
U[User] --> C[Caddy :80/:443]
|
||||
C --> R[RomM]
|
||||
C --> P[Copyparty]
|
||||
C --> W[Calibre-Web]
|
||||
C --> J[Jellyfin]
|
||||
C --> S[Sonarr]
|
||||
C --> D[Radarr]
|
||||
C --> L[Lidarr]
|
||||
C --> A[Readarr]
|
||||
C --> O[Prowlarr]
|
||||
W --> L2[Calibre library]
|
||||
U[User] --> C[Caddy :80/:443 on Dankclaw]
|
||||
C -->|guarded: Anubis + Authentik| R[RomM :8085]
|
||||
C -->|guarded| P[Copyparty :3923]
|
||||
C -->|unguarded| W[Calibre-Web :8083]
|
||||
C -->|unguarded| J[Jellyfin :8096]
|
||||
C -->|exempt by construction| X[Plex :32400]
|
||||
U -->|direct IP:port, no vhost| S[ARR stack + Prowlarr + qBittorrent on FrankBook-Pro]
|
||||
```
|
||||
|
||||
## Services
|
||||
|
||||
| Service | Hostname | Port | Docs |
|
||||
|---------|----------|------|------|
|
||||
| RomM | romm.dankserver.local | 8085 | [[RomM]] |
|
||||
| Copyparty | files.dankserver.local | 3923 | [[Copyparty]] |
|
||||
| Calibre-Web | books.dankserver.local | 8083 | [[Calibre-Web]] |
|
||||
| Jellyfin | jellyfin.dankserver.local | 8096 | [[Jellyfin]] |
|
||||
| Sonarr | sonarr.dankserver.local | 8989 | [[ARR-Stack]] |
|
||||
| Radarr | radarr.dankserver.local | 7878 | [[ARR-Stack]] |
|
||||
| Lidarr | lidarr.dankserver.local | 8686 | [[ARR-Stack]] |
|
||||
| Readarr | readarr.dankserver.local | 8787 | [[ARR-Stack]] |
|
||||
| Prowlarr | prowlarr.dankserver.local | 9696 | [[ARR-Stack]] |
|
||||
| qBittorrent | qbittorrent.dankserver.local | 8080 | [[ARR-Stack]] |
|
||||
| Service | Public route | Port | Docs |
|
||||
|---------|--------------|------|------|
|
||||
| RomM | `romm.franksdank.cloud` (guarded: Anubis → Authentik; post-auth route → 192.168.0.235:8085) | 8085 | [[RomM]] |
|
||||
| Copyparty | `files.franksdank.cloud` (guarded; post-auth route → 192.168.0.235:3923) | 3923 | [[Copyparty]] |
|
||||
| Calibre-Web | `books.franksdank.cloud` (unguarded — own login) | 8083 | [[Calibre-Web]] |
|
||||
| Jellyfin | `jelly.franksdank.cloud` (unguarded — own auth) | 8096 | [[Jellyfin]] |
|
||||
| Plex | `plex.franksdank.cloud` (+ legacy plain-HTTP `plex.franksdank.casa`) | 32400 | [[Plex]] |
|
||||
|
||||
## Optional Services
|
||||
The *arr stack (Sonarr 8989, Radarr 7878, Lidarr 8686, Readarr 8787,
|
||||
Prowlarr 9696) and qBittorrent (8080, behind the [[Gluetun]] tunnel netns)
|
||||
run on **FrankBook-Pro**, not on this host — see [[ARR-Stack]]; none of them
|
||||
have a Caddy vhost.
|
||||
|
||||
These services are included in the compose file but may be disabled.
|
||||
## Never-deployed services
|
||||
|
||||
| Service | Hostname | Port | Docs |
|
||||
|---------|----------|------|------|
|
||||
| Jackett | jackett.dankserver.local | 9117 | [[ARR-Stack]] |
|
||||
| Whisparr | whisparr.dankserver.local | 6969 | [[ARR-Stack]] |
|
||||
Jackett and Whisparr were evaluated during the ARR-stack design phase and
|
||||
never deployed (no unit, no vhost, no live container). Prowlarr covers the
|
||||
indexer-aggregation role — see [[Prowlarr]].
|
||||
|
||||
## Removed Services
|
||||
|
||||
|
||||
@@ -1,226 +1,68 @@
|
||||
---
|
||||
type: reference
|
||||
title: Jellyfin
|
||||
description: Jellyfin media server on Dankserver — quadlet unit, entropy-volume data layout, ports, client access, and hardware-transcode status.
|
||||
tags: [jellyfin, dankserver, media-server]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# Jellyfin
|
||||
|
||||
Jellyfin is a free, open-source media server and suite of applications for organizing, managing, and streaming personal media collections (movies, TV shows, music, photos) to networked devices. It is a community fork of Emby, written in C# (.NET), and uses FFmpeg for transcoding.
|
||||
Jellyfin is the free media server on Dankserver — a podman quadlet service
|
||||
(`jellyfin.service`, generated from `dankserver/jellyfin/quadlet/jellyfin.container`)
|
||||
serving music, movies, and shows over LAN. It replaced the earlier research
|
||||
brief; it runs alongside [[Plex]], which remains the primary server for some
|
||||
clients.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `jellyfin.dankserver.local` — **Docs:** https://jellyfin.org
|
||||
**Host:** Dankserver (192.168.0.235) — **Access:** `http://192.168.0.235:8096`,
|
||||
public vhost `jelly.franksdank.cloud` behind the [[Anubis]] guard chain →
|
||||
[[Authentik]] outpost (post-auth route proxies `localhost:8096`).
|
||||
|
||||
## Facts
|
||||
## Facts (verified from the live unit, 2026-09-03)
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Latest version | Check https://jellyfin.org/downloads |
|
||||
| Image | `jellyfin/jellyfin:latest` (Docker Hub) or `ghcr.io/jellyfin/jellyfin` |
|
||||
| Base | Debian-based |
|
||||
| Primary port | 8096 (HTTP, web UI + API) |
|
||||
| HTTPS port | 8920 (optional) |
|
||||
| Client discovery | 7359/udp |
|
||||
| DLNA | 1900/udp (optional) |
|
||||
| GPU passthrough | `/dev/dri` (Intel QSV / AMD VA-API) or NVIDIA NVENC |
|
||||
| License | MIT |
|
||||
| Unit | `~/.config/containers/systemd/jellyfin.container` → `jellyfin.service` (user manager), `Restart=always`, `RestartSec=5` |
|
||||
| Image | `ghcr.io/jellyfin/jellyfin:latest` |
|
||||
| Network | `dankserver_appnet`; publishes 8096/tcp, 8920/tcp, 7359/udp, 1900/udp |
|
||||
| Data roots | `/home/dank/Containers/jellyfin/config:/config`, `/home/dank/Containers/jellyfin/cache:/cache` |
|
||||
| Media | `Volume=/mnt/entropy:/data:ro` — the whole [[Entropy Volume]] mounted read-only; nothing automated writes to it |
|
||||
| GPU | none — no `AddDevice`; CPU decode only (jellyfin-ffmpeg path) |
|
||||
| Env quirks | `DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true`, `LD_PRELOAD=libjemalloc.so.2`, `MALLOC_TRIM_THRESHOLD_=131072` kept verbatim from the compose-era container (zero-drift cutover) |
|
||||
| Health | `curl -f http://localhost:8096/health` every 30 s |
|
||||
|
||||
## Architecture
|
||||
## Data layout
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
U[User] --> C[Caddy :80/:443]
|
||||
C --> J[Jellyfin :8096]
|
||||
J --> Lib[/media/movies]
|
||||
J --> Lib2[/media/shows]
|
||||
J --> Lib3[/media/music]
|
||||
J --> Conf[Jellyfin config]
|
||||
J --> Cache[Jellyfin cache]
|
||||
```
|
||||
/home/dank/Containers/jellyfin/config -> /config (JELLYFIN_DATA_DIR)
|
||||
/home/dank/Containers/jellyfin/cache -> /cache (JELLYFIN_CACHE_DIR, XDG_CACHE_HOME)
|
||||
/mnt/entropy -> /data (read-only media volume)
|
||||
```
|
||||
|
||||
## Docker Compose (reference — retired 2026-09-01; live mounts use `/home/dank/Containers/jellyfin`, see Deployment below)
|
||||
Library folders point at `/data` paths; because the mount uses the same
|
||||
absolute path as on the host, library paths survive container recreation.
|
||||
|
||||
```yaml
|
||||
services:
|
||||
jellyfin:
|
||||
image: jellyfin/jellyfin:latest
|
||||
container_name: jellyfin
|
||||
restart: unless-stopped
|
||||
user: "1000:1000"
|
||||
ports:
|
||||
- "8096:8096/tcp"
|
||||
- "8920:8920/tcp"
|
||||
- "7359:7359/udp"
|
||||
- "1900:1900/udp"
|
||||
environment:
|
||||
- JELLYFIN_PublishedServerUrl=http://192.168.0.235:8096
|
||||
- DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true
|
||||
volumes:
|
||||
- /opt/jellyfin/config:/config
|
||||
- /opt/jellyfin/cache:/cache
|
||||
- /mnt/media/movies:/data/movies:ro
|
||||
- /mnt/media/shows:/data/shows:ro
|
||||
devices:
|
||||
- /dev/dri:/dev/dri
|
||||
group_add:
|
||||
- "992" # Host render group GID — verify with `getent group render`
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8096/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
## Ports & access
|
||||
|
||||
## Caddy Configuration
|
||||
| Port | Proto | Purpose |
|
||||
|------|-------|---------|
|
||||
| 8096 | TCP | Web UI + API (`JELLYFIN_PublishedServerUrl=http://192.168.0.235:8096`) |
|
||||
| 8920 | TCP | DLNA/UPnP root device control |
|
||||
| 7359 | UDP | service discovery (client auto-discovery) |
|
||||
| 1900 | UDP | SSDP discovery |
|
||||
|
||||
```caddy
|
||||
jellyfin.dankserver.local {
|
||||
reverse_proxy 127.0.0.1:8096
|
||||
Client access paths and the public-exposure policy (auth wall required before
|
||||
any public vhost; Plex-style claim tokens do not exist here — Jellyfin uses its
|
||||
own users/API keys) follow the fleet [[Authentik]]/[[Anubis]] chain pattern.
|
||||
|
||||
transport http {
|
||||
versions h2c 1.1
|
||||
}
|
||||
}
|
||||
```
|
||||
## Configuration workflow
|
||||
|
||||
Set **Base URL** to `/` (or the path you configure) in Jellyfin Dashboard → Networking. Add `127.0.0.1` to **Known Proxies**.
|
||||
|
||||
## Storage
|
||||
|
||||
| Mount | Purpose | Size Estimate |
|
||||
|-------|---------|---------------|
|
||||
| `/home/dank/Containers/jellyfin/config` | SQLite database, settings, cached images | 10–100 GB |
|
||||
| `/home/dank/Containers/jellyfin/cache` | Transcoding segments, extracted posters | Self-cleaning per session |
|
||||
| `/mnt/entropy/Movies`, `/mnt/entropy/TVShows` | Media, **read-only binds** (`:ro`) — no automated write path | — |
|
||||
|
||||
The database must be on local storage (SSD/NVMe preferred). Media libraries can be on NFS/mergerfs. If media is on NFS, set `DOTNET_SYSTEM_IO_DISABLEFILELOCKING=true`.
|
||||
|
||||
## Deployment (Quadlet)
|
||||
|
||||
Since 2026-09-01: `dankserver/jellyfin/quadlet/jellyfin.container` →
|
||||
`jellyfin.service` (generator-enabled), deployed with
|
||||
`./scripts/deploy.sh dankserver --service jellyfin`. GPU passthrough uses
|
||||
`AddDevice=/dev/dri` — plain `Device=` is **not** a quadlet key and makes the
|
||||
v1 generator reject the whole unit (learned live: "unsupported key 'Device'
|
||||
in group 'Container'"). Entropy mounts stay `:ro`; the container runs as
|
||||
root inside the user namespace, so the render-node ACLs apply via the device
|
||||
cgroup regardless of `GroupAdd=keep-groups`.
|
||||
|
||||
## Authentication
|
||||
|
||||
- **Built-in auth:** per-user libraries, parental controls, max bitrate
|
||||
limits. The local `dank` admin account is built-in; its password is
|
||||
Frank's bootstrap value — never recorded in this repo. (2026-09-01: a
|
||||
corrupted session-archive reading briefly suggested the password had
|
||||
changed; verified offline against the stored PBKDF2-SHA512 hash, the
|
||||
bootstrap value still authenticates.)
|
||||
- **LDAP via Authentik (live 2026-09-01):** the LDAP-Auth plugin
|
||||
authenticates users against the authentik LDAP outpost on Dankclaw — see
|
||||
[[Authentik]] for the outpost unit, provider, and RBAC objects.
|
||||
|
||||
### LDAP-Auth plugin (v23.0.0.0, live 2026-09-01)
|
||||
|
||||
- **Install from the GitHub releases zip** — `repo.jellyfin.org`'s stable
|
||||
manifest path 404s here, so fetch
|
||||
`jellyfin/jellyfin-plugin-ldapauth` release asset
|
||||
`ldap-authentication_23.0.0.0.zip` from GitHub and unzip into
|
||||
`config/plugins/LDAP-Auth_23.0.0.0/`. The config lives at
|
||||
`config/plugins/configurations/LDAP-Auth.xml` — write it directly, then
|
||||
restart the service.
|
||||
- **Live config:** server `192.168.0.143:389`, base DN
|
||||
`dc=franksdank,dc=cloud`, bind DN
|
||||
`cn=svc-jellyfin-ldap,ou=users,dc=franksdank,dc=cloud`, bind password =
|
||||
the authentik outpost token (secret — the XML lives on the host only,
|
||||
never in the repo), search filter
|
||||
`(memberOf=cn=jellyfin_users,ou=groups,dc=franksdank,dc=cloud)`, admin
|
||||
filter on `cn=jellyfin_admins,ou=groups,…`, `CreateUsersFromLdap=true`
|
||||
(auto-create on first login).
|
||||
- **Attribute separator is a comma.** `LdapSearchAttributes` is
|
||||
`Split(',')` in the plugin source — a semicolon-separated list
|
||||
(`uid;cn;mail;displayName`) parses as ONE bogus attribute, the search
|
||||
silently matches nothing, and the log says `Found no users matching X`.
|
||||
Use `uid,cn,mail,displayName`.
|
||||
- **Username attribute is `cn`.** Authentik 2026.x maps `uid` to an opaque
|
||||
per-user hash, not the username, so `uid=<name>` never matches. Set
|
||||
`LdapUsernameAttribute=cn` (authentik exposes the username as `cn`).
|
||||
- **Verify with a throwaway user:** create a test member of
|
||||
`jellyfin_users` in authentik, then
|
||||
`POST /Users/AuthenticateByName` with headers `Content-Type:
|
||||
application/json` **and** `X-Emby-Authorization: MediaBrowser
|
||||
Client="…", Device="…", DeviceId="…", Version="10.11.0"` — both are
|
||||
required in 10.11 (missing `X-Emby-Authorization` → 400). 200 + non-admin
|
||||
policy = LDAP path works. Delete the test user from authentik **and**
|
||||
Jellyfin afterward.
|
||||
- **Plugin load lines only show in `journalctl --user -u jellyfin.service`**
|
||||
(`Loaded plugin: LDAP-Auth 23.0.0.0`) — `podman logs` does not carry the
|
||||
loader lines in this image.
|
||||
|
||||
## Metadata Scraping
|
||||
|
||||
| Provider | Content | Type |
|
||||
|----------|---------|------|
|
||||
| TheMovieDb (TMDb) | Movies, TV shows, posters, fan art, overviews | Default |
|
||||
| OMDb API | Movies only, English metadata | Default |
|
||||
| TheTVDB | TV shows, episodes | Plugin |
|
||||
| fanart.tv | Extra artwork, banners, thumbnails | Plugin |
|
||||
| AniDB | Anime metadata | Plugin |
|
||||
| MusicBrainz | Music metadata | Plugin |
|
||||
| Open Subtitles | Subtitle downloads | Plugin |
|
||||
| Intro Skipper | TV show intro detection | Plugin |
|
||||
|
||||
## Clients
|
||||
|
||||
| Platform | App | Quality |
|
||||
|----------|-----|---------|
|
||||
| Web | Jellyfin Web | Excellent |
|
||||
| Android | Jellyfin (Google Play / F-Droid) | Excellent |
|
||||
| Android TV / Fire TV | Jellyfin | Good |
|
||||
| iOS / iPadOS | Swiftfin (third-party) | Good |
|
||||
| Desktop | Jellyfin Media Player (mpv-based) | Excellent |
|
||||
| Roku | Jellyfin (Channel Store) | Good |
|
||||
| Kodi | Jellyfin addon | Excellent |
|
||||
| Samsung/LG Smart TVs | TV browser | Fair |
|
||||
|
||||
## Jellyfin vs Plex
|
||||
|
||||
| Feature | Jellyfin | Plex |
|
||||
|---------|----------|------|
|
||||
| Cost | Free, no tiers | Free core; Plex Pass ($5/mo or $120 lifetime) |
|
||||
| License | MIT | Proprietary |
|
||||
| Account required | No | Yes |
|
||||
| Hardware transcoding | Free | Plex Pass required |
|
||||
| Mobile sync | Free | Plex Pass |
|
||||
| Live TV / DVR | Free | Plex Pass |
|
||||
| Client apps | Good, improving | Excellent, widest device support |
|
||||
|
||||
Run Jellyfin alongside Plex for an incremental migration. Point Jellyfin at the same media folders as Plex. Watch history and metadata will not transfer cleanly.
|
||||
|
||||
## Resource Requirements
|
||||
|
||||
- **Idle / Direct Play:** ~200–500 MB RAM, <5% CPU. Negligible.
|
||||
- **1080p transcode (CPU):** 40–60% CPU on a modern multi-core CPU.
|
||||
- **1080p transcode (with QSV):** 3–5% CPU.
|
||||
- **4K HDR transcode (with QSV):** 5–15% CPU.
|
||||
- **Minimum host RAM:** 4 GB. 8 GB comfortable for transcoding.
|
||||
|
||||
## Deployment Checklist
|
||||
|
||||
1. Verify GPU on host: `ls -l /dev/dri/`, `lspci | grep -i vga`, `getent group render`.
|
||||
2. Install media drivers: `sudo apt install intel-media-va-driver-non-free vainfo intel-gpu-tools`.
|
||||
3. Create directories: `/home/dank/Containers/jellyfin/config`, `/home/dank/Containers/jellyfin/cache`.
|
||||
4. Write compose file, verify device and GID.
|
||||
5. Deploy: `podman compose up -d`.
|
||||
6. Test GPU passthrough: `podman exec jellyfin /usr/lib/jellyfin-ffmpeg/vainfo --display drm --device /dev/dri/renderD128`.
|
||||
7. Configure Caddy reverse proxy. Set Known Proxies in Jellyfin.
|
||||
8. Add media libraries in Dashboard.
|
||||
9. Install plugins: Open Subtitles, fanart.tv, Intro Skipper.
|
||||
10. Test playback on Android/Chrome.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **GPU passthrough silently failing:** `/dev/dri` must be passed and the correct render node used. Verify with `vainfo` inside the container.
|
||||
- **Wrong render group GID:** Common GID is 992, but varies per host. Run `getent group render` to find it.
|
||||
- **Subtitle burn-in triggers full transcode:** PGS (image-based) subtitles force full video transcoding. SRT/ASS (text-based) play fine.
|
||||
- **Database on NFS:** SQLite on network storage causes slow startup and corruption risk. Keep `/config` on local storage.
|
||||
- **Client bitrate limit too low:** Many clients default to 20 Mbps. Set Max Streaming Bitrate to Original or Maximum.
|
||||
- **Naming convention mismatches:** Non-standard folder/file names cause missing metadata. Use `Movie Title (Year)` for movies and `Show Name/Season 01/Show Name S01E01.mkv` for TV.
|
||||
1. Create libraries pointing at `/data` folders (movies, shows, audio).
|
||||
2. Set metadata/language preferences (`LANG=en_US.UTF-8` pinned in the unit).
|
||||
3. Configure clients to use `http://192.168.0.235:8096` or the guarded vhost.
|
||||
|
||||
## See Also
|
||||
|
||||
- [[Dankserver Stack]]
|
||||
- [[ARR-Stack]] — automated download into Jellyfin libraries
|
||||
- [[Copyparty]] — alternative file viewer for existing collections
|
||||
- Plex — existing media server on this host
|
||||
- [[Plex]] — co-resident media server on the same volume
|
||||
- [[Entropy Volume]] — the 91 T array mounted read-only at `/data`
|
||||
- [[Caddy]] · [[Anubis]] · [[Authentik]] — edge chain for `jelly.franksdank.cloud`
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Plex
|
||||
|
||||
Plex Media Server is the **containerized media server on Dankserver**: a
|
||||
podman quadlet (`plex.service`) under the systemd **user** generator,
|
||||
generated from `dankserver/plex/quadlet/plex.container`. It is the only media
|
||||
server actually listening on this host. Jellyfin, by contrast, is a research
|
||||
brief on this host, not a running service (see [[Jellyfin]]).
|
||||
Plex Media Server is a **containerized media server on Dankserver**: a podman
|
||||
quadlet (`plex.service`) under the systemd **user** generator, generated from
|
||||
`dankserver/plex/quadlet/plex.container`. It shares the host with a second live
|
||||
media server, [[Jellyfin]] (`jellyfin.service`, listening on 8096); both serve
|
||||
from the same read-only Entropy Volume mount.
|
||||
|
||||
**Host:** Dankserver — **Ports:** 32400/tcp (PMS web + API), 32400 is the
|
||||
only port PMS needs for client streaming; LAN clients connect directly,
|
||||
@@ -21,7 +21,7 @@ public traffic can be fronted by Caddy like every other vhost.
|
||||
| Identity | fleet rootless model — container root maps to the `dank` user (1000:1000); the deployer chowns the data root on first cutover |
|
||||
| Port | `32400/tcp` published on `0.0.0.0` — zero client reconfiguration |
|
||||
| Network | `dankserver_appnet`, alias `plex`; Tautulli reaches it at `http://plex:32400` |
|
||||
| GPU | none by decision — CPU decode only; the RTX 3090 stays dedicated to `frank-default-small` |
|
||||
| GPU | none by decision — CPU decode only; the RTX 3090 stays dedicated to `frank-small` |
|
||||
| Deploy | `./scripts/deploy.sh dankserver --service plex` |
|
||||
| Docs | https://support.plex.tv |
|
||||
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
RomM (ROM Manager) is a self-hosted ROM library manager and player. It scans a ROM collection, enriches it with metadata and cover art from multiple providers, and serves it through a clean web interface. RomM also supports browser-based emulation via EmulatorJS and native emulator streaming.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `romm.dankserver.local` — **Docs:** https://docs.romm.app
|
||||
**Host:** Dankserver — **Access:** `romm.franksdank.cloud` guarded by the
|
||||
Anubis → Authentik chain ([[Caddy]] routes it post-auth to
|
||||
`192.168.0.235:8085`) — **Docs:** https://docs.romm.app
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Latest version | 5.2.0 (released 2026-07-29) |
|
||||
| Image | `ghcr.io/rommapp/romm:latest` |
|
||||
| Running image | `ghcr.io/rommapp/romm:latest` (rolling tag — no pin; the version claims on this page were true at research time; verify against the live container before relying on them) |
|
||||
| Port | 8085 (host) → 8080 (container) |
|
||||
| Database | MariaDB (default); PostgreSQL optional |
|
||||
| Cache / Queue | Redis or Valkey (required for task queue) |
|
||||
@@ -21,7 +22,9 @@ RomM (ROM Manager) is a self-hosted ROM library manager and player. It scans a R
|
||||
|
||||
## Architecture
|
||||
|
||||
RomM 5.2.0 requires three supporting services. The compose stack includes `romm`, `mariadb`, and `redis` (or `valkey`).
|
||||
Current RomM releases require MariaDB plus Redis (or Valkey) for the task
|
||||
queue; this deployment runs **redis** (`REDIS_HOST=redis` in the live unit),
|
||||
not valkey.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
@@ -68,7 +71,7 @@ These are set via environment variables or in `config.yml`:
|
||||
| `MOBYGAMES_API_KEY` | MobyGames | Paid hobbyist API. Note: RomM recommends Screenscraper as free alternative. |
|
||||
| `RETROACHIEVEMENTS_API_KEY` | RetroAchievements | Hash-based achievements via bundled RAHasher binary. |
|
||||
| `STEAMGRIDDB_API_KEY` | SteamGridDB | Custom cover art via the search cover button. |
|
||||
| `HASHEOUS_API_ENABLED` | Hasheous | Set to `true`. Free, hash-based, proxies IGDB data. Fast scans. |
|
||||
| `HASHEOUS_API_ENABLED` | Hasheous | Set to `true` in the live unit env file. Free, hash-based, proxies IGDB data. Fast scans. |
|
||||
| `PLAYMATCH_API_ENABLED` | Playmatch | Set to `true`. Multi-provider hash matching (IGDB, SS, SteamGridDB, RA). |
|
||||
|
||||
### Config File
|
||||
@@ -117,15 +120,15 @@ Since 2026-09-01 the trio runs as repo-tracked quadlet units, deployed with
|
||||
|
||||
## Volumes
|
||||
|
||||
The live unit mounts one root bind — `Volume=/home/dank/Containers/romm:/romm`
|
||||
— so `/romm/config`, `/romm/library`, `/romm/resources`, and `/romm/assets`
|
||||
all resolve inside a single host-side data root:
|
||||
|
||||
| Container path | Host path |
|
||||
|----------------|-----------|
|
||||
| `/romm/library` | `/home/dank/Containers/romm/library` |
|
||||
| `/romm/resources` | `/home/dank/Containers/romm/resources` |
|
||||
| `/romm/config` | `/home/dank/Containers/romm/config` |
|
||||
| `/var/lib/mysql` | `/home/dank/Containers/romm/mariadb` (mapped subuid owner — never chown) |
|
||||
| `/data` (redis) | `/home/dank/Containers/romm/redis` (mapped subuid owner) |
|
||||
|
||||
The library volume contains ROM files and subdirectories per platform. The resources volume stores cached artwork, metadata, and the asset cache. The config volume holds `config.yml` and other configuration.
|
||||
| `/romm/*` (single root bind) | `/home/dank/Containers/romm/*` |
|
||||
| `/var/lib/mysql` (romm-mariadb) | `/home/dank/Containers/romm/mariadb` (mapped subuid owner — never chown) |
|
||||
| `/data` (romm-redis) | `/home/dank/Containers/romm/redis` (mapped subuid owner) |
|
||||
|
||||
The cutover rescued RomM's anonymous `/romm` volume (assets, plus empty
|
||||
mountpoint stubs that shadowed nothing) into the data root before first unit
|
||||
|
||||
@@ -1,8 +1,19 @@
|
||||
---
|
||||
type: reference
|
||||
title: Lidarr
|
||||
description: Lidarr music manager in the *arr stack on FrankBook-Pro — live quadlet deployment, ports, volumes, and wiring facts.
|
||||
tags: [lidarr, arr-stack, frankbook-pro]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# Lidarr
|
||||
|
||||
Lidarr manages music albums in the *arr stack on Dankserver. It automatically searches, downloads, and organizes albums from indexers into the Jellyfin music library.
|
||||
Lidarr manages music albums in the *arr stack. The stack runs on
|
||||
**FrankBook-Pro** (the Mac mini) as quadlet units inside its podman machine —
|
||||
not on Dankserver. It searches, downloads, and organizes albums from indexers
|
||||
into the Jellyfin music library.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `lidarr.dankserver.local` — **Docs:** https://wiki.servarr.com/lidarr
|
||||
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `8686` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/lidarr
|
||||
|
||||
## Facts
|
||||
|
||||
@@ -10,36 +21,41 @@ Lidarr manages music albums in the *arr stack on Dankserver. It automatically se
|
||||
|------|-------|
|
||||
| Image | `lscr.io/linuxserver/lidarr:latest` |
|
||||
| Port | 8686 (host) → 8686 (container) |
|
||||
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
|
||||
| Config root | `/Volumes/COMPLETE/lidarr-data:/config` |
|
||||
| Min RAM | 256 MB |
|
||||
| Metadata | MusicBrainz |
|
||||
|
||||
## Docker Compose
|
||||
## Deployment (current)
|
||||
|
||||
```yaml
|
||||
lidarr:
|
||||
image: lscr.io/linuxserver/lidarr:latest
|
||||
container_name: lidarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/lidarr/config:/config
|
||||
- /mnt/media/music:/music
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "8686:8686"
|
||||
networks: [appnet]
|
||||
Quadlet unit `lidarr.container` from this repo (`frankbook-pro/lidarr/quadlet/`)
|
||||
is installed inside the podman machine at
|
||||
`/home/core/.config/containers/systemd/lidarr.service` by the frankbook-pro
|
||||
handler in `scripts/deploy-remote.sh`. Unit shape:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
ContainerName=lidarr
|
||||
Image=lscr.io/linuxserver/lidarr:latest
|
||||
Environment=PUID=0
|
||||
Environment=PGID=0
|
||||
Environment=TZ=America/Los_Angeles
|
||||
Environment=UMASK_SET=022
|
||||
Volume=/Volumes/COMPLETE/lidarr-data:/config
|
||||
PublishPort=8686:8686
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=900
|
||||
Restart=always
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Add Prowlarr as the indexer source (prefer torrent-based indexers for FLAC).
|
||||
2. Add qBittorrent as the download client with the `music` category.
|
||||
1. Add Prowlarr as the indexer source (prefer torrent-based indexers for FLAC —
|
||||
the Nyaa feed carries music categories; see [[Prowlarr]]).
|
||||
2. Add qBittorrent as the download client with the `music` category ([[qBittorrent]]).
|
||||
3. Set quality profile (Lossless → High Bitrate → Standard).
|
||||
4. Set root folder to `/music`.
|
||||
4. Set the root folder to the music root under the COMPLETE volume.
|
||||
5. Add artists and verify downloads.
|
||||
|
||||
## Gotchas
|
||||
|
||||
@@ -1,47 +1,82 @@
|
||||
---
|
||||
type: reference
|
||||
title: MariaDB (RomM Backend)
|
||||
description: MariaDB 11 database backend for RomM on Dankserver — quadlet unit, network alias, env-file secret handling, and backup path.
|
||||
tags: [mariadb, romm, dankserver]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# MariaDB (RomM Backend)
|
||||
|
||||
MariaDB 11 provides the database backend for RomM on Dankserver. RomM 5.2.0 requires MariaDB (or PostgreSQL) for its data store.
|
||||
MariaDB 11 provides the database backend for [[RomM]] on Dankserver. RomM's
|
||||
current release requires MariaDB (or PostgreSQL) for its data store; this
|
||||
deployment uses MariaDB.
|
||||
|
||||
**Host:** Dankserver — **Docs:** https://mariadb.com/kb/en/docker-mariadb-information/
|
||||
**Host:** Dankserver — container name `romm-mariadb`, unit
|
||||
`romm-mariadb.service` (user-manager quadlet from
|
||||
`dankserver/romm/quadlet/romm-mariadb.container`).
|
||||
|
||||
## Facts
|
||||
## Facts (verified from the live unit)
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `docker.io/mariadb:11` |
|
||||
| Port | 3306 (internal, within `appnet`) |
|
||||
| Database name | `romm` |
|
||||
| Data volume | `/opt/romm/mariadb` |
|
||||
| Image | `docker.io/library/mariadb:11` |
|
||||
| Port | 3306 — internal only; the unit publishes **no** port, so the DB is unreachable from the host network by construction |
|
||||
| Network | `dankserver_appnet` with `alias=mariadb` — RomM reaches it via `DB_HOST=mariadb` |
|
||||
| Database / user | `romm` / `romm` |
|
||||
| Data volume | `/home/dank/Containers/romm/mariadb:/var/lib/mysql` |
|
||||
| Secrets | supplied via `EnvironmentFile=/home/dank/Containers/romm/env` (mode 0600, host-local — `MARIADB_ROOT_PASSWORD` and friends never enter the repo) |
|
||||
|
||||
## Docker Compose
|
||||
## Unit shape (as deployed)
|
||||
|
||||
```yaml
|
||||
mariadb:
|
||||
image: docker.io/mariadb:11
|
||||
container_name: romm-mariadb
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MARIADB_ROOT_PASSWORD: "${MARIADB_ROOT_PASSWORD}"
|
||||
MARIADB_DATABASE: romm
|
||||
MARIADB_USER: "${ROMM_DB_USER}"
|
||||
MARIADB_PASSWORD: "${ROMM_DB_PASSWD}"
|
||||
volumes:
|
||||
- /opt/romm/mariadb:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "mariadb-admin", "ping", "-h", "localhost"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
```ini
|
||||
[Unit]
|
||||
Description=RomM mariadb container
|
||||
After=network.target
|
||||
Wants=romm-redis.service
|
||||
|
||||
[Container]
|
||||
ContainerName=romm-mariadb
|
||||
Image=docker.io/library/mariadb:11
|
||||
Network=dankserver_appnet:alias=mariadb
|
||||
EnvironmentFile=/home/dank/Containers/romm/env
|
||||
Environment=MARIADB_DATABASE=romm
|
||||
Environment=MARIADB_USER=romm
|
||||
Volume=/home/dank/Containers/romm/mariadb:/var/lib/mysql
|
||||
HealthCmd=mariadb-admin ping -h localhost
|
||||
HealthInterval=30s
|
||||
HealthTimeout=10s
|
||||
HealthRetries=3
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
```
|
||||
|
||||
`MARIADB_ROOT_PASSWORD` and `MARIADB_PASSWORD` are read from the env file at
|
||||
container-create time (`EnvironmentFile=` appears in both `[Container]` and
|
||||
`[Service]` so `podman generate systemd`-style regeneration keeps them). The
|
||||
root password is a real secret — per repo secret rules it lives only in the
|
||||
host-local env file, never in git.
|
||||
|
||||
## Boot order
|
||||
|
||||
RomM declares `Wants=romm-mariadb.service` + `After=romm-mariadb.service`, so
|
||||
a cold boot starts the database first; the health ping (`mariadb-admin ping`)
|
||||
is what marks the unit healthy for anything gating on it.
|
||||
|
||||
## Backup
|
||||
|
||||
Back up the volume directory periodically:
|
||||
Back up the volume directory periodically (stop-free: rsync of a quiet DB dir):
|
||||
|
||||
```bash
|
||||
sudo rsync -a /opt/romm/mariadb /mnt/backup/romm-mariadb/
|
||||
sudo rsync -a /home/dank/Containers/romm/mariadb /mnt/backup/romm-mariadb/
|
||||
```
|
||||
|
||||
For consistency-critical dumps prefer `mariadb-dump` over file copy; the data
|
||||
dir copy is only safe while RomM traffic is idle.
|
||||
|
||||
## See Also
|
||||
|
||||
- [[RomM]] — service that uses this database
|
||||
- [[redis]] — the sibling cache/queue container on the same network
|
||||
|
||||
@@ -1,20 +1,55 @@
|
||||
---
|
||||
type: reference
|
||||
title: Prowlarr
|
||||
description: Prowlarr indexer-management layer for the *arr stack on FrankBook-Pro — feed routes, sync model, API surface, and verified live gotchas.
|
||||
tags: [prowlarr, arr-stack, frankbook-pro]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# Prowlarr
|
||||
|
||||
Prowlarr is the indexer management layer for the *arr stack. It hosts the
|
||||
indexer definitions and exposes them as Torznab feeds and downloads;
|
||||
Sonarr, Radarr, Lidarr, and Readarr query those feeds and receive results.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `prowlarr.dankserver.local` — **Docs:** https://wiki.servarr.com/prowlarr
|
||||
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `9696` (no
|
||||
reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis
|
||||
guard chain) — **Docs:** https://wiki.servarr.com/prowlarr
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `lscr.io/linuxserver/prowlarr:latest` |
|
||||
| Image | `lscr.io/linuxserver/prowlarr:latest` (runs v2.5.2 line) |
|
||||
| Port | 9696 (host) → 9696 (container) |
|
||||
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
|
||||
| Config root | `/Volumes/COMPLETE/prowlarr-data:/config` |
|
||||
| Min RAM | 256 MB |
|
||||
| Auth | Forms (web UI) + API key (`/api/v1/...` and feed routes) |
|
||||
|
||||
## Deployment (current)
|
||||
|
||||
Quadlet unit `prowlarr.container` from this repo
|
||||
(`frankbook-pro/prowlarr/quadlet/`), installed inside the podman machine at
|
||||
`/home/core/.config/containers/systemd/prowlarr.service` by the frankbook-pro
|
||||
handler in `scripts/deploy-remote.sh`:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
ContainerName=prowlarr
|
||||
Image=lscr.io/linuxserver/prowlarr:latest
|
||||
Environment=PUID=0
|
||||
Environment=PGID=0
|
||||
Environment=TZ=America/Los_Angeles
|
||||
Environment=UMASK_SET=022
|
||||
Volume=/Volumes/COMPLETE/prowlarr-data:/config
|
||||
PublishPort=9696:9696
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=900
|
||||
Restart=always
|
||||
```
|
||||
|
||||
## Live wiring (verified end-to-end 2026-08-30)
|
||||
|
||||
Indexer queries flow **through** Prowlarr; a grab hands off to the querying
|
||||
@@ -35,35 +70,17 @@ http://prowlarr:9696/{indexerId}/download?link=...&file=... (torrent handoff)
|
||||
The global API key is in `config.xml` (`<ApiKey>`); per-application keys are
|
||||
only used by Prowlarr's own sync calls, NOT by the feeds. The arr download
|
||||
clients authenticate to qBittorrent with the permanent WebUI password stored
|
||||
in `/home/dank/.qbpass` (mode 600) on Dankserver.
|
||||
in `/home/dank/.qbpass` (mode 600, owner `dank`) on Dankserver — see
|
||||
[[qBittorrent]] for why that password must be pinned in the conf file.
|
||||
|
||||
**Readarr caveat:** Readarr is abandoned upstream (last release 0.4.x); its
|
||||
qBittorrent client cannot authenticate against qB 5 (`Authentication
|
||||
failure` on the connection test while Sonarr/Lidarr/Radarr pass with the
|
||||
same credentials). The books pipeline is parked pending a Readarr successor;
|
||||
the indexer row itself is healthy.
|
||||
**Readarr caveat:** Readarr is abandoned upstream; its qBittorrent client
|
||||
cannot authenticate against newer qB Web-API versions (`Authentication
|
||||
failure` on the connection test while Sonarr/Lidarr/Radarr pass with the same
|
||||
credentials — root cause: qB ≥ 5's 204 empty-body login success, fixed fleet-
|
||||
wide by pinning qB to 4.6.7). The books pipeline is parked pending a Readarr
|
||||
successor; the indexer row itself is healthy.
|
||||
|
||||
## Docker Compose
|
||||
|
||||
```yaml
|
||||
prowlarr:
|
||||
image: lscr.io/linuxserver/prowlarr:latest
|
||||
container_name: prowlarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/prowlarr/config:/config
|
||||
- /mnt/media/downloads:/downloads:ro
|
||||
ports:
|
||||
- "9696:9696"
|
||||
networks: [appnet]
|
||||
```
|
||||
|
||||
## Gotchas (all verified live 2026-08-30)
|
||||
## Gotchas (verified live 2026-08-30)
|
||||
|
||||
- **The feed route is `/{indexerId}/api`.** There is no `/torznab/{id}/feed`
|
||||
— that path (and any other unmatched path) hits the Forms-auth catch-all
|
||||
@@ -92,12 +109,13 @@ prowlarr:
|
||||
- Instance name/`InstanceName=Prowlarr` in `config.xml` does NOT prefix the
|
||||
API/feed routes on this build (they answer at root; the `/Prowlarr/...`
|
||||
prefix 302s to the SPA).
|
||||
- **Application auto-sync cannot manage these rows** (they carry
|
||||
`SyncLevel=2`): `POST /api/v1/applications/test` fails with
|
||||
`Unable to cast object of type 'NzbDrone.Core.Thing…'` — Prowlarr v1
|
||||
cannot deserialize Radarr 6.3's newer response types. The manual Torznab
|
||||
rows above are therefore the real integration; sync neither duplicates
|
||||
nor clobbers them.
|
||||
- **Application auto-sync model (v2):** Applications are first-class rows in
|
||||
the `Applications` table; each of the four app rows (sonarr/radarr/lidarr/
|
||||
readarr) carries the real baseUrl+apiKey with `SyncLevel=FullSync`. The
|
||||
earlier v1-era failure where `POST /api/v1/applications/test` threw
|
||||
`Unable to cast object of type 'NzbDrone.Core.Thing…'` (v1 could not
|
||||
deserialize Radarr 6.3's newer response types) is historical — it was the
|
||||
reason the manual Torznab rows were created in the first place.
|
||||
- Prowlarr runs `AuthenticationMethod=Forms` + `AuthenticationRequired=Enabled`
|
||||
healthily — the DryIoc crash combo was `None`+`Enabled` only (see
|
||||
[[radarr]] auth notes).
|
||||
@@ -105,7 +123,4 @@ prowlarr:
|
||||
## See Also
|
||||
|
||||
- [[ARR-Stack]] — full *arr stack documentation
|
||||
- [[radarr]]
|
||||
- [[sonarr]]
|
||||
- [[lidarr]]
|
||||
- [[readarr]]
|
||||
- [[Radarr]] · [[Sonarr]] · [[Lidarr]] · [[Readarr]] · [[qBittorrent]]
|
||||
|
||||
@@ -1,27 +1,44 @@
|
||||
---
|
||||
type: reference
|
||||
title: qBittorrent
|
||||
description: qBittorrent download client for the *arr stack — pinned 4.6.7 on FrankBook-Pro, shares the Gluetun WireGuard netns, PBKDF2 WebUI credential recipe.
|
||||
tags: [qbittorrent, arr-stack, frankbook-pro, gluetun]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# qBittorrent
|
||||
|
||||
qBittorrent is the torrent download client for the *arr stack on Dankserver. It receives download requests from Sonarr, Radarr, Lidarr, and Readarr via category tagging.
|
||||
qBittorrent is the torrent download client for the *arr stack. The stack runs on
|
||||
**FrankBook-Pro** (the Mac mini) as quadlet units inside its podman machine —
|
||||
not on Dankserver. It receives download requests from Sonarr, Radarr, Lidarr,
|
||||
and Readarr via category tagging.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `qbittorrent.dankserver.local` — **Docs:** https://www.qbittorrent.org
|
||||
**Host:** FrankBook-Pro (podman machine) — **Access:** WebUI on port `8080`,
|
||||
published by the [[Gluetun]] unit because qBittorrent shares that container's
|
||||
network namespace (a netns-sharer publishes no ports of its own).
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `lscr.io/linuxserver/qbittorrent:latest` |
|
||||
| Port | 8080 (host) → 8080 (container) |
|
||||
| Min RAM | 512 MB |
|
||||
| Auth | Web UI username/password; LAN mode available |
|
||||
| Image | `lscr.io/linuxserver/qbittorrent:4.6.7` — **pinned**, see the pin rationale below |
|
||||
| Network | `Network=gluetun.container` (torrent egress exits via the WireGuard/ProtonVPN tunnel) |
|
||||
| Ports | 8080 (WebUI) and 6881 TCP+UDP published on the gluetun unit |
|
||||
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
|
||||
| Volumes | `/Volumes/COMPLETE/qbittorrent-data:/config`, plus `/Volumes/COMPLETE` and `/Volumes/INCOMPLETE` mounted at identical paths |
|
||||
| Auth | Web UI username/password (`admin` + generated password); LAN bypass not used |
|
||||
|
||||
## Configuration
|
||||
## Why the 4.6.7 pin exists (2026-09-01)
|
||||
|
||||
1. Keep Web UI authentication ON (LAN bypass not needed — the arr apps
|
||||
authenticate with the API) and give them a permanent password.
|
||||
2. Create download categories per app (`radarr`, `sonarr`, `lidarr`,
|
||||
`readarr`): the arr download clients route category-per-app, and Prowlarr
|
||||
feeds hand grabs to each app's own client.
|
||||
3. Set max active downloads: Settings → Downloads (recommended: 5 global,
|
||||
3 per category).
|
||||
Readarr's abandoned qBittorrent client rejects qB ≥ 5's **204 empty-body login
|
||||
success** as `Authentication failure` — a runtime break, not just an API-create
|
||||
issue. The fleet pins `lscr.io/linuxserver/qbittorrent:4.6.7` while Readarr is
|
||||
in the stack. **Never unpin to `latest` while Readarr is in the fleet.**
|
||||
|
||||
Second trap on any version flip: qB 5.x's shutdown conf rewrite leaves a
|
||||
`WebUI\Password_PBKDF2=@ByteArray(...)` line that 4.6.7 rejects — every login
|
||||
then returns "invalid credentials" (the arrs included). Fix = rewrite the same
|
||||
conf line with the same password while qB is stopped.
|
||||
|
||||
## Persistent WebUI credentials (verified 2026-08-30)
|
||||
|
||||
@@ -46,31 +63,34 @@ val = (base64.b64encode(salt) + b":" + base64.b64encode(h)).decode()
|
||||
|
||||
Then `podman start qbittorrent` and confirm login survives a
|
||||
`podman restart` — the temp-password rotation stops the moment stored
|
||||
credentials verify. The chosen value lives host-local in
|
||||
`/home/dank/.qbpass` (mode 600, owner `dank`) — never in git; every arr
|
||||
download client and `prowlarr.md` reference it. (The classic
|
||||
`@ByteArray(salt+hash)` form is WRONG for qb5: login 401s on it; verify()
|
||||
base64-decodes the two halves separately.)
|
||||
credentials verify. The chosen value lives host-local in `/home/dank/.qbpass`
|
||||
(mode 600, owner `dank`) — never in git; every arr download client and
|
||||
[[Prowlarr]] reference it. (The classic `@ByteArray(salt+hash)` form is WRONG
|
||||
for qb5: login 401s on it; verify() base64-decodes the two halves separately.)
|
||||
|
||||
## Docker Compose
|
||||
## Deployment (current)
|
||||
|
||||
```yaml
|
||||
qbittorrent:
|
||||
image: lscr.io/linuxserver/qbittorrent:latest
|
||||
container_name: qbittorrent
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/qbittorrent/config:/config
|
||||
- /mnt/media/downloads:/downloads
|
||||
- /mnt/media/downloads/incomplete:/downloads/incomplete
|
||||
ports:
|
||||
- "8080:8080"
|
||||
networks: [appnet]
|
||||
Quadlet unit `qbittorrent.container` from this repo
|
||||
(`frankbook-pro/qbittorrent/quadlet/`), installed inside the podman machine at
|
||||
`/home/core/.config/containers/systemd/qbittorrent.service` by the
|
||||
frankbook-pro handler in `scripts/deploy-remote.sh`:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
ContainerName=qbittorrent
|
||||
Image=lscr.io/linuxserver/qbittorrent:4.6.7
|
||||
Network=gluetun.container
|
||||
Environment=PUID=0
|
||||
Environment=PGID=0
|
||||
Environment=TZ=America/Los_Angeles
|
||||
Environment=UMASK_SET=022
|
||||
Volume=/Volumes/COMPLETE/qbittorrent-data:/config
|
||||
Volume=/Volumes/COMPLETE:/Volumes/COMPLETE
|
||||
Volume=/Volumes/INCOMPLETE:/Volumes/INCOMPLETE
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=900
|
||||
Restart=always
|
||||
```
|
||||
|
||||
## Gotchas (verified live)
|
||||
@@ -81,9 +101,17 @@ qbittorrent:
|
||||
download queue" in the arr logs) after any restart.
|
||||
- API login from `curl` needs a `Referer: http://<host>:<port>/` header
|
||||
(CSRF protection) or POSTs get rejected even with a valid SID.
|
||||
- Cookie-name quirk by version: qB 5.x names its WebUI session cookie
|
||||
`QBT_SID_<port>`; 4.6.7 uses plain `SID`. Any automation must parse the
|
||||
cookie generically (e.g. `grep -oE '[A-Za-z_]*SID[A-Za-z0-9_]*=[^;[:space:]]*'`)
|
||||
instead of hard-coding a port-suffixed name, or it fails with 403 cascades
|
||||
that never reach qB as failed logins.
|
||||
- Egress verification for this stack must run **inside the gluetun container**
|
||||
(`podman exec gluetun wget -qO- https://ipinfo.io/json`); running the same
|
||||
probe one ssh-context out returns the residential IP — a false leak alarm.
|
||||
- Ensure umask is set to `022` so downloaded files are readable by arr apps.
|
||||
- Monitor bandwidth limits to avoid saturating the network.
|
||||
|
||||
## See Also
|
||||
|
||||
- [[ARR-Stack]] — full *arr stack documentation
|
||||
- [[Gluetun]] — the WireGuard tunnel this container shares
|
||||
|
||||
@@ -1,52 +1,69 @@
|
||||
---
|
||||
type: reference
|
||||
title: Radarr
|
||||
description: Radarr movie manager in the *arr stack on FrankBook-Pro — live quadlet deployment, ports, volumes, and wiring facts.
|
||||
tags: [radarr, arr-stack, frankbook-pro]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# Radarr
|
||||
|
||||
Radarr manages movies in the *arr stack on Dankserver. It automatically searches, downloads, and organizes movies from indexers into the Jellyfin media library.
|
||||
Radarr manages movies in the *arr stack. The stack runs on **FrankBook-Pro**
|
||||
(the Mac mini) as quadlet units inside its podman machine — not on Dankserver.
|
||||
It searches, downloads, and organizes movies from indexers into the Jellyfin
|
||||
movie library.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `radarr.dankserver.local` — **Docs:** https://wiki.servarr.com/radarr
|
||||
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `7878` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/radarr
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `lscr.io/linuxserver/radarr:latest` (v6 stable) |
|
||||
| Image | `lscr.io/linuxserver/radarr:latest` (v6 line; v6.3.x verified live 2026-08-30) |
|
||||
| Port | 7878 (host) → 7878 (container) |
|
||||
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
|
||||
| Config root | `/Volumes/COMPLETE/radarr-data:/config` |
|
||||
| Min RAM | 512 MB |
|
||||
| Metadata | TMDB / TheMovieDB API |
|
||||
|
||||
## Docker Compose
|
||||
## Deployment (current)
|
||||
|
||||
```yaml
|
||||
radarr:
|
||||
image: lscr.io/linuxserver/radarr:latest
|
||||
container_name: radarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/radarr/config:/config
|
||||
- /mnt/media/movies:/movies
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "7878:7878"
|
||||
networks: [appnet]
|
||||
Quadlet unit `radarr.container` from this repo (`frankbook-pro/radarr/quadlet/`)
|
||||
is installed inside the podman machine at
|
||||
`/home/core/.config/containers/systemd/radarr.service` by the frankbook-pro
|
||||
handler in `scripts/deploy-remote.sh`. Unit shape:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
ContainerName=radarr
|
||||
Image=lscr.io/linuxserver/radarr:latest
|
||||
Environment=PUID=0
|
||||
Environment=PGID=0
|
||||
Environment=TZ=America/Los_Angeles
|
||||
Environment=UMASK_SET=022
|
||||
Volume=/Volumes/COMPLETE/radarr-data:/config
|
||||
PublishPort=7878:7878
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=900
|
||||
Restart=always
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Add Prowlarr as the indexer source.
|
||||
2. Add qBittorrent as the download client with the `movies` category.
|
||||
1. Add Prowlarr as the indexer source (the YTS indexer row feeds Radarr — see [[Prowlarr]]).
|
||||
2. Add qBittorrent as the download client with the `movies` category ([[qBittorrent]]).
|
||||
3. Set quality profile and cutoff quality.
|
||||
4. Set root folder to `/movies`.
|
||||
4. Set the root folder to the movies root under the COMPLETE volume (Radarr
|
||||
imports from where [[qBittorrent]] drops completed downloads; first verified
|
||||
grab+import was a 2160p Dark Knight test on 2026-08-30).
|
||||
5. Add movies and verify downloads.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Radarr v6 is the current stable (v6.3.x as of 2026-08). `:latest` points to the current release.
|
||||
- Movie renaming produces `Title (Year)` format. Jellyfin scanner handles this.
|
||||
- File permissions: qBittorrent downloads as PUID; arr apps must read/move files.
|
||||
- File permissions: qBittorrent downloads as PUID=0; arr apps must read/move files.
|
||||
|
||||
## See Also
|
||||
|
||||
|
||||
@@ -1,55 +1,81 @@
|
||||
---
|
||||
type: reference
|
||||
title: Readarr
|
||||
description: Readarr ebook/audiobook manager in the *arr stack on FrankBook-Pro — retired upstream, pinned image, parked qB download client.
|
||||
tags: [readarr, arr-stack, frankbook-pro]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# Readarr
|
||||
|
||||
> **RETIRED (May 2026).** The Servarr Team retired Readarr: its metadata became unusable and the community migration to Open Library stalled. There is no upstream development. Alternatives: the Bookshelf community fork, or the Calibre content server. See [Readarr (Retired)](https://wiki.servarr.com/readarr).
|
||||
> **RETIRED UPSTREAM (May 2026).** The Servarr Team retired Readarr: its
|
||||
> metadata became unusable and the community migration to Open Library stalled.
|
||||
> There is no upstream development. Alternatives: the Bookshelf community fork,
|
||||
> or the Calibre content server. This instance still runs on a pinned image
|
||||
> tag; see below.
|
||||
|
||||
Readarr manages ebooks and audiobooks in the *arr stack on Dankserver. It automatically searches, downloads, and organizes books into the Calibre library.
|
||||
Readarr manages ebooks and audiobooks in the *arr stack. The stack runs on
|
||||
**FrankBook-Pro** (the Mac mini) as quadlet units inside its podman machine —
|
||||
not on Dankserver. It organizes books into the Calibre library that
|
||||
[[Calibre-Web]] serves.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `readarr.dankserver.local` — **Docs:** https://wiki.servarr.com/readarr
|
||||
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `8787` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/readarr
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `lscr.io/linuxserver/readarr:latest` (v0.2.x development) |
|
||||
| Image | `lscr.io/linuxserver/readarr:amd64-1.0.980` — **pinned tag** (LSIO ships no untagged `latest` for readarr; the tag was pinned after a manifest probe) |
|
||||
| Port | 8787 (host) → 8787 (container) |
|
||||
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
|
||||
| Config root | `/Volumes/COMPLETE/readarr-data:/config` |
|
||||
| Min RAM | 256 MB |
|
||||
| Metadata | Goodreads / StoryGraph |
|
||||
| Metadata | Goodreads / StoryGraph (provider status at retirement) |
|
||||
|
||||
## Docker Compose
|
||||
## Deployment (current)
|
||||
|
||||
```yaml
|
||||
readarr:
|
||||
image: lscr.io/linuxserver/readarr:latest
|
||||
container_name: readarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/readarr/config:/config
|
||||
- /mnt/media/books:/books
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "8787:8787"
|
||||
networks: [appnet]
|
||||
Quadlet unit `readarr.container` from this repo (`frankbook-pro/readarr/quadlet/`)
|
||||
is installed inside the podman machine at
|
||||
`/home/core/.config/containers/systemd/readarr.service` by the frankbook-pro
|
||||
handler in `scripts/deploy-remote.sh`. Unit shape:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
ContainerName=readarr
|
||||
Image=lscr.io/linuxserver/readarr:amd64-1.0.980
|
||||
Environment=PUID=0
|
||||
Environment=PGID=0
|
||||
Environment=TZ=America/Los_Angeles
|
||||
Environment=UMASK_SET=022
|
||||
Volume=/Volumes/COMPLETE/readarr-data:/config
|
||||
PublishPort=8787:8787
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=900
|
||||
Restart=always
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Add Prowlarr as the indexer source (torrent indexers with book content).
|
||||
2. Add qBittorrent as the download client with the `books` category.
|
||||
1. Add Prowlarr as the indexer source (torrent indexers with book content;
|
||||
the Byrutor row feeds Readarr — see [[Prowlarr]]).
|
||||
2. The qBittorrent download client is **parked**: Readarr's abandoned client
|
||||
fails auth against newer qB Web-API versions (see [[qBittorrent]] for the
|
||||
4.6.7 pin rationale); re-enable only after the image changes. Until then,
|
||||
books are imported manually or via Calibre tooling.
|
||||
3. Set author profile (format preference: epub, mobi, etc.).
|
||||
4. Set quality profile for audiobooks (320 kbps MP3, 128 kbps, lossless).
|
||||
5. Set root folder to `/books`.
|
||||
6. Add authors and verify downloads.
|
||||
5. Set the root folder to the books root under the COMPLETE volume.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Readarr is in development (~v0.2.x). Some features may be incomplete.
|
||||
- Calibre integration is folder-based, not API-based. Readarr drops files into `/books` which Calibre-Web serves.
|
||||
- Not all indexers have all formats (epub, mobi, pdf). Goodreads/StoryGraph metadata helps match editions.
|
||||
- Readarr is abandoned upstream (retired May 2026; last line was 0.4.x before
|
||||
the final tags). The pinned `amd64-1.0.980` tag exists precisely because
|
||||
`:latest` does not exist for this image on LSIO.
|
||||
- Calibre integration is folder-based, not API-based. Readarr drops files into
|
||||
the books root which [[Calibre-Web]] serves.
|
||||
- Not all indexers carry all formats (epub, mobi, pdf). Goodreads/StoryGraph
|
||||
metadata helps match editions while those providers still respond.
|
||||
|
||||
## See Also
|
||||
|
||||
|
||||
@@ -1,40 +1,67 @@
|
||||
---
|
||||
type: reference
|
||||
title: Redis (RomM Cache / Queue)
|
||||
description: Redis 7-alpine cache and task-queue backend for RomM on Dankserver — quadlet unit, network alias topology, and backup path.
|
||||
tags: [redis, romm, dankserver]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# Redis (RomM Cache / Queue)
|
||||
|
||||
Redis 7 provides the caching and task queue backend for RomM on Dankserver. RomM 5.2.0 requires Redis (or Valkey) for its task queue.
|
||||
Redis 7 provides the caching and task-queue backend for [[RomM]] on Dankserver.
|
||||
RomM requires Redis (or Valkey) for its task queue; this deployment runs
|
||||
stock `redis:7-alpine` — no Valkey here, unlike the SearXNG cache on
|
||||
Dankclaw ([[Valkey]]).
|
||||
|
||||
**Host:** Dankserver — **Docs:** https://redis.io/docs/
|
||||
**Host:** Dankserver — container name `romm-redis`, unit `romm-redis.service`
|
||||
(user-manager quadlet from `dankserver/romm/quadlet/romm-redis.container`).
|
||||
|
||||
## Facts
|
||||
## Facts (verified from the live unit)
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `docker.io/redis:7-alpine` |
|
||||
| Port | 6379 (internal, within `appnet`) |
|
||||
| Data volume | `/opt/romm/redis` |
|
||||
| Auth | None (local-only, no password needed) |
|
||||
| Image | `docker.io/library/redis:7-alpine` |
|
||||
| Port | 6379 — internal only; no `PublishPort`, so it is unreachable from the host network by construction |
|
||||
| Network | `dankserver_appnet` with `alias=redis` — that alias is what makes `REDIS_HOST=redis` in the RomM unit resolve |
|
||||
| Data volume | `/home/dank/Containers/romm/redis:/data` |
|
||||
| Auth | None — safe precisely because the container is not published anywhere; only appnet members can reach it |
|
||||
|
||||
## Docker Compose
|
||||
## Unit shape (as deployed)
|
||||
|
||||
```yaml
|
||||
redis:
|
||||
image: docker.io/redis:7-alpine
|
||||
container_name: romm-redis
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- /opt/romm/redis:/data
|
||||
healthcheck:
|
||||
test: ["CMD", "redis-cli", "ping"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
```ini
|
||||
[Container]
|
||||
ContainerName=romm-redis
|
||||
Image=docker.io/library/redis:7-alpine
|
||||
Network=dankserver_appnet:alias=redis
|
||||
Volume=/home/dank/Containers/romm/redis:/data
|
||||
HealthCmd=redis-cli ping
|
||||
HealthInterval=10s
|
||||
HealthTimeout=5s
|
||||
HealthRetries=3
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
```
|
||||
|
||||
No `EnvironmentFile` — there is nothing secret in this unit; the auth-less
|
||||
posture is enforced by network topology (alias-only reachability), not by a
|
||||
password. If a future client ever needs Redis from outside the appnet, add
|
||||
`PublishPort` **and** a `requirepass` in the same change — never just the port.
|
||||
|
||||
## Backup
|
||||
|
||||
```bash
|
||||
sudo rsync -a /opt/romm/redis /mnt/backup/romm-redis/
|
||||
sudo rsync -a /home/dank/Containers/romm/redis /mnt/backup/romm-redis/
|
||||
```
|
||||
|
||||
Redis here is cache + queue state; losing it costs queued jobs and cache warm,
|
||||
not the library (the database lives in [[MariaDB]]).
|
||||
|
||||
## See Also
|
||||
|
||||
- [[RomM]] — service that uses this cache
|
||||
- [[Valkey]] — the SearXNG-side equivalent on Dankclaw
|
||||
|
||||
@@ -1,53 +1,70 @@
|
||||
---
|
||||
type: reference
|
||||
title: Sonarr
|
||||
description: Sonarr TV manager in the *arr stack on FrankBook-Pro — live quadlet deployment, ports, volumes, and wiring facts.
|
||||
tags: [sonarr, arr-stack, frankbook-pro]
|
||||
timestamp: 2026-09-03T00:00:00Z
|
||||
---
|
||||
|
||||
# Sonarr
|
||||
|
||||
Sonarr manages TV shows in the *arr stack on Dankserver. It automatically searches, downloads, and organizes episodes from indexers into the Jellyfin media library.
|
||||
Sonarr manages TV shows in the *arr stack. The stack runs on **FrankBook-Pro**
|
||||
(the Mac mini) as quadlet units inside its podman machine — not on Dankserver.
|
||||
It searches, downloads, and organizes episodes from indexers into the Jellyfin
|
||||
TV library.
|
||||
|
||||
**Host:** Dankserver — **Hostname:** `sonarr.dankserver.local` — **Docs:** https://wiki.servarr.com/sonarr
|
||||
**Host:** FrankBook-Pro (podman machine) — **Access:** direct port `8989` (no reverse-proxy vhost; the *arr stack is exempt by construction from the Anubis guard chain) — **Docs:** https://wiki.servarr.com/sonarr
|
||||
|
||||
## Facts
|
||||
|
||||
| Item | Value |
|
||||
|------|-------|
|
||||
| Image | `lscr.io/linuxserver/sonarr:latest` (v4 stable) |
|
||||
| Image | `lscr.io/linuxserver/sonarr:latest` (v4 line) |
|
||||
| Port | 8989 (host) → 8989 (container) |
|
||||
| Env | `PUID=0`, `PGID=0`, `TZ=America/Los_Angeles`, `UMASK_SET=022` |
|
||||
| Config root | `/Volumes/COMPLETE/sonarr-data:/config` |
|
||||
| Min RAM | 512 MB |
|
||||
| Metadata | TMDB / TVDB |
|
||||
|
||||
## Docker Compose
|
||||
## Deployment (current)
|
||||
|
||||
```yaml
|
||||
sonarr:
|
||||
image: lscr.io/linuxserver/sonarr:latest
|
||||
container_name: sonarr
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
- PUID=1000
|
||||
- PGID=1000
|
||||
- TZ=America/New_York
|
||||
- UMASK_SET=022
|
||||
volumes:
|
||||
- /opt/sonarr/config:/config
|
||||
- /mnt/media/tv:/tv
|
||||
- /mnt/media/downloads:/downloads
|
||||
ports:
|
||||
- "8989:8989"
|
||||
networks: [appnet]
|
||||
Quadlet unit `sonarr.container` from this repo (`frankbook-pro/sonarr/quadlet/`)
|
||||
is installed inside the podman machine at
|
||||
`/home/core/.config/containers/systemd/sonarr.service` by the frankbook-pro
|
||||
handler in `scripts/deploy-remote.sh`. Unit shape:
|
||||
|
||||
```ini
|
||||
[Container]
|
||||
ContainerName=sonarr
|
||||
Image=lscr.io/linuxserver/sonarr:latest
|
||||
Environment=PUID=0
|
||||
Environment=PGID=0
|
||||
Environment=TZ=America/Los_Angeles
|
||||
Environment=UMASK_SET=022
|
||||
Volume=/Volumes/COMPLETE/sonarr-data:/config
|
||||
PublishPort=8989:8989
|
||||
|
||||
[Service]
|
||||
TimeoutStartSec=900
|
||||
Restart=always
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Add Prowlarr as the indexer source.
|
||||
2. Add qBittorrent as the download client with the `tv` category.
|
||||
1. Add Prowlarr as the indexer source (see [[Prowlarr]] — the feed route is `/{indexerId}/api`).
|
||||
2. Add qBittorrent as the download client with the `tv` category ([[qBittorrent]]).
|
||||
3. Set quality profile, cutoff, and minimum/maximum episode sizes.
|
||||
4. Set root folder to `/tv`.
|
||||
5. Add series and verify downloads.
|
||||
4. Set the root folder to the TV root under the COMPLETE volume (Sonarr imports
|
||||
from where [[qBittorrent]] drops completed downloads).
|
||||
5. Add a test series and verify the grab → download → import chain end-to-end.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- Sonarr v4 is the current stable. The v3 branch uses the `:v3` tag.
|
||||
- Anime has different quality profiles and naming conventions than Standard series.
|
||||
- Missing episodes: set "Unmonitor Missing Episodes" to auto-unmonitor old episodes.
|
||||
- Timezone-sensitive scheduler: ensure all containers use the same TZ.
|
||||
- Timezone-sensitive scheduler: every unit in the stack runs
|
||||
`TZ=America/Los_Angeles`; keep them uniform.
|
||||
|
||||
## See Also
|
||||
|
||||
|
||||
Reference in New Issue
Block a user