Running Plex in Docker is the gold standard for home media servers in 2026. You get reproducible deployments, easy updates, clean isolation from the host OS, and the ability to back up your entire configuration as a single volume. But the moment you add hardware transcoding to the equation, things get complicated. GPU passthrough into a Docker container requires the right drivers, the right runtime, and the right container flags — get any one of them wrong and Plex falls back to CPU transcoding without telling you.
Why Docker for Plex
Before we get into GPU configuration, it’s worth understanding why Docker is the preferred way to run Plex. A bare-metal Plex install ties your media server to the host OS — updates can break things, configuration files scatter across /var/lib, and migrating to new hardware means re-doing everything from scratch.
Docker solves all of that. Your Plex configuration lives in a bind-mounted volume. Your media libraries are passed in as read-only mounts. The Plex binary itself is just a container image that you can update with a single docker pull. If something goes wrong, you roll back to the previous image. If your server dies, you spin up a new container on different hardware, point it at the same volumes, and Plex picks up exactly where it left off.
The two most popular Plex Docker images are the official plexinc/pms-docker and the community-maintained linuxserver/plex. Both work with GPU passthrough. The LinuxServer image adds PGID/PUID user mapping and automatic library permissions, which avoids the common “permission denied on media files” headache.
Prerequisites: Host-Side NVIDIA Setup
GPU passthrough to Docker requires three things on the host machine:
- NVIDIA proprietary drivers installed on the host (not inside the container). On Ubuntu/Debian, use
sudo apt install nvidia-driver-560or whatever the latest stable version is. Verify withnvidia-smi. - NVIDIA Container Toolkit (formerly nvidia-docker2). This installs a custom OCI runtime that hooks into Docker’s container creation process and injects the GPU device nodes and driver libraries into the container at startup.
- Docker Engine configured to use the NVIDIA runtime. This can be set globally in
/etc/docker/daemon.jsonor per-container with the--runtime=nvidiaflag.
Install the NVIDIA Container Toolkit with:
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update && sudo apt install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
After this, test that Docker can see your GPU:
docker run --rm --gpus all nvidia/cuda:12.6.0-base-ubuntu24.04 nvidia-smi
You should see your GPU listed with driver version and CUDA version. If this fails, the issue is on the host — fix it before touching Plex.
The Docker Compose Configuration
Here’s a production-ready docker-compose.yml for Plex with GPU passthrough:
services:
plex:
image: linuxserver/plex:latest
container_name: plex
network_mode: host
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=America/New_York
- VERSION=docker
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=compute,video,utility
volumes:
- ./config:/config
- /mnt/media/movies:/movies:ro
- /mnt/media/tv:/tv:ro
- /dev/shm:/transcode
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: all
capabilities: [gpu, compute, video]
Key details:
- network_mode: host — Plex discovery (GDM) uses broadcast/multicast, which doesn’t work through Docker’s default bridge network. Host networking lets local clients find your server automatically.
- NVIDIA_VISIBLE_DEVICES=all — exposes all GPUs to the container. Set to a specific GPU UUID if you have multiple cards and want to dedicate one to Plex.
- NVIDIA_DRIVER_CAPABILITIES=compute,video,utility — the
videocapability is critical. Without it, the NVDEC/NVENC hardware blocks won’t be available inside the container. - /dev/shm:/transcode — mounts shared memory as the transcode directory. This keeps temporary transcode segments in RAM instead of writing to disk, eliminating I/O bottlenecks and reducing SSD wear.
- deploy.resources.reservations.devices — this is the Docker Compose v2 syntax for GPU reservation. It replaces the older
runtime: nvidiaapproach.
Enabling Hardware Transcoding in Plex
Getting the GPU visible inside the container is only half the battle. You also need to enable hardware transcoding in Plex’s settings. This requires a Plex Pass subscription — hardware transcoding is not available on the free tier.
In the Plex web UI, go to Settings → Transcoder and check “Use hardware acceleration when available” and “Use hardware-accelerated video encoding.” For HDR content, also enable “Use hardware-accelerated tone mapping.”
After enabling these settings, play a video that requires transcoding (force it by setting the quality to 720p in the player) and check the Plex dashboard. You should see “(hw)” next to both the video decoder and encoder. If you see “(hw)” on the decoder but not the encoder, or vice versa, something is misconfigured.
Common Pitfalls and How to Fix Them
Pitfall 1: “nvidia-smi works in the container but Plex still uses CPU.” Check that NVIDIA_DRIVER_CAPABILITIES includes video. Many guides only set compute,utility, which gives you CUDA but not the hardware encoder/decoder. Also verify your GPU isn’t artificially limited — consumer GeForce cards before the RTX 40 series were limited to 3–5 simultaneous NVENC sessions by the driver. The community nvidia-patch removes this limit.
Pitfall 2: “Permission denied on /dev/dri.” Some setups need explicit device passthrough for the DRM render nodes. Add devices: [/dev/dri:/dev/dri] to your compose file, or ensure the container user is in the video and render groups.
Pitfall 3: “Transcoding works but quality is terrible.” By default, NVENC uses a fast preset that prioritizes speed over quality. You can improve this in Plex’s advanced transcoder settings, but the real answer is to avoid transcoding when possible. Pre-optimize your library for common client codecs, and reserve GPU transcoding for the cases where it’s genuinely needed.
Pitfall 4: “Docker Compose up fails with ‘unknown device’ error.” You’re probably using Docker Compose v1 syntax with a v2+ runtime. The deploy.resources.reservations.devices block requires Docker Compose v2 (the docker compose plugin, not the standalone docker-compose binary).
Performance Comparison: CPU vs GPU in Docker
To put numbers on the difference, here’s what a 4K HEVC → 1080p H.264 transcode looks like on the same machine, with and without GPU passthrough:
| Method | Speed | CPU Usage | Max Streams |
|---|---|---|---|
| CPU (i7-12700) | 1.2× realtime | 95–100% | 1–2 |
| QSV (12th gen iGPU) | 6× realtime | 15–25% | 4–6 |
| NVENC (RTX 3060) | 11× realtime | 5–10% | 8–12 |
The CPU column is the real story. With GPU transcoding, your CPU stays almost idle — free to handle Plex metadata scanning, library updates, subtitle processing, and other background tasks that would otherwise compete with transcoding for CPU time.
When Local GPU Isn’t Enough
Docker GPU passthrough is excellent for personal use, but it has limits. Your GPU sits idle 90% of the time and maxes out during peak viewing hours. If you share your library with family and friends, a single consumer GPU can become a bottleneck when multiple users need simultaneous HDR transcodes.
PlexBeam takes the same GPU transcoding pipeline — NVDEC decode, CUDA tone mapping, NVENC encode — and moves it to dedicated remote workers. Your Plex container stays light (no GPU needed locally), and transcode requests are routed to the nearest GPU worker with available capacity. Think of it as Docker GPU passthrough, but elastic and always available.