11 KiB
name, description, version, author, license, platforms, metadata, related_skills
| name | description | version | author | license | platforms | metadata | related_skills | |||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| plex-setup | Deploy and configure Plex Media Server on a self-hosted Linux server — Docker, GPU hardware transcoding, network configuration, media library management, and troubleshooting. | 1.1.0 | Hermes Agent | MIT |
|
|
|
Plex Media Server Setup
Deploy and manage Plex Media Server via Docker on a self-hosted Linux server. Covers first-run setup, GPU hardware transcoding, network configuration, media library management, sonic analysis, Plex API interaction, and troubleshooting.
When to Use
- User asks to set up Plex on their homelab/server
- User wants hardware-accelerated transcoding (NVIDIA, Intel QuickSync)
- User wants to add media drives to an existing Plex container
- User asks about sonic analysis, Plexamp DJ, or "sonically similar" features
- User needs to query or manage Plex programmatically via API
- User is migrating Plex to a new server
Prerequisites
- Docker + docker-compose-v2 installed
- NVIDIA driver installed (for NVIDIA GPU transcoding) OR Intel GPU for QuickSync
- nvidia-container-toolkit configured (for NVIDIA GPUs)
- Plex account and an active Plex Pass (for hardware transcoding)
Setup Steps
1. Create directory structure
mkdir -p ~/docker/plex/config
config/— Persistent Plex data (database, metadata, preferences)
2. Create docker-compose.yml
services:
plex:
image: plexinc/pms-docker:latest
container_name: plex
network_mode: host
environment:
- TZ=America/New_York
- PLEX_CLAIM=claim-<your-claim-token>
- ADVERTISE_IP=http://<server-lan-ip>:32400/
volumes:
- /home/ray/docker/plex/config:/config
- /dev/shm:/transcode
devices:
- /dev/dri:/dev/dri
restart: unless-stopped
Key configuration details:
network_mode: host— Required for DLNA/GDM discovery, remote access, and automatic local network detection. Without host mode, Plex can't broadcast its presence on the LAN.PLEX_CLAIM— One-time token from https://plex.tv/claim. Expires ~5 minutes after generation. Set it, start the container once, then remove it (optional but recommended after first run).ADVERTISE_IP— Must be the server's actual LAN IP (check withip -4 addr show | grep -oP '(?<=inet\s)\d+\.\d+\.\d+\.\d+' | grep -v 127.0.0.1). Required for proper remote access configuration. DO NOT guess this — verify the IP first./dev/dri— Device passthrough for hardware transcoding. Works for both NVIDIA and Intel GPUs. NVIDIA also needs thenvidiaDocker runtime in some configurations, but/dev/drialone covers VA-API/NVDEC for Plex./dev/shm:/transcode— RAM-backed transcode directory. Prevents SSD wear from heavy transcoding and improves performance. Ensure the server has enough RAM (minimum 2GB free for 4K transcodes).
3. Get a claim token and start
- Visit https://plex.tv/claim and copy the token (expires in ~5 minutes)
- Add
PLEX_CLAIM=claim-<token>to the compose file - Start the container:
cd ~/docker/plex && docker compose up -d - Verify it's healthy:
docker ps --filter name=plex docker logs plex | tail -10 - Look for "Token obtained successfully" in logs — confirms the server is linked to your Plex account
4. Access and configure
Open http://<server-ip>:32400/web in a browser. The server should appear as claimed and ready. If it doesn't automatically detect:
- Check
ADVERTISE_IPis correct - Restart the container with updated config
5. Add media libraries (after first run)
Once the server is running and claimed, add media mounts as volumes. Do this after the first run — get the server healthy and accessible first, then add media:
volumes:
- /home/ray/docker/plex/config:/config
- /dev/shm:/transcode
- /mnt/media/Videos:/data/media/Movies:ro
- /mnt/media/Music:/data/media/Music:ro
- /mnt/wd-passport/Videos:/data/media/WDVideos:ro
Pitfall: Binding mount paths into /data/media/ is convention, not requirement. Plex lets you point at any path inside the container. Use whatever layout makes sense, then add libraries via the Plex web UI pointing at the container paths.
Recreate the container to apply the new volume mounts (restart won't pick them up):
docker compose up -d plex
Why: docker compose restart reuses the existing container config — new volume mounts won't appear. up -d recreates with the updated compose file, which is required for volume, device, or environment changes.
6. Verify hardware transcoding
- Play a media file that requires transcoding (high-bitrate 4K, or audio format the client doesn't support)
- Check Plex Dashboard (web UI top-right activity icon) or:
# In the Plex logs docker logs plex 2>&1 | grep -i "hwaccel\|transcode\|nvidia\|nvdec" - On a successful HW transcode, you should see lines indicating NVDEC/NVENC or VA-API usage
Pitfalls
PLEX_CLAIMexpired — The token is only valid for ~5 minutes. If you didn't start the container in time, removePLEX_CLAIMfrom the compose, restart, and the server remains unclaimed. To re-claim: generate a new token, re-add it, rundocker compose up -d(NOT restart —restartdoesn't re-read env vars, onlyup -ddoes), then remove the token after success.ADVERTISE_IPwrong — If you guess the IP, remote access and local discovery will fail. Always checkip -4 addr showand set it to the correct LAN IP before first start.libusb_init failedin logs — Harmless. Means no USB TV tuner is attached. Ignore it.chown: missing operand after 'plex:plex'in logs — Cosmetic during first init. Harmless.- Hardware transcoding not working — Check that
/dev/driis accessible inside the container:docker exec plex ls -la /dev/dri. If the device doesn't exist, verify NVIDIA driver is installed and the container was created with--device /dev/dri. For NVIDIA specifically, you may also needruntime: nvidiain the compose or--gpus allondocker run. - Plex not showing on local network — Host network mode usually fixes this. If still not visible, check firewall rules (ufw/iptables blocking UDP 1900 for SSDP).
- Media mount paths — Use
:ro(read-only) for all media mounts. Plex only reads from these directories; write access is unnecessary and risks accidental file modification. docker compose restartvsup -d—compose restartreuses the existing container config and only restarts the process.compose up -drecreates the container with any config changes. Useup -dwhen you changeenvironment,devices, orvolumes; userestartfor a simple process restart.- Plexamp DJ blocked after sonic analysis — Even with completed analysis, Plexamp DJ features may still show "Requires Sonic Analysis". Top causes: (1)
MusicAnalysisBehaviorserver pref ismanualinstead ofscheduled— Plexamp reads this server-level flag and blocks DJ when it's notscheduled. Fix:PUT /:/prefs?MusicAnalysisBehavior=scheduled. (2) Plexamp cached old server state — force-quit and reopen. (3) Sonic analysis indexes need reload — restart the Plex container. Seereferences/plex-management.mdfor full troubleshooting. - Plex API token mangled by bash shell — Plex tokens like
fjCWcQF_trzJHgYKhRXVcontain underscores and other chars that bash may mangle in shell string expansion. Ifcurl -s "http://...?X-Plex-Token=$TOKEN"returns 401 but the token is correct, the shell is the culprit. Use Python urllib instead: read the token withxml.etree.ElementTree, build the URL withurllib.request.Request, and the token passes through unmolested. Thecurlcommand works fine when the token is copied literally — the problem is bash variable interpolation, not the API itself. - Compilation folders showing as "Various Artists" — When Plex scans a parent folder containing multiple compilation subfolders, it can cross-contaminate album grouping even with
respectTags=true. Fix: add each subfolder as an individual library location instead of the parent. Process: (1) Insert rows intosection_locationstable in the Plex SQLite DB (com.plexapp.plugins.library.db) withlibrary_section_idandroot_pathfor each subfolder. (2) Delete the old parent location row. (3) Restart Plex container and trigger a library refresh. This isolates each compilation folder so they appear as distinct entities in Plex. Use Python + sqlite3 module (not thesqlite3CLI, which may not be installed). respectTagschange has no effect on existing items — ChangingrespectTagsfrom false→true (or vice versa) does NOT cause Plex to re-read embedded tags on already-matched albums. "Refresh Metadata" in the web UI andGET /refresh?force=1will appear to do nothing. You MUST either touch all files to update their mtime (so Plex sees them as "changed") then run a forced scan, or perform the Plex Dance (remove location→scan→empty trash→re-add location→scan) to reprocess from scratch. Seereferences/plex-management.mdfor both workflows.
Verification Checklist
- Container is
Upandhealthyindocker ps http://<server-ip>:32400/webloads the Plex web interface- Server appears as claimed (linked to Plex account)
/dev/driis accessible inside the container- Media libraries are scannable after adding mounts
- Hardware transcoding is active (check Plex Dashboard during a transcode)
- Remote access is configured (if desired)
Managing Plex After Setup
For programmatic management — API endpoints, sonic analysis, database queries, butler task scheduling, tag-based artist/album grouping, file permission troubleshooting (DOSATTRIB xattrs), and the "Various Artists" fix — see references/plex-management.md. For Plex 1.43.x --analyze-loudness regression / DJ Friendgänger blockage, see references/plex-1.43-loudness-debug.md (full investigation + diagnostic workflow).\n\nBundled scripts:\n- scripts/fix-compilation-tags.py — add compilation=1 + albumartist=Various Artists to untagged tracks (for singles/compilations that should appear as standalone entries)\n- scripts/strip-various-artists.py — REMOVE album_artist=Various Artists and empty album_artist from files so Plex uses the track-level artist tag (for tracks wrongly grouped under "Various Artists")
Covers:
- Plex HTTP API (sections, preferences, activities, tokens)
- Sonic analysis: enabling, triggering immediately, monitoring progress
- Butler scheduling and forced task execution
- Database inspection (fingerprint state, activity history)
- Common pitfalls (fpcalc myths, butler timing, progress interpretation)