Running 40+ Docker containers on UnRAID without losing your mind
At some point your UnRAID server stops being a NAS and starts being a small data center. I’m running 47 containers right now – Plex, Sonarr, Radarr, Lidarr, qBittorrent, SABnzbd, Immich, Ollama, audiobookshelf, two game servers, and a long tail of smaller tools. Here’s how I keep it manageable.
Naming
When you have 47 containers, naming matters. I follow the upstream image name where possible: binhex-plexpass, binhex-sonarr, binhex-radarr, binhex-lidarr. It makes grepping logs and writing scripts that target groups of containers straightforward.
Non-binhex containers use PascalCase for external services (Unraid-Cloudflared-Tunnel, MeTube-YouTube) and lowercase for infrastructure (runestone-nginx, mariadb, redis). Inconsistent, but the grouping is legible at a glance.
Path mappings
The biggest source of headaches between containers is inconsistent path mappings. My rule for media containers: /mnt/user/data maps to /data.
SABnzbd: /mnt/user/data → /data
Radarr: /mnt/user/data → /data
Sonarr: /mnt/user/data → /data
When Radarr tells SABnzbd where a completed file is, the paths match inside both containers. No remote path mapping gymnastics.
Download clients are slightly different – they only need their own piece of the tree:
qBittorrent: /mnt/user/data/downloads/torrents → /data
Lidarr: /mnt/user/data/downloads → /data
The principle holds even if the mount point doesn’t start at the root of /mnt/user/data – the container-side path is always /data, so anything writing to /data/... lands in a predictable place on the host.
Shared scripts directory
All custom scripts live in /mnt/user/appdata/scripts and get mounted into any container that needs them – always at the same path:
/mnt/user/appdata/scripts → /mnt/user/appdata/scripts
Radarr, Sonarr, and Lidarr all have this mount. A script written once is accessible from every container that runs automations. Permissions are PUID=99 PGID=100 across the board – every binhex container and qbittorrent runs as the same user, so there are no permission surprises when one container writes a file another needs to read.
The docker.sock question
Four containers have access to the Docker socket: binhex-sonarr, binhex-radarr, and two Lidarr instances. Sonarr and Radarr use it to spin up temporary MKVToolNix containers for DoVi muxing operations. The Lidarr containers use it to invoke beets containers for post-download tagging.
It’s a calculated trade-off – Docker socket access is essentially root on the host. These four containers are updated regularly and are the only ones that get it. Everything else is isolated.
Plex gets a hard cap, not just priority
Plex is the only container my family and friends interact with directly, so I don’t want background jobs starving it. But I also don’t want a runaway Plex transcode eating the whole machine. The solution is a hard resource cap:
- CPU: 4 cores max (
CpuQuota=400000) - RAM: 4GB max
Background jobs like DoVi conversions run uncapped but check for active Plex streams before starting heavy work. If someone is watching, the job waits. Plex stays smooth, conversions happen overnight.