Status: CURRENT — MAJOR 2026 UPDATE
Last reviewed: 31 August 2026
Applies to: Docker Compose, Bazarr, Jellyfin, Seerr, Plex, Prowlarr, Radarr, Sonarr and TautulliThe original idea behind this stack is still good: put related containers on one Docker network so they can find each other by service name instead of hard-coding IP addresses. A few of the actual applications and Docker habits from the old stack are now cactus though, so this is the cleaned-up version.
My entertainment stack has always been built around one simple Docker feature:
http://prowlarr:9696No memorising container IP addresses. No changing configs when Docker hands a container a different IP. If two containers are on the same user-defined Docker network, Docker’s internal DNS lets them talk to each other using the service/container name.
That part of the original article was spot on and is still how I’d do it today.
What’s changed since the old stack?
- Overseerr is gone. The original project was archived in February 2026. Overseerr and Jellyseerr have effectively converged into Seerr, which is the current maintained project.
- Watchtower is gone. The upstream project was archived in December 2025 and now explicitly says it is no longer maintained.
- The top-level Compose
version: "3.6"line is obsolete and ignored by modern Docker Compose. - I’ve changed application configs from anonymous/named Docker volumes to obvious bind mounts under
/home/richay/docker/. Much easier to back up and inspect when something inevitably goes sideways at 1am. - Radarr/Sonarr/Bazarr now see one consistent
/datatree instead of three completely different host paths. - Prowlarr and Seerr don’t need access to your entire media library, so they no longer get it. Less access, less bullshit.
- Plex still uses host networking in this example because LinuxServer continues to document that as its standard setup, but its old
ports:entry has been removed because Docker ignores published ports in host-network mode.
Overseerr → Seerr
The old stack used:
sctx/overseerr:latestThat repository was archived on 15 February 2026. The current maintained project is Seerr, which supports Plex, Jellyfin and Emby and still integrates with Sonarr and Radarr.
The current official Docker image is:
ghcr.io/seerr-team/seerr:latestIf you’re migrating an existing Overseerr/Jellyseerr database rather than starting fresh, use Seerr’s official migration guide. Don’t just point a random new image at the old database and hope Docker Jesus sorts it out 🙂
Watchtower has been removed
The old stack let Watchtower automatically pull and replace containers. The Watchtower maintainers archived the project on 17 December 2025 and now state that it is no longer maintained.
I don’t think unattended auto-updates are worth handing permanent Docker-socket access to an abandoned container.
Updating this stack manually is hardly an ordeal:
docker compose pull
docker compose up -d
docker image pruneLinuxServer currently recommends Diun if you want notifications that new images are available, rather than automatically updating everything while you’re asleep and waking up to seven broken services and a strong urge to throw the server into the pool.
Folder layout
I keep Compose files and persistent Docker data separate:
/home/richay/docker-compose/ # Compose files and small hand-managed config
/home/richay/docker/ # Persistent container dataA simple media tree might look like:
/mnt/media/
├── downloads/
└── media/
├── movies/
├── tv/
└── music/The important part is that Radarr/Sonarr and your download client see the same filesystem through the same /data container path. That allows hardlinks and atomic moves instead of copying a massive file from one mount to another and then deleting the original.
Create the config folders:
mkdir -p /home/richay/docker-compose/entertainment
mkdir -p /home/richay/docker/{bazarr,jellyfin,seerr,plex,prowlarr,radarr,sonarr,tautulli}
mkdir -p /mnt/media/{downloads,media/movies,media/tv,media/music}Current entertainment Compose stack
This keeps the spirit of my original stack without carrying all the old baggage:
services:
bazarr:
image: lscr.io/linuxserver/bazarr:latest
container_name: bazarr
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Perth
volumes:
- /home/richay/docker/bazarr:/config
- /mnt/media:/data
ports:
- "6767:6767"
restart: unless-stopped
networks:
- entertainment
jellyfin:
image: lscr.io/linuxserver/jellyfin:latest
container_name: jellyfin
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Perth
volumes:
- /home/richay/docker/jellyfin:/config
- /mnt/media/media:/data/media:ro
ports:
- "8096:8096"
# Optional local discovery:
# - "7359:7359/udp"
# Optional DLNA/service discovery:
# - "1900:1900/udp"
# Intel/AMD hardware acceleration:
# devices:
# - /dev/dri:/dev/dri
restart: unless-stopped
networks:
- entertainment
seerr:
image: ghcr.io/seerr-team/seerr:latest
container_name: seerr
init: true
environment:
- LOG_LEVEL=info
- TZ=Australia/Perth
- PORT=5055
volumes:
- /home/richay/docker/seerr:/app/config
ports:
- "5055:5055"
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:5055/api/v1/settings/public || exit 1
start_period: 20s
timeout: 3s
interval: 15s
retries: 3
restart: unless-stopped
networks:
- entertainment
plex:
image: lscr.io/linuxserver/plex:latest
container_name: plex
network_mode: host
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Perth
- VERSION=docker
- PLEX_CLAIM=
volumes:
- /home/richay/docker/plex:/config
- /mnt/media/media:/data/media:ro
# Intel/AMD hardware acceleration:
# devices:
# - /dev/dri:/dev/dri
restart: unless-stopped
prowlarr:
image: lscr.io/linuxserver/prowlarr:latest
container_name: prowlarr
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Perth
volumes:
- /home/richay/docker/prowlarr:/config
ports:
- "9696:9696"
restart: unless-stopped
networks:
- entertainment
radarr:
image: lscr.io/linuxserver/radarr:latest
container_name: radarr
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Perth
volumes:
- /home/richay/docker/radarr:/config
- /mnt/media:/data
ports:
- "7878:7878"
restart: unless-stopped
networks:
- entertainment
sonarr:
image: lscr.io/linuxserver/sonarr:latest
container_name: sonarr
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Perth
volumes:
- /home/richay/docker/sonarr:/config
- /mnt/media:/data
ports:
- "8989:8989"
restart: unless-stopped
networks:
- entertainment
tautulli:
image: lscr.io/linuxserver/tautulli:latest
container_name: tautulli
environment:
- PUID=1000
- PGID=1000
- TZ=Australia/Perth
volumes:
- /home/richay/docker/tautulli:/config
ports:
- "8181:8181"
restart: unless-stopped
networks:
- entertainment
networks:
entertainment:
name: entertainment
Why keep an explicit entertainment network?
Docker Compose automatically creates a default network and provides service-name DNS anyway, so technically the explicit network isn’t required if everything lives in this one Compose project.
I still like naming it entertainment because it gives me a stable network name that another stack can deliberately join later.
For example, Radarr can talk to Sonarr/Prowlarr-style services using names such as:
http://prowlarr:9696
http://radarr:7878
http://sonarr:8989
http://seerr:5055
http://jellyfin:8096No container IPs required. Docker handles the internal DNS. Fucking lovely.
Plex is the odd bastard
Plex uses network_mode: host in the LinuxServer recommended configuration, so it does not join the entertainment bridge network in this example.
That also means this old combination was pointless:
network_mode: host
ports:
- 32400:32400Docker explicitly ignores published ports when host networking is enabled because Plex is already binding directly to the host’s network stack.
So Tautulli/Seerr should reach Plex using the Docker host’s LAN address, for example:
http://192.168.1.10:32400Replace that with your actual Docker/Plex host address.
Jellyfin ports
The only Jellyfin port I expose by default in the stack is:
8096/tcp # normal Jellyfin HTTP web/APILinuxServer still documents 8920/tcp, 7359/udp and 1900/udp as optional ports. I don’t bother with Jellyfin’s own HTTPS port 8920 when Traefik is handling TLS in front of it.
7359/udp is useful for local client discovery and 1900/udp is used for service/DLNA discovery. Uncomment them only if you actually use those features.
Hardware transcoding
For Intel/AMD hardware acceleration, LinuxServer’s Jellyfin image still supports mapping the host’s DRI device:
devices:
- /dev/dri:/dev/driThe same mapping can be used for Plex when the Docker host has the GPU available.
If you’re running Docker inside a Proxmox LXC, get the GPU working in the LXC first. Then pass it to Docker. Debugging Proxmox → LXC → Docker → Jellyfin all at once is how hobbies turn into drinking problems 🙂
Where’s qBittorrent?
I deliberately left the download client out of this stack.
If qBittorrent needs to live behind a VPN, I prefer it in a dedicated VPN/download stack rather than mixing VPN networking into Plex, Jellyfin and everything else.
See my updated Docker Stack with ExpressVPN article for the VPN side.
Radarr and Sonarr can still use that qBittorrent instance as their download client — it does not need to be in the same Compose file.
Don’t mount everything into everything
My old stack gave Prowlarr and Overseerr access to media, storage and downloads even though they had no bloody reason to touch those files.
The new split is:
- Radarr / Sonarr / Bazarr: access to the shared
/datatree. - Plex / Jellyfin: read-only access to
/data/media. - Prowlarr / Seerr / Tautulli: config only; no media filesystem access required.
It’s cleaner and reduces the blast radius if one container ever gets compromised.
Starting and checking the stack
cd /home/richay/docker-compose/entertainment
docker compose up -d
docker compose psThen confirm the internal Docker DNS works from one of the containers:
docker exec sonarr getent hosts prowlarr
docker exec sonarr getent hosts radarrIf those return container IPs, the service-name networking is doing exactly what we wanted.
Old stack — what I’d keep and what I’d bin
- ✅ Keep: one shared Docker network and service-name communication.
- ✅ Keep: LinuxServer images for the *arr apps, Jellyfin, Plex and Tautulli.
- ✅ Keep: Perth timezone and sensible PUID/PGID ownership.
- 🛠️ Change: Overseerr → Seerr.
- 🛠️ Change: named volumes → obvious bind-mounted config folders.
- 🛠️ Change: multiple inconsistent media paths → one
/datatree. - 🗑️ Bin: obsolete Compose
version: "3.6". - 🗑️ Bin: Watchtower.
- 🗑️ Bin: pointless Plex
ports:while using host networking.
References
- Docker Compose networking / service-name DNS
- Docker Compose obsolete version field
- Docker host networking
- Seerr Docker documentation
- Seerr migration guide
- Archived Watchtower project
- LinuxServer Jellyfin
- LinuxServer Plex
- TRaSH Guides file/folder structure
- My VPN/download stack
The original stack wasn’t bad at all — the networking idea aged really well. It just accumulated a couple of dead projects, redundant mounts and Docker archaeology around it. A bit of a clean-out and she’s good again 🙂
