media stack: shared /data/media layout, promote sonarr/radarr/jellyfin/jellyseerr

- Promote sonarr, radarr, jellyfin, jellyseerr from _dev
- qBittorrent, Sonarr, Radarr, Lidarr, Readarr, Whisparr mount /data/media
  at /media so paths match across containers (no remote path mappings,
  hardlinks work); downloads go to /media/downloads/prowlarr
- Jellyfin: drop photos (use Immich) and unused internal network, rewrite README
- Jellyseerr: add TZ, document container hostnames and root folders

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
code
2026-11-02 17:43:22 +00:00
co-authored by Claude Opus 5.5
parent f41ca56096
commit 7ed139d134
25 changed files with 193 additions and 124 deletions
+101
View File
@@ -0,0 +1,101 @@
# Jellyfin
## Overview
Jellyfin is a free, open-source media server. It organizes your movies, shows, music and books and streams them to web, mobile and TV clients. In this setup Sonarr and Radarr fill the library; Jellyfin just reads it.
## Project Details
- **Project Repository:** [https://jellyfin.org/](https://jellyfin.org/) ([Docs](https://jellyfin.org/docs/))
- **Container Image:** [jellyfin/jellyfin](https://hub.docker.com/r/jellyfin/jellyfin)
- **Reverse Proxy Port:** `8096`
## Getting Started
Open http://localhost:8096 in your browser and complete the setup wizard:
1. **Create your admin account**
2. **Add media libraries** — point each one at the matching container folder:
| Library type | Folder |
|---|---|
| Movies | `/movies` |
| Shows | `/shows` |
| Music | `/music` |
| Books | `/books` |
3. Finish the wizard. Jellyfin scans the folders and pulls metadata.
For Jellyseerr, create an API key under **Dashboard → API Keys**.
## Environment Variable Notes
| Variable | Description |
|---|---|
| `JELLYFIN_IMAGE` | Container image (default: `jellyfin/jellyfin:latest`) |
| `JELLYFIN_RESTART` | Restart policy (default: `unless-stopped`) |
| `JELLYFIN_PORT` | Published port for the web UI (default: `8096`) |
| `JELLYFIN_URL` | Public URL clients use to reach the server (default: `http://localhost:8096`) — set this to your reverse proxy URL |
| `JELLYFIN_MEDIA` | Shared media root on the host (default: `/data/media`) — the same folder qBittorrent, Sonarr, Radarr and Bazarr use |
| `VOL_PATH` | Base path for persistent data volumes (default: `/data`) |
## Volume Notes
| Volume | Purpose |
|---|---|
| `${VOL_PATH:-/data}/jellyfin/config` | Configuration, database and metadata |
| `${VOL_PATH:-/data}/jellyfin/cache` | Transcode and image cache |
| `${JELLYFIN_MEDIA:-/data/media}/movies` → `/movies` | Movies (Radarr root folder `/media/movies`) |
| `${JELLYFIN_MEDIA:-/data/media}/shows` → `/shows` | TV shows (Sonarr root folder `/media/shows`) |
| `${JELLYFIN_MEDIA:-/data/media}/music` → `/music` | Music |
| `${JELLYFIN_MEDIA:-/data/media}/books` → `/books` | Books |
Jellyfin mounts only the library subfolders, not `/data/media/downloads`, so half-finished downloads never show up in the library.
## Network Notes
Requires an external `proxy` network. Create it once with:
```bash
docker network create proxy
```
Jellyseerr reaches Jellyfin at `http://jellyfin:8096` over the `proxy` network.
## Docker Run
```bash
docker run -d \
--name=jellyfin \
-e JELLYFIN_PublishedServerUrl=http://localhost:8096 \
-p 8096:8096 \
-v ${VOL_PATH:-/data}/jellyfin/cache:/cache \
-v ${VOL_PATH:-/data}/jellyfin/config:/config \
-v ${JELLYFIN_MEDIA:-/data/media}/books:/books \
-v ${JELLYFIN_MEDIA:-/data/media}/movies:/movies \
-v ${JELLYFIN_MEDIA:-/data/media}/music:/music \
-v ${JELLYFIN_MEDIA:-/data/media}/shows:/shows \
--network proxy \
--restart unless-stopped \
jellyfin/jellyfin:latest
```
## Additional Notes / Gotchas
- **Create the library folders first.** If `/data/media/movies` etc. don't exist, Docker creates them owned by root and Sonarr/Radarr (PUID 1000) can't write to them:
```bash
mkdir -p /data/media/{downloads/prowlarr,movies,shows,music,books}
chown -R 1000:1000 /data/media
```
- **Only port 8096 is published.** HTTPS (8920) is handled by Nginx Proxy Manager. Local network auto-discovery (UDP 1900/7359) won't work through the bridge network, so add the server to clients by URL.
- **Photos** are left out on purpose — use the Immich stack for photo libraries.
- **Hardware transcoding** needs the GPU passed into the container (e.g. `devices: [/dev/dri:/dev/dri]` for Intel/AMD). It's not included by default.
## Dockhand Stack, Deploy from Git
- **Cookbooks Repository**
- **stackname:** jellyfin
- **Compose file path:** jellyfin/compose.yaml
- **Additional env file (optional):** jellyfin/sample.env
Load `jellyfin/sample.env` into the Environment variables in Dockhand, then create the Stack.
@@ -8,7 +8,6 @@ services:
- ${JELLYFIN_MEDIA:-/data/media}/books:/books - ${JELLYFIN_MEDIA:-/data/media}/books:/books
- ${JELLYFIN_MEDIA:-/data/media}/movies:/movies - ${JELLYFIN_MEDIA:-/data/media}/movies:/movies
- ${JELLYFIN_MEDIA:-/data/media}/music:/music - ${JELLYFIN_MEDIA:-/data/media}/music:/music
- ${JELLYFIN_MEDIA:-/data/media}/photos:/photos
- ${JELLYFIN_MEDIA:-/data/media}/shows:/shows - ${JELLYFIN_MEDIA:-/data/media}/shows:/shows
environment: environment:
- JELLYFIN_PublishedServerUrl=${JELLYFIN_URL:-http://localhost:8096} - JELLYFIN_PublishedServerUrl=${JELLYFIN_URL:-http://localhost:8096}
@@ -16,9 +15,7 @@ services:
- "${JELLYFIN_PORT:-8096}:8096" - "${JELLYFIN_PORT:-8096}:8096"
networks: networks:
- proxy - proxy
- internal
networks: networks:
proxy: proxy:
external: true external: true
internal:
-75
View File
@@ -1,75 +0,0 @@
# Jellyfin
## Overview
* [DockerHub jellyfin](https://hub.docker.com/r/jellyfin/jellyfin)
* [Docs](https://jellyfin.org/docs/)
### Ports
* 8096/tcp is used by default for HTTP traffic. You can change this in the dashboard.
* 8920/tcp is used by default for HTTPS traffic. You can change this in the dashboard.
* 1900/udp is used for service auto-discovery. This is not configurable.
* 7359/udp is also used for auto-discovery. This is not configurable.
## Project Details
- **Container Image:** [jellyfin/jellyfin:latest](https://hub.docker.com/r/jellyfin/jellyfin)
- **Reverse Proxy Port:** `8096`
## Getting Started
1. Start the container: `docker compose up -d`
2. Open http://localhost:8096 in your browser
3. Follow the initial setup wizard to configure the application
## Environment Variable Notes
JELLYFIN_URL – default: http://localhost:8096
JELLYFIN_PORT – default: 8096
JELLYFIN_MEDIA – default: /data/media – shared media library, same one used by Radarr, Bazarr, etc.
## Volume Notes
/cache – host path /data/jellyfin/cache
/config – host path /data/jellyfin/config
/books – host path ${JELLYFIN_MEDIA:-/data/media}/books
/movies – host path ${JELLYFIN_MEDIA:-/data/media}/movies
/music – host path ${JELLYFIN_MEDIA:-/data/media}/music
/photos – host path ${JELLYFIN_MEDIA:-/data/media}/photos
/shows – host path ${JELLYFIN_MEDIA:-/data/media}/shows
## Network Notes
Requires proxy network
## Docker Run
```bash
docker run -d \
--name jellyfin \
-p 8096:8096 \
-v /data/jellyfin/cache:/cache \
-v /data/jellyfin/config:/config \
-v /data/media/books:/books \
-v /data/media/movies:/movies \
-v /data/media/music:/music \
jellyfin/jellyfin:latest
```
See compose.yaml for the full set of environment variables.
## Additional Notes / Gotchas
Nothing specific to this stack so far.
## Dockhand Stack, Deploy from Git
Cookbooks Repository
stackname: jellyfin_dev
Compose file path: jellyfin_dev/compose.yaml
Additional env file (optional): jellyfin_dev/sample.env
Then "Load" jellyfin_dev/sample.env into the Environmental variables in dockhand
Create the Stack
@@ -15,8 +15,17 @@ Jellyseerr is a free and open-source request management system for your Jellyfin
Open http://localhost:5055 in your browser and complete the initial setup: Open http://localhost:5055 in your browser and complete the initial setup:
1. **Create your admin account** 1. **Create your admin account**
2. **Connect your media server** — select Jellyfin or Emby, enter server URL and API key 2. **Connect Jellyfin** — sign in with your Jellyfin admin account. Server URL: `http://jellyfin:8096` (container name on the `proxy` network). Then pick which libraries to sync (Movies, Shows)
3. **Connect Sonarr and Radarr** — Jellyseerr needs these to handle requests 3. **Connect Radarr and Sonarr** — get each API key from **Settings → General** in the app:
| | Radarr | Sonarr |
|---|---|---|
| Hostname | `radarr` | `sonarr` |
| Port | `7878` | `8989` |
| Root Folder | `/media/movies` | `/media/shows` |
| Quality Profile | pick one | pick one |
Tick **Default Server** on each, click **Test**, then **Save**
4. Users can now browse your library and submit requests via the Jellyseerr UI 4. Users can now browse your library and submit requests via the Jellyseerr UI
### Request flow ### Request flow
@@ -30,6 +39,7 @@ User submits a request → approved (auto or manual) → Jellyseerr sends it to
| `JELLYSEERR_IMAGE` | Container image (default: `ghcr.io/hotio/jellyseerr:release`) | | `JELLYSEERR_IMAGE` | Container image (default: `ghcr.io/hotio/jellyseerr:release`) |
| `JELLYSEERR_RESTART` | Restart policy (default: `unless-stopped`) | | `JELLYSEERR_RESTART` | Restart policy (default: `unless-stopped`) |
| `JELLYSEERR_PORT` | Published port for the web UI (default: `5055`) | | `JELLYSEERR_PORT` | Published port for the web UI (default: `5055`) |
| `TZ` | Container timezone (default: `America/Vancouver`) |
| `VOL_PATH` | Base path for persistent data volumes (default: `/data`) | | `VOL_PATH` | Base path for persistent data volumes (default: `/data`) |
## Volume Notes ## Volume Notes
@@ -54,6 +64,7 @@ docker run -d \
-e PUID=1000 \ -e PUID=1000 \
-e PGID=1000 \ -e PGID=1000 \
-e UMASK=002 \ -e UMASK=002 \
-e TZ=America/Vancouver \
-p 5055:5055 \ -p 5055:5055 \
-v ${VOL_PATH:-/data}/jellyseerr/config:/config \ -v ${VOL_PATH:-/data}/jellyseerr/config:/config \
--network proxy \ --network proxy \
@@ -63,13 +74,15 @@ docker run -d \
## Additional Notes / Gotchas ## Additional Notes / Gotchas
Nothing specific to this stack so far. - Jellyseerr doesn't mount any media. It only talks to Jellyfin, Sonarr and Radarr over their APIs, so it needs just `/config`.
- The root folders entered here are paths *inside the Sonarr/Radarr containers* (`/media/shows`, `/media/movies`), not host paths.
- Use container names (`jellyfin`, `sonarr`, `radarr`), not `localhost`. Inside the container, `localhost` is Jellyseerr itself.
## Dockhand Stack, Deploy from Git ## Dockhand Stack, Deploy from Git
- **Cookbooks Repository** - **Cookbooks Repository**
- **stackname:** jellyseerr_dev - **stackname:** jellyseerr
- **Compose file path:** jellyseerr_dev/compose.yaml - **Compose file path:** jellyseerr/compose.yaml
- **Additional env file (optional):** jellyseerr_dev/sample.env - **Additional env file (optional):** jellyseerr/sample.env
Load `jellyseerr_dev/sample.env` into the Environment variables in Dockhand, then create the Stack. Load `jellyseerr/sample.env` into the Environment variables in Dockhand, then create the Stack.
@@ -8,6 +8,7 @@ services:
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
- UMASK=002 - UMASK=002
- TZ=${TZ:-America/Vancouver}
ports: ports:
- "${JELLYSEERR_PORT:-5055}:5055" - "${JELLYSEERR_PORT:-5055}:5055"
networks: networks:
@@ -1,5 +1,6 @@
# Jellyseerr # Jellyseerr
VOL_PATH=/data VOL_PATH=/data
TZ=America/Vancouver
JELLYSEERR_IMAGE=ghcr.io/hotio/jellyseerr:release JELLYSEERR_IMAGE=ghcr.io/hotio/jellyseerr:release
JELLYSEERR_PORT=5055 JELLYSEERR_PORT=5055
JELLYSEERR_RESTART=unless-stopped JELLYSEERR_RESTART=unless-stopped
+8 -5
View File
@@ -20,13 +20,13 @@ Open http://localhost:8686 in your browser and complete the initial setup wizard
Once the wizard finishes, Lidarr displays **"No artists found"**. To populate your library: Once the wizard finishes, Lidarr displays **"No artists found"**. To populate your library:
- Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/music`) — this is where your organized music library will live - Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/media/music`) — this is where your organized music library will live
- Click **Add an artist** and search by name — Lidarr fetches metadata, discography, and album art - Click **Add an artist** and search by name — Lidarr fetches metadata, discography, and album art
- Lidarr cross-references your Root Folder for any existing files and matches them to the artist's catalog - Lidarr cross-references your Root Folder for any existing files and matches them to the artist's catalog
### Download flow ### Download flow
qBittorrent downloads to its own directory → Lidarr picks it up, renames/tags the files, and moves them into `<Root Folder>/Artist Name/Album/` qBittorrent downloads to `/media/downloads/prowlarr` → Lidarr picks it up, renames/tags the files, and moves them into `<Root Folder>/Artist Name/Album/`
### Spotify playlist import ### Spotify playlist import
@@ -40,6 +40,7 @@ Lidarr doesn't natively import Spotify playlists. Use a community tool like [Spo
| `LIDARR_RESTART` | Restart policy (default: `unless-stopped`) | | `LIDARR_RESTART` | Restart policy (default: `unless-stopped`) |
| `LIDARR_PORT` | Published port for the web UI (default: `8686`) | | `LIDARR_PORT` | Published port for the web UI (default: `8686`) |
| `VOL_PATH` | Base path for persistent data volumes (default: `/data`) | | `VOL_PATH` | Base path for persistent data volumes (default: `/data`) |
| `LIDARR_MEDIA` | Shared media root on the host (default: `/data/media`), mounted at `/media`. Must be the same folder qBittorrent, Sonarr, Radarr and Jellyfin use |
| `TZ` | Container timezone (default: `America/Vancouver`) | | `TZ` | Container timezone (default: `America/Vancouver`) |
## Volume Notes ## Volume Notes
@@ -47,7 +48,7 @@ Lidarr doesn't natively import Spotify playlists. Use a community tool like [Spo
| Volume | Purpose | | Volume | Purpose |
|---|---| |---|---|
| `${VOL_PATH:-/data}/lidarr/config` | Application configuration and database | | `${VOL_PATH:-/data}/lidarr/config` | Application configuration and database |
| `${VOL_PATH:-/data}/lidarr/data` | Download client data and working directory | | `${LIDARR_MEDIA:-/data/media}` → `/media` | Shared media root: downloads in `/media/downloads`, library in `/media/music` |
## Network Notes ## Network Notes
@@ -68,7 +69,7 @@ docker run -d \
-e TZ=America/Vancouver \ -e TZ=America/Vancouver \
-p 8686:8686 \ -p 8686:8686 \
-v ${VOL_PATH:-/data}/lidarr/config:/config \ -v ${VOL_PATH:-/data}/lidarr/config:/config \
-v ${VOL_PATH:-/data}/lidarr/data:/data \ -v ${LIDARR_MEDIA:-/data/media}:/media \
--network proxy \ --network proxy \
--restart unless-stopped \ --restart unless-stopped \
ghcr.io/hotio/lidarr:release ghcr.io/hotio/lidarr:release
@@ -76,7 +77,9 @@ docker run -d \
## Additional Notes / Gotchas ## Additional Notes / Gotchas
Nothing specific to this stack so far. - **One shared media folder.** qBittorrent, Sonarr, Radarr, Lidarr and Jellyfin all use `/data/media` on the host, mounted at `/media`, so a download has the same path in every container: no Remote Path Mapping needed, and imports can use hardlinks. Enable **Settings → Media Management → Use Hardlinks instead of Copy**.
- **Layout:** `/data/media/downloads/prowlarr` (qBittorrent category `prowlarr`), `/data/media/music` (Lidarr root, Jellyfin's `/music` library).
- In the qBittorrent download client settings, set **Category** to `prowlarr`.
## Dockhand Stack, Deploy from Git ## Dockhand Stack, Deploy from Git
+1 -1
View File
@@ -4,7 +4,7 @@ services:
restart: ${LIDARR_RESTART:-unless-stopped} restart: ${LIDARR_RESTART:-unless-stopped}
volumes: volumes:
- ${VOL_PATH:-/data}/lidarr/config:/config - ${VOL_PATH:-/data}/lidarr/config:/config
- ${VOL_PATH:-/data}/lidarr/data:/data - ${LIDARR_MEDIA:-/data/media}:/media
environment: environment:
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
+1
View File
@@ -4,3 +4,4 @@ LIDARR_IMAGE=ghcr.io/hotio/lidarr:release
TZ=America/Vancouver TZ=America/Vancouver
LIDARR_PORT=8686 LIDARR_PORT=8686
LIDARR_RESTART=unless-stopped LIDARR_RESTART=unless-stopped
LIDARR_MEDIA=/data/media
+14 -2
View File
@@ -25,11 +25,12 @@ BitTorrent client with a full-featured web UI.
QBT_PASS – default: ChangeThisPassword QBT_PASS – default: ChangeThisPassword
QBT_PORT – default: 8080 QBT_PORT – default: 8080
QBT_MEDIA – default: /data/media (shared media root, also mounted by Sonarr, Radarr and Jellyfin)
## Volume Notes ## Volume Notes
/config – host path /data/qbit/config /config – host path /data/qbit/config
/downloads – host path /data/qbit/downloads /media – host path /data/media (downloads go to /media/downloads)
/incomplete – host path /data/qbit/incomplete /incomplete – host path /data/qbit/incomplete
/dev/net/tun – host path /dev/net/tun /dev/net/tun – host path /dev/net/tun
@@ -44,7 +45,7 @@ docker run -d \
--name qbittorrent \ --name qbittorrent \
-p 8080:8080 \ -p 8080:8080 \
-v /data/qbit/config:/config \ -v /data/qbit/config:/config \
-v /data/qbit/downloads:/downloads \ -v /data/media:/media \
-v /data/qbit/incomplete:/incomplete \ -v /data/qbit/incomplete:/incomplete \
-v /dev/net/tun:/dev/net/tun \ -v /dev/net/tun:/dev/net/tun \
trigus42/qbittorrentvpn:latest trigus42/qbittorrentvpn:latest
@@ -56,6 +57,17 @@ See compose.yaml for the full set of environment variables.
Check the container logs on first start for the temporary web UI password. Check the container logs on first start for the temporary web UI password.
### Shared media folder (for Sonarr / Radarr / Jellyfin)
`/data/media` on the host is mounted at `/media` in qBittorrent, Sonarr and Radarr, so a file has the same path in every container. Imports then work without Remote Path Mappings, and can use hardlinks instead of copying.
In qBittorrent, set:
- **Options → Downloads → Default Save Path:** `/media/downloads`
- **Category `prowlarr`** (right-click Categories → Add): save path `/media/downloads/prowlarr`
Then in Sonarr/Radarr set the qBittorrent download client's **Category** to `prowlarr`.
## Dockhand Stack, Deploy from Git ## Dockhand Stack, Deploy from Git
Cookbooks Repository Cookbooks Repository
+1 -1
View File
@@ -4,7 +4,7 @@ services:
restart: ${QBT_RESTART:-unless-stopped} restart: ${QBT_RESTART:-unless-stopped}
volumes: volumes:
- ${VOL_PATH:-/data}/qbit/config:/config - ${VOL_PATH:-/data}/qbit/config:/config
- ${VOL_PATH:-/data}/qbit/downloads:/downloads - ${QBT_MEDIA:-/data/media}:/media
- ${VOL_PATH:-/data}/qbit/incomplete:/incomplete - ${VOL_PATH:-/data}/qbit/incomplete:/incomplete
- ${VOL_PATH:-/data}/qbit/watched:/watched - ${VOL_PATH:-/data}/qbit/watched:/watched
- /dev/net/tun:/dev/net/tun - /dev/net/tun:/dev/net/tun
+1
View File
@@ -4,3 +4,4 @@ QBT_IMAGE=trigus42/qbittorrentvpn:latest
QBT_RESTART=unless-stopped QBT_RESTART=unless-stopped
QBT_PORT=8080 QBT_PORT=8080
QBT_PASS=ChangeThisPassword QBT_PASS=ChangeThisPassword
QBT_MEDIA=/data/media
+10 -8
View File
@@ -26,7 +26,7 @@ Once the wizard finishes, you'll see an empty library. To populate it:
### Download flow ### Download flow
qBittorrent downloads to its own directory → Radarr picks it up, renames the file, and moves it into `<Root Folder>/Movie Name (Year)/` qBittorrent downloads to `/media/downloads/prowlarr` → Radarr picks it up, renames the file, and moves it into `<Root Folder>/Movie Name (Year)/`
## Environment Variable Notes ## Environment Variable Notes
@@ -36,7 +36,7 @@ qBittorrent downloads to its own directory → Radarr picks it up, renames the f
| `RADARR_RESTART` | Restart policy (default: `unless-stopped`) | | `RADARR_RESTART` | Restart policy (default: `unless-stopped`) |
| `RADARR_PORT` | Published port for the web UI (default: `7878`) | | `RADARR_PORT` | Published port for the web UI (default: `7878`) |
| `VOL_PATH` | Base path for persistent data volumes (default: `/data`) | | `VOL_PATH` | Base path for persistent data volumes (default: `/data`) |
| `RADARR_MEDIA` | Path to the shared media library (default: `/data/media`) — point this at the same library used by Sonarr, Bazarr, and Jellyfin/etc. so downloads land in the shared library | | `RADARR_MEDIA` | Shared media root on the host (default: `/data/media`), mounted at `/media`. Must be the same folder qBittorrent, Sonarr and Jellyfin use |
| `TZ` | Container timezone (default: `America/Vancouver`) | | `TZ` | Container timezone (default: `America/Vancouver`) |
## Volume Notes ## Volume Notes
@@ -44,7 +44,7 @@ qBittorrent downloads to its own directory → Radarr picks it up, renames the f
| Volume | Purpose | | Volume | Purpose |
|---|---| |---|---|
| `${VOL_PATH:-/data}/radarr/config` | Application configuration and database | | `${VOL_PATH:-/data}/radarr/config` | Application configuration and database |
| `${RADARR_MEDIA:-/data/media}` | Shared media library, kept separate from `VOL_PATH` since it's typically the same library mounted into Sonarr, Bazarr, and Jellyfin/etc. | | `${RADARR_MEDIA:-/data/media}` → `/media` | Shared media library, kept separate from `VOL_PATH` since it's typically mounted into Sonarr, Radarr, Bazarr, and Jellyfin/etc. |
## Network Notes ## Network Notes
@@ -73,13 +73,15 @@ docker run -d \
## Additional Notes / Gotchas ## Additional Notes / Gotchas
Nothing specific to this stack so far. - **One shared media folder.** qBittorrent, Sonarr, Radarr and Jellyfin all use `/data/media` on the host. qBittorrent, Sonarr and Radarr mount it at `/media`, so a download has the same path in every container: no Remote Path Mapping needed, and imports can use hardlinks (instant, no extra disk space). Enable **Settings → Media Management → Use Hardlinks instead of Copy**.
- **Layout:** `/data/media/downloads/prowlarr` (qBittorrent category `prowlarr`), `/data/media/shows` (Sonarr), `/data/media/movies` (Radarr). The `shows`/`movies` names match the Jellyfin stack's library mounts.
- In the qBittorrent download client settings, set **Category** to `prowlarr`.
## Dockhand Stack, Deploy from Git ## Dockhand Stack, Deploy from Git
- **Cookbooks Repository** - **Cookbooks Repository**
- **stackname:** radarr_dev - **stackname:** radarr
- **Compose file path:** radarr_dev/compose.yaml - **Compose file path:** radarr/compose.yaml
- **Additional env file (optional):** radarr_dev/sample.env - **Additional env file (optional):** radarr/sample.env
Load `radarr_dev/sample.env` into the Environment variables in Dockhand, then create the Stack. Load `radarr/sample.env` into the Environment variables in Dockhand, then create the Stack.
+8 -5
View File
@@ -20,13 +20,13 @@ Open http://localhost:8787 in your browser and complete the initial setup wizard
Once the wizard finishes, you'll see an empty library. To populate it: Once the wizard finishes, you'll see an empty library. To populate it:
- Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/books`) — this is where your organized book library will live - Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/media/books`) — this is where your organized book library will live
- Click **Add Author** and search by name — Readarr fetches metadata, covers, and available editions - Click **Add Author** and search by name — Readarr fetches metadata, covers, and available editions
- Optionally connect a **List** (Goodreads, etc.) to auto-import authors from your reading lists - Optionally connect a **List** (Goodreads, etc.) to auto-import authors from your reading lists
### Download flow ### Download flow
qBittorrent downloads to its own directory → Readarr picks it up, renames the file, and moves it into `<Root Folder>/Author Name/Book Name/` qBittorrent downloads to `/media/downloads/prowlarr` → Readarr picks it up, renames the file, and moves it into `<Root Folder>/Author Name/Book Name/`
## Environment Variable Notes ## Environment Variable Notes
@@ -36,6 +36,7 @@ qBittorrent downloads to its own directory → Readarr picks it up, renames the
| `READARR_RESTART` | Restart policy (default: `unless-stopped`) | | `READARR_RESTART` | Restart policy (default: `unless-stopped`) |
| `READARR_PORT` | Published port for the web UI (default: `8787`) | | `READARR_PORT` | Published port for the web UI (default: `8787`) |
| `VOL_PATH` | Base path for persistent data volumes (default: `/data`) | | `VOL_PATH` | Base path for persistent data volumes (default: `/data`) |
| `READARR_MEDIA` | Shared media root on the host (default: `/data/media`), mounted at `/media`. Must be the same folder qBittorrent, Sonarr, Radarr and Jellyfin use |
| `TZ` | Container timezone (default: `America/Vancouver`) | | `TZ` | Container timezone (default: `America/Vancouver`) |
## Volume Notes ## Volume Notes
@@ -43,7 +44,7 @@ qBittorrent downloads to its own directory → Readarr picks it up, renames the
| Volume | Purpose | | Volume | Purpose |
|---|---| |---|---|
| `${VOL_PATH:-/data}/readarr/config` | Application configuration and database | | `${VOL_PATH:-/data}/readarr/config` | Application configuration and database |
| `${VOL_PATH:-/data}/readarr/data` | Download client data and working directory | | `${READARR_MEDIA:-/data/media}` → `/media` | Shared media root: downloads in `/media/downloads`, library in `/media/books` |
## Network Notes ## Network Notes
@@ -64,7 +65,7 @@ docker run -d \
-e TZ=America/Vancouver \ -e TZ=America/Vancouver \
-p 8787:8787 \ -p 8787:8787 \
-v ${VOL_PATH:-/data}/readarr/config:/config \ -v ${VOL_PATH:-/data}/readarr/config:/config \
-v ${VOL_PATH:-/data}/readarr/data:/data \ -v ${READARR_MEDIA:-/data/media}:/media \
--network proxy \ --network proxy \
--restart unless-stopped \ --restart unless-stopped \
ghcr.io/hotio/readarr:release ghcr.io/hotio/readarr:release
@@ -72,7 +73,9 @@ docker run -d \
## Additional Notes / Gotchas ## Additional Notes / Gotchas
Nothing specific to this stack so far. - **One shared media folder.** qBittorrent, Sonarr, Radarr, Readarr and Jellyfin all use `/data/media` on the host, mounted at `/media`, so a download has the same path in every container: no Remote Path Mapping needed, and imports can use hardlinks. Enable **Settings → Media Management → Use Hardlinks instead of Copy**.
- **Layout:** `/data/media/downloads/prowlarr` (qBittorrent category `prowlarr`), `/data/media/books` (Readarr root, Jellyfin's `/books` library).
- In the qBittorrent download client settings, set **Category** to `prowlarr`.
## Dockhand Stack, Deploy from Git ## Dockhand Stack, Deploy from Git
+1 -1
View File
@@ -4,7 +4,7 @@ services:
restart: ${READARR_RESTART:-unless-stopped} restart: ${READARR_RESTART:-unless-stopped}
volumes: volumes:
- ${VOL_PATH:-/data}/readarr/config:/config - ${VOL_PATH:-/data}/readarr/config:/config
- ${VOL_PATH:-/data}/readarr/data:/data - ${READARR_MEDIA:-/data/media}:/media
environment: environment:
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
+1
View File
@@ -4,3 +4,4 @@ READARR_IMAGE=ghcr.io/hotio/readarr:release
TZ=America/Vancouver TZ=America/Vancouver
READARR_PORT=8787 READARR_PORT=8787
READARR_RESTART=unless-stopped READARR_RESTART=unless-stopped
READARR_MEDIA=/data/media
+12 -9
View File
@@ -20,13 +20,13 @@ Open http://localhost:8989 in your browser and complete the initial setup wizard
Once the wizard finishes, you'll see an empty library. To populate it: Once the wizard finishes, you'll see an empty library. To populate it:
- Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/tv`) — this is where your organized TV library will live - Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/media/shows`) — this is where your organized TV library will live
- Click **Add Series** and search by title — Sonarr fetches metadata, posters, and available releases - Click **Add Series** and search by title — Sonarr fetches metadata, posters, and available releases
- Optionally connect a **List** (Trakt, IMDb, etc.) to auto-import series from your watchlists - Optionally connect a **List** (Trakt, IMDb, etc.) to auto-import series from your watchlists
### Download flow ### Download flow
qBittorrent downloads to its own directory → Sonarr picks it up, renames the file, and moves it into `<Root Folder>/Series Name/Season XX/` qBittorrent downloads to `/media/downloads/prowlarr` → Sonarr picks it up, renames the file, and moves it into `<Root Folder>/Series Name/Season XX/`
## Environment Variable Notes ## Environment Variable Notes
@@ -36,6 +36,7 @@ qBittorrent downloads to its own directory → Sonarr picks it up, renames the f
| `SONARR_RESTART` | Restart policy (default: `unless-stopped`) | | `SONARR_RESTART` | Restart policy (default: `unless-stopped`) |
| `SONARR_PORT` | Published port for the web UI (default: `8989`) | | `SONARR_PORT` | Published port for the web UI (default: `8989`) |
| `VOL_PATH` | Base path for persistent data volumes (default: `/data`) | | `VOL_PATH` | Base path for persistent data volumes (default: `/data`) |
| `SONARR_MEDIA` | Shared media root on the host (default: `/data/media`), mounted at `/media`. Must be the same folder qBittorrent, Radarr and Jellyfin use |
| `TZ` | Container timezone (default: `America/Vancouver`) | | `TZ` | Container timezone (default: `America/Vancouver`) |
## Volume Notes ## Volume Notes
@@ -43,7 +44,7 @@ qBittorrent downloads to its own directory → Sonarr picks it up, renames the f
| Volume | Purpose | | Volume | Purpose |
|---|---| |---|---|
| `${VOL_PATH:-/data}/sonarr/config` | Application configuration and database | | `${VOL_PATH:-/data}/sonarr/config` | Application configuration and database |
| `${VOL_PATH:-/data}/sonarr/data` | Download client data and working directory | | `${SONARR_MEDIA:-/data/media}` → `/media` | Shared media library, kept separate from `VOL_PATH` since it's typically mounted into Sonarr, Radarr, Bazarr, and Jellyfin/etc. |
## Network Notes ## Network Notes
@@ -64,7 +65,7 @@ docker run -d \
-e TZ=America/Vancouver \ -e TZ=America/Vancouver \
-p 8989:8989 \ -p 8989:8989 \
-v ${VOL_PATH:-/data}/sonarr/config:/config \ -v ${VOL_PATH:-/data}/sonarr/config:/config \
-v ${VOL_PATH:-/data}/sonarr/data:/data \ -v ${SONARR_MEDIA:-/data/media}:/media \
--network proxy \ --network proxy \
--restart unless-stopped \ --restart unless-stopped \
ghcr.io/hotio/sonarr:release ghcr.io/hotio/sonarr:release
@@ -72,13 +73,15 @@ docker run -d \
## Additional Notes / Gotchas ## Additional Notes / Gotchas
Nothing specific to this stack so far. - **One shared media folder.** qBittorrent, Sonarr, Radarr and Jellyfin all use `/data/media` on the host. qBittorrent, Sonarr and Radarr mount it at `/media`, so a download has the same path in every container: no Remote Path Mapping needed, and imports can use hardlinks (instant, no extra disk space). Enable **Settings → Media Management → Use Hardlinks instead of Copy**.
- **Layout:** `/data/media/downloads/prowlarr` (qBittorrent category `prowlarr`), `/data/media/shows` (Sonarr), `/data/media/movies` (Radarr). The `shows`/`movies` names match the Jellyfin stack's library mounts.
- In the qBittorrent download client settings, set **Category** to `prowlarr`.
## Dockhand Stack, Deploy from Git ## Dockhand Stack, Deploy from Git
- **Cookbooks Repository** - **Cookbooks Repository**
- **stackname:** sonarr_dev - **stackname:** sonarr
- **Compose file path:** sonarr_dev/compose.yaml - **Compose file path:** sonarr/compose.yaml
- **Additional env file (optional):** sonarr_dev/sample.env - **Additional env file (optional):** sonarr/sample.env
Load `sonarr_dev/sample.env` into the Environment variables in Dockhand, then create the Stack. Load `sonarr/sample.env` into the Environment variables in Dockhand, then create the Stack.
@@ -4,7 +4,7 @@ services:
restart: ${SONARR_RESTART:-unless-stopped} restart: ${SONARR_RESTART:-unless-stopped}
volumes: volumes:
- ${VOL_PATH:-/data}/sonarr/config:/config - ${VOL_PATH:-/data}/sonarr/config:/config
- ${VOL_PATH:-/data}/sonarr/data:/data - ${SONARR_MEDIA:-/data/media}:/media
environment: environment:
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
@@ -4,3 +4,4 @@ SONARR_IMAGE=ghcr.io/hotio/sonarr:release
TZ=America/Vancouver TZ=America/Vancouver
SONARR_PORT=8989 SONARR_PORT=8989
SONARR_RESTART=unless-stopped SONARR_RESTART=unless-stopped
SONARR_MEDIA=/data/media
+8 -5
View File
@@ -20,13 +20,13 @@ Open http://localhost:6969 in your browser and complete the initial setup wizard
Once the wizard finishes, you'll see an empty library. To populate it: Once the wizard finishes, you'll see an empty library. To populate it:
- Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/adult`) — this is where your organized library will live - Go to **Settings → Media Management** and add a **Root Folder** (e.g., `/media/adult`) — this is where your organized library will live
- Click **Add Movie** and search by title — Whisparr fetches metadata and available releases - Click **Add Movie** and search by title — Whisparr fetches metadata and available releases
- Optionally connect a **List** to auto-import from your watchlists - Optionally connect a **List** to auto-import from your watchlists
### Download flow ### Download flow
qBittorrent downloads to its own directory → Whisparr picks it up, renames the file, and moves it into `<Root Folder>/Title (Year)/` qBittorrent downloads to `/media/downloads/prowlarr` → Whisparr picks it up, renames the file, and moves it into `<Root Folder>/Title (Year)/`
## Environment Variable Notes ## Environment Variable Notes
@@ -36,6 +36,7 @@ qBittorrent downloads to its own directory → Whisparr picks it up, renames the
| `WHISPARR_RESTART` | Restart policy (default: `unless-stopped`) | | `WHISPARR_RESTART` | Restart policy (default: `unless-stopped`) |
| `WHISPARR_PORT` | Published port for the web UI (default: `6969`) | | `WHISPARR_PORT` | Published port for the web UI (default: `6969`) |
| `VOL_PATH` | Base path for persistent data volumes (default: `/data`) | | `VOL_PATH` | Base path for persistent data volumes (default: `/data`) |
| `WHISPARR_MEDIA` | Shared media root on the host (default: `/data/media`), mounted at `/media`. Must be the same folder qBittorrent, Sonarr, Radarr and Jellyfin use |
| `TZ` | Container timezone (default: `America/Vancouver`) | | `TZ` | Container timezone (default: `America/Vancouver`) |
## Volume Notes ## Volume Notes
@@ -43,7 +44,7 @@ qBittorrent downloads to its own directory → Whisparr picks it up, renames the
| Volume | Purpose | | Volume | Purpose |
|---|---| |---|---|
| `${VOL_PATH:-/data}/whisparr/config` | Application configuration and database | | `${VOL_PATH:-/data}/whisparr/config` | Application configuration and database |
| `${VOL_PATH:-/data}/whisparr/data` | Download client data and working directory | | `${WHISPARR_MEDIA:-/data/media}` → `/media` | Shared media root: downloads in `/media/downloads`, library in `/media/adult` |
## Network Notes ## Network Notes
@@ -64,7 +65,7 @@ docker run -d \
-e TZ=America/Vancouver \ -e TZ=America/Vancouver \
-p 6969:6969 \ -p 6969:6969 \
-v ${VOL_PATH:-/data}/whisparr/config:/config \ -v ${VOL_PATH:-/data}/whisparr/config:/config \
-v ${VOL_PATH:-/data}/whisparr/data:/data \ -v ${WHISPARR_MEDIA:-/data/media}:/media \
--network proxy \ --network proxy \
--restart unless-stopped \ --restart unless-stopped \
ghcr.io/hotio/whisparr:release ghcr.io/hotio/whisparr:release
@@ -72,7 +73,9 @@ docker run -d \
## Additional Notes / Gotchas ## Additional Notes / Gotchas
Nothing specific to this stack so far. - **One shared media folder.** qBittorrent, Sonarr, Radarr, Whisparr and Jellyfin all use `/data/media` on the host, mounted at `/media`, so a download has the same path in every container: no Remote Path Mapping needed, and imports can use hardlinks. Enable **Settings → Media Management → Use Hardlinks instead of Copy**.
- **Layout:** `/data/media/downloads/prowlarr` (qBittorrent category `prowlarr`), `/data/media/adult` (Whisparr root, not mounted by Jellyfin by default).
- In the qBittorrent download client settings, set **Category** to `prowlarr`.
## Dockhand Stack, Deploy from Git ## Dockhand Stack, Deploy from Git
+1 -1
View File
@@ -4,7 +4,7 @@ services:
restart: ${WHISPARR_RESTART:-unless-stopped} restart: ${WHISPARR_RESTART:-unless-stopped}
volumes: volumes:
- ${VOL_PATH:-/data}/whisparr/config:/config - ${VOL_PATH:-/data}/whisparr/config:/config
- ${VOL_PATH:-/data}/whisparr/data:/data - ${WHISPARR_MEDIA:-/data/media}:/media
environment: environment:
- PUID=1000 - PUID=1000
- PGID=1000 - PGID=1000
+1
View File
@@ -4,3 +4,4 @@ WHISPARR_IMAGE=ghcr.io/hotio/whisparr:release
TZ=America/Vancouver TZ=America/Vancouver
WHISPARR_PORT=6969 WHISPARR_PORT=6969
WHISPARR_RESTART=unless-stopped WHISPARR_RESTART=unless-stopped
WHISPARR_MEDIA=/data/media