KingDezigns — PLEX32 Optimization & Setup Summary

📅 June 19–20, 2026 🖥 PLEX32 — Dell Wyse 5070 ⚙️ Ubuntu 24.04 🐳 Docker Compose ☁️ Plex Media Server + Tautulli
Overview

PLEX32 was recently migrated from NAS08 to a dedicated Dell Wyse 5070 (Intel Celeron J4105, 8GB RAM) to support Plex Pass features including Sonic Radio that require x86 CPU capabilities. This session covered a full 7-step optimization of the new server — hardware transcoding, playback tuning, Tautulli setup, automated backup, scheduled maintenance, and subtitle handling.

Hardware Transcoding — Enabled Tautulli — Installed Backup — Automated SSH Keys — Configured

All 7 optimization steps completed successfully. PLEX32 is now fully configured and production-ready.

Step 1 — Hardware transcoding (Intel Quick Sync)

The J4105 has Intel Quick Sync but the Plex Docker container had no access to /dev/dri and was silently falling back to software transcoding on every stream.

1 Confirmed iGPU is exposed on the host
ls -la /dev/dri

card0 (video, GID 44) and renderD128 (render, GID 993) both present

2 Updated docker-compose.yml — added device passthrough and group_add
devices:
  - /dev/dri:/dev/dri
group_add:
  - "44"
  - "993"

Container needs both the device node and supplementary group membership to access the GPU

docker exec confirmed groups 44 and 993 in container process — /dev/dri visible inside container

3 Enabled hardware transcoding in Plex UI
Settings → Transcoder → Use hardware acceleration when available ✅
Settings → Transcoder → Use hardware-accelerated video encoding ✅

Both were already checked — confirming the settings were attempting HW transcode but failing silently due to missing device access

Dashboard showed: 4K (HEVC Main 10) (hw) / SD (HEVC) — Transcode (hw) — both sides of pipeline on GPU

4 Set transcoder temp directory
Settings → Transcoder → Transcoder temporary directory: /transcode

Was empty — Plex was writing transcode scratch files to uncontrolled location inside container filesystem

Now maps to /opt/plex/transcode on host via existing volume mount

Step 2 — Direct Play / Direct Stream tuning

Library codec analysis revealed 90 HEVC Main 10 files (~75%) and 29 H.264 files (~25%), all with AAC audio. Roku TV (Hisense 55R8BX) was tested — video Direct Streams, audio converts AAC → AC3 for HDMI passthrough.

1 Codec analysis — video
find "/mnt/plex/media/04 - Videos/Movies" \( -iname "*.mkv" -o -iname "*.mp4" \) | while read -r f; do
  ffprobe -v error -select_streams v:0 -show_entries stream=codec_name,profile \
  -of csv=p=0 "$f" 2>/dev/null
done | sort | uniq -c | sort -rn

82+8 hevc,Main 10 / 29 h264,High — library is 75% HEVC 10-bit

2 Codec analysis — audio
find ... | ffprobe ... -select_streams a:0 ... | sort | uniq -c

119 aac — 100% AAC audio across entire library. No TrueHD, no DTS. Audio will never force a transcode due to format incompatibility.

3 Live playback test on Roku
Plex Dashboard → active session while playing on Roku TV

Video: 4K (HEVC Main 10) — Direct Stream ✅ / Audio: English (AAC 5.1) → AC3 Transcode (lightweight, expected for Roku HDMI passthrough)

Result: Video never transcodes. Audio does a lightweight AAC→AC3 conversion for Roku surround output. Optimal for this setup.

Steps 3 & 4 — Sonic Radio + Tautulli

Sonic Radio was confirmed working — the whole reason for migrating to PLEX32. Opening any artist in the Music library and clicking Live Radio plays that artist then branches into similar artists using AI-driven discovery. Requires x86 CPU — confirmed working on J4105.

Tautulli was installed as a second service in the existing docker-compose.yml, running on port 8181. Connected to Plex, email notification configured for Plex server down/up alerts using existing Zoho SMTP credentials.

Tautulli added to docker-compose.yml
tautulli:
  image: lscr.io/linuxserver/tautulli:latest
  container_name: tautulli
  environment:
    - PUID=1000
    - PGID=1001
    - TZ=America/New_York
  volumes:
    - /opt/tautulli/config:/config
  ports:
    - 8181:8181
  restart: unless-stopped
Config directory
/opt/tautulli/config
Web UI
http://192.168.150.45:8181
Notification triggers set
Plex Server Down + Plex Server Back Up → email to rufus.king@kingdezigns.com
Step 5 — Automated config backup

A backup script was created to archive Plex and Tautulli configs to NAS08 via NFS every 3 days. rsync was attempted first but failed due to NFS directory scanning performance issues and permission constraints from NAS08's all_squash export. The final approach uses tar locally then a single cp to NFS.

⚠ Key issue — rsync over NFS hung indefinitely

rsync hung at "sending incremental file list" because scanning thousands of small Plex metadata files over NFS was extremely slow. Additionally NAS08's all_squash NFS export (anonuid=33/anongid=1001) prevented rufusking on PLEX32 from writing new files to the destination until directory permissions were corrected on NAS08.

sudo chown -R www-data:ncshare /export/kingdezigns-all/Docker/plex/config
sudo chmod -R 2770 /export/kingdezigns-all/Docker/plex/config

Final solution: tar to /tmp locally (no NFS), then single cp to NFS. NFS write speed confirmed at 100 MB/s. Total backup runtime ~10 minutes.

Backup script location
/usr/scripts/plex32/plex32_backup.sh
Schedule
0 2 */3 * * /usr/scripts/plex32/plex32_backup.sh    # Every 3 days at 2:00 AM
Plex archive destination (NAS08)
/export/kingdezigns-all/Docker/plex/config/backups/plex/
plex-config-YYYY-MM-DD.tar.gz    (3 copies retained)
Tautulli archive destination (NAS08)
/export/kingdezigns-all/Docker/plex/config/backups/tautulli/
tautulli-config-YYYY-MM-DD.tar.gz    (3 copies retained)
Excludes from Plex archive
Cache / Logs / Crash Reports
SMTP password file
/etc/plex32-smtp-pass    (chmod 600, owned by rufusking)
Restore procedure (run on plex32)
cd ~/docker/plex && docker compose down
cp /mnt/plex/config/backups/plex/plex-config-YYYY-MM-DD.tar.gz /tmp/
sudo rm -rf /opt/plex/config/Library
sudo tar -xzf /tmp/plex-config-YYYY-MM-DD.tar.gz -C /opt/plex
sudo chown -R rufusking:ncshare /opt/plex/config
cd ~/docker/plex && docker compose up -d
docker ps    # verify both plex and tautulli show Up
# Open http://192.168.150.45:32400/web and confirm library intact
rm /tmp/plex-config-YYYY-MM-DD.tar.gz
Remote launcher + SSH key authentication

A launcher script was created on KingDezigns001 to remotely execute PLEX32 scripts via SSH with a simple menu. SSH key authentication was configured from KingDezigns001 to all VLAN 50 servers, and from PLEX32 to NAS08, eliminating all password prompts.

Launcher script (KingDezigns001)
~/scripts/plex32_launcher.sh
Desktop shortcut (KingDezigns001)
~/Desktop/PLEX32-Launcher.desktop
Menu options
1) Update Check      → /usr/scripts/plex32/plex32_update_check.sh
2) Health Report     → /usr/scripts/plex32/plex32_health_report.sh
3) Plex32 Backup     → /usr/scripts/plex32/plex32_backup.sh
SSH keys configured (no password)
KingDezigns001 → PLEX32   (192.168.150.45)
KingDezigns001 → NAS08    (192.168.150.35)
KingDezigns001 → NAS16    (192.168.150.40)
PLEX32         → NAS08    (192.168.150.35)    # required for backup disk stats
sudo without password (plex32) — /etc/sudoers.d/rufusking-nopasswd
rufusking ALL=(ALL) NOPASSWD: /usr/bin/apt-get update, /usr/bin/fail2ban-client status, /usr/bin/fail2ban-client status sshd
Steps 6 & 7 — Scheduled maintenance & subtitle handling

Scheduled maintenance was already configured to run between 2:00 AM and 5:00 AM. The following library analysis tasks were confirmed enabled as scheduled tasks:

TaskSetting
Generate video preview thumbnailsAs a scheduled task (changed from Never)
Generate chapter image thumbnailsAs a scheduled task
Analyze audio tracks for loudnessAs a scheduled task
Generate intro video markersAs a scheduled task and when media is added
Generate credits video markersAs a scheduled task and when media is added
Analyze audio tracks for sonic featuresAs a scheduled task
Generate voice activity dataAs a scheduled task (changed from Never)

Subtitle handling: Library contains 1168 SRT (safe, no transcode) and 279 PGS image-based subtitles (burn-in forces transcode if selected). Since subtitles are used occasionally and Quick Sync handles the transcode efficiently, Option B (bulk PGS→SRT conversion) was not pursued. Subtitle Mode confirmed set to Manually selected — subtitles only appear when explicitly chosen, preventing accidental burn-in transcoding.

Lessons learned
LessonDetail
GPU device passthrough requires group membership Adding /dev/dri to Docker devices is not enough — the container process also needs supplementary groups matching the video (44) and render (993) GIDs on the host. Use group_add in docker-compose.
rsync over NFS is unreliable for large Plex configs Thousands of small metadata files cause rsync to hang indefinitely building the file list over NFS. Use tar locally then a single cp to NFS instead — much faster and more reliable.
NAS08 all_squash NFS exports require correct directory ownership Even sudo on PLEX32 cannot create files on NFS mounts with all_squash unless the destination directory on NAS08 is owned by www-data:ncshare with 2770 permissions.
Scripts running as non-root need sudo for apt-get and fail2ban-client Both commands require root access. Grant specific NOPASSWD sudo rights via /etc/sudoers.d/ rather than running the whole script as root.
SSH keys should be set up on all servers from the start Key authentication eliminates password prompts for both interactive SSH and script-to-script SSH calls (e.g. PLEX32 → NAS08 for disk stats). Generate once per machine, copy to all targets.
Hardware transcoding silently falls back without /dev/dri access Plex showed hardware transcoding as "enabled" in settings but was silently using software transcoding. Always verify with the Dashboard showing (hw) next to the codec during an active transcode.
AAC audio across the entire library is ideal TrueHD and DTS-HD MA are the common culprits that force audio transcoding on most clients. A library with 100% AAC will never trigger an audio-forced transcode regardless of client.
Network docs — items to update
ItemOld valueNew value
server_plex32.md — docker-compose.yml No devices or group_add block devices: /dev/dri + group_add: ["44","993"] + Tautulli service added
server_plex32.md — Scheduled Jobs 2 cron jobs (update check, health report) 3 cron jobs — add: 0 2 */3 * * /usr/scripts/plex32/plex32_backup.sh
server_plex32.md — new scripts section No backup script plex32_backup.sh — tar + NFS copy to NAS08, 3 copies retained, HTML email report
server_plex32.md — SSH keys Not documented PLEX32 has SSH key to NAS08 (192.168.150.35) — required for backup disk stats
server_plex32.md — sudoers Not documented /etc/sudoers.d/rufusking-nopasswd — apt-get update + fail2ban-client commands
server_plex32.md — Tautulli Not present Tautulli running on port 8181, config at /opt/tautulli/config, Plex down/up alerts active
network_index.md — KingDezigns001 tools Not documented plex32_launcher.sh at ~/scripts/ + PLEX32-Launcher.desktop on Desktop — SSH keys to all VLAN 50 servers
server_nas08.md — NFS export permissions Not documented /export/kingdezigns-all/Docker/plex/config — www-data:ncshare 2770, backups/plex and backups/tautulli subdirs created