Your Server Is Transcoding Files It Doesn’t Need To, and It’s Your Fault
Harsh? Maybe. But if you’ve got Plex running and you haven’t explicitly verified direct play is happening, you’re almost certainly burning CPU cycles re-encoding videos that your TV or phone could play natively. Plex’s defaults are… generous, let’s say. It will cheerfully transcode 4K HDR content to 1080p SDR on your server’s CPU while that server fans spin up to jet engine levels.
Here’s how to actually configure this thing.
Direct Play vs Transcoding: Why This Matters So Much
When Plex direct plays a file:
- The file is sent to the client as-is (or remuxed with zero re-encoding)
- CPU usage: nearly zero
- Quality: original, no degradation
- Buffer: minimal
When Plex transcodes:
- The server re-encodes the video in real time
- CPU usage: high (software transcode) or moderate (hardware transcode)
- Quality: slightly degraded from original
- Buffer: depends on transcode speed vs bitrate
Direct play is always better when you can get it. The goal is to encode your library (using HandBrake, as covered previously) into formats your clients can natively play, then configure Plex to stop trying to “help.”
What breaks direct play
- Client says it can’t play the codec (H.265 on old devices, AV1 on most things)
- Container format mismatch (rare with MKV/MP4)
- Bitrate higher than the client’s quality setting allows
- Subtitle format — this is a sneaky one. Image-based subtitles (PGS, VOBSUB) force a transcode even if the video and audio are fine. Convert them to SRT/ASS format
Check what’s happening: in Plex, go to Dashboard → Now Playing. It’ll show “Direct Play,” “Direct Stream,” or “Transcode.” Aim for the first one.
Hardware Transcoding Setup
When you do need to transcode (you will sometimes), make sure your GPU is doing it, not your CPU.
Requirements
- Plex Pass — hardware transcoding is a Plex Pass feature. Yes, it costs money. Yes, it’s worth it if you have remote users.
- Intel QuickSync: Any Intel processor with integrated graphics, 6th gen (Skylake) or newer
- NVIDIA NVENC: GTX 600 series or newer
- AMD VCE: Radeon RX 400 series or newer
Docker setup with Intel QuickSync
version: "3.8"
services:
plex:
image: plexinc/pms-docker:latest
container_name: plex
network_mode: host
restart: unless-stopped
devices:
- /dev/dri:/dev/dri # Intel GPU access
environment:
- PLEX_CLAIM=claim-xxxxxxxxxxxxxxxxxxxx # Get from plex.tv/claim
- PLEX_UID=1000
- PLEX_GID=1000
- TZ=America/New_York
volumes:
- /opt/plex/config:/config
- /media:/data
For the claim token, visit plex.tv/claim — it expires in 4 minutes, so have your Compose file ready before you grab it.
Docker with NVIDIA
services:
plex:
image: plexinc/pms-docker:latest
container_name: plex
network_mode: host
restart: unless-stopped
runtime: nvidia # Requires nvidia-container-toolkit
environment:
- NVIDIA_VISIBLE_DEVICES=all
- NVIDIA_DRIVER_CAPABILITIES=video,compute,utility
- PLEX_CLAIM=claim-xxxxxxxxxxxxxxxxxxxx
volumes:
- /opt/plex/config:/config
- /media:/data
Install nvidia-container-toolkit first if you haven’t:
distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/libnvidia-container/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/libnvidia-container/$distribution/libnvidia-container.list | \
sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
sudo apt update && sudo apt install -y nvidia-container-toolkit
sudo systemctl restart docker
After launching, go to Plex Settings → Transcoder → enable “Use hardware acceleration when available.” Check Dashboard during a transcode — you should see it report HW transcode.
Remote Access: Port Forwarding vs the Relay
Here’s where people leave performance on the table. By default, if Plex can’t directly connect to your server, it routes traffic through Plex’s relay servers. This is:
- Bandwidth-limited to 2Mbps (enough for SD, not great for HD)
- Adding latency
- Dependent on Plex’s infrastructure
Fix it: forward port 32400 on your router to your server’s local IP.
Router: External port 32400 → Internal 192.168.1.100:32400
In Plex: Settings → Remote Access → Manually specify public port → 32400.
Plex will verify it can reach itself from outside. Once it shows a green checkmark and your external IP/port, remote clients will connect directly to your server. Full bandwidth, no relay tax.
If you can’t port-forward (CG-NAT, landlord’s router, etc.), a Cloudflare Tunnel proxying port 32400 is a reasonable alternative. Plex’s direct connections will use that tunnel instead of the relay.
Bandwidth requirements for remote access
| Quality | Bitrate needed |
|---|---|
| 720p | 4 Mbps |
| 1080p | 8-20 Mbps |
| 4K | 25-80 Mbps |
Multiply by number of concurrent remote streams. If your upload is 50 Mbps, two 4K direct play streams is pushing it.
Useful PLEX_PREFERENCE Environment Variables
Plex’s Docker image supports environment variables to pre-configure preferences without touching the UI:
environment:
# Transcoder settings
- PLEX_PREFERENCE_1=HardwareAcceleratedCodecs=1
- PLEX_PREFERENCE_2=TranscoderH264BackgroundPreset=fast
- PLEX_PREFERENCE_3=TranscoderQuality=2
# Library scanning
- PLEX_PREFERENCE_4=FSEventLibraryUpdatesEnabled=1
- PLEX_PREFERENCE_5=FSEventLibraryPartialScanEnabled=1
# Network
- PLEX_PREFERENCE_6=allowedNetworks=192.168.1.0/24
- PLEX_PREFERENCE_7=LanNetworksBandwidth=192.168.1.0/24
The LanNetworksBandwidth setting is important — it tells Plex which networks to treat as high-bandwidth local connections. Without it, a device on your LAN that connects via hostname or VPN IP might get treated as a remote (low bitrate) connection.
Library Scan Optimization
Default Plex scans are fine for small libraries. For 10,000+ items:
- Enable partial scans (Settings → Library) — only scans recently changed folders
- Set a reasonable scan interval — hourly is fine, every 5 minutes is overkill
- Use inotify (Linux) for filesystem event-based scanning — Plex picks up new files instantly without full scans
# Check your inotify watch limit (Plex needs one per directory)
cat /proc/sys/fs/inotify/max_user_watches
# Increase if needed (add to /etc/sysctl.conf)
fs.inotify.max_user_watches=524288
sudo sysctl -p
Metadata Agent Tuning
Plex’s automatic metadata is convenient but can cause issues:
- Disable “Allow automatic photo tags” unless you specifically want face recognition on your photos
- Lock metadata on movies you’ve manually edited to prevent Plex from overwriting your changes
- Set agent language to match your preferred metadata source locale
- For anime, use the Hama agent (community) instead of the default — it maps AniDB/TheTVDB better
Plex vs Jellyfin: The Honest Take
Since we’re optimizing Plex, worth addressing the elephant: should you just use Jellyfin?
Choose Plex if:
- You want the most polished client apps (especially TV apps)
- You have users who are not technically inclined — Plex’s setup experience is smoother
- You care about the Plex ecosystem (Live TV, Tidal, watchlist features)
- You’re already paying for Plex Pass
Choose Jellyfin if:
- You refuse to pay for hardware transcoding features (Jellyfin is 100% free)
- You want full control over your metadata and no “phoning home” to Plex servers
- You primarily use web browsers or HTPC — Jellyfin’s web UI is excellent
- You’re on ARM hardware (Raspberry Pi, etc.) — Jellyfin’s resource usage is lower
The honest answer: both are good now. Plex has the edge on client polish; Jellyfin has the edge on being free and self-contained. If you’re starting fresh in 2024, seriously consider Jellyfin. If you already have Plex and it’s working, tune it properly before jumping ship.
One thing that trips people up switching: Plex and Jellyfin both want to be the only thing touching your media. Pick one as primary. Running both simultaneously on the same library is a path to metadata chaos.