Skip to content
SumGuy's Ramblings
Go back

Plex Optimization: Remote Access, Transcoding, and Taming the Beast

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:

When Plex transcodes:

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

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

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:

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

QualityBitrate needed
720p4 Mbps
1080p8-20 Mbps
4K25-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:

# 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:

Plex vs Jellyfin: The Honest Take

Since we’re optimizing Plex, worth addressing the elephant: should you just use Jellyfin?

Choose Plex if:

Choose Jellyfin if:

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.


Share this post on:

Previous Post
Docker Volumes vs Bind Mounts: Where Your Data Actually Lives
Next Post
Home Assistant + Node-RED: Automate Your Home Without Losing Your Mind