Advanced Plex Configuration on Linux


Advanced Plex Configuration on Linux

Elevate your Plex server with advanced Linux configurations, Docker deployments, and automation.

Docker Deployment

Basic Docker Setup

# Pull official Plex image
docker pull plexinc/pms-docker

# Run Plex container
docker run -d \
  --name plex \
  --network=host \
  -e TZ="America/New_York" \
  -e PLEX_CLAIM="claim-xxxxxxxxxxxx" \
  -v /path/to/config:/config \
  -v /path/to/transcode:/transcode \
  -v /path/to/media:/data \
  plexinc/pms-docker

Docker Compose

Create docker-compose.yml:

version: '3.8'

services:
  plex:
    image: plexinc/pms-docker:latest
    container_name: plex
    restart: unless-stopped
    network_mode: host
    environment:
      - TZ=America/New_York
      - PLEX_CLAIM=claim-xxxxxxxxxxxx
      - PLEX_UID=1000
      - PLEX_GID=1000
    volumes:
      - ./config:/config
      - ./transcode:/transcode
      - /mnt/media/movies:/data/movies
      - /mnt/media/tv:/data/tv
      - /mnt/media/music:/data/music
    devices:
      - /dev/dri:/dev/dri  # Intel Quick Sync
# Start with Docker Compose
docker compose up -d

# View logs
docker compose logs -f plex

# Update Plex
docker compose pull && docker compose up -d

Hardware Transcoding in Docker

# NVIDIA GPU
services:
  plex:
    # ... other config ...
    runtime: nvidia
    environment:
      - NVIDIA_VISIBLE_DEVICES=all
      - NVIDIA_DRIVER_CAPABILITIES=compute,video,utility

# Intel Quick Sync
services:
  plex:
    # ... other config ...
    devices:
      - /dev/dri:/dev/dri

Systemd Service Management

Custom Systemd Service

sudo nano /etc/systemd/system/plexmediaserver.service
[Unit]
Description=Plex Media Server
After=network-online.target

[Service]
Type=simple
User=plex
Group=plex
ExecStartPre=/bin/sleep 10
ExecStart=/usr/lib/plexmediaserver/Plex\ Media\ Server
ExecStop=/bin/kill -SIGTERM $MAINPID
Restart=on-failure
RestartSec=5
Environment="PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR=/var/lib/plexmediaserver/Library/Application Support"
Environment="PLEX_MEDIA_SERVER_HOME=/usr/lib/plexmediaserver"
Environment="PLEX_MEDIA_SERVER_MAX_PLUGIN_PROCS=6"
Environment="PLEX_MEDIA_SERVER_INFO_DEVICE=PC"
Environment="PLEX_MEDIA_SERVER_INFO_VENDOR=Linux"

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable plexmediaserver
sudo systemctl start plexmediaserver

Service Management Commands

# Status and control
sudo systemctl status plexmediaserver
sudo systemctl restart plexmediaserver
sudo systemctl stop plexmediaserver

# View logs
sudo journalctl -u plexmediaserver -f
sudo journalctl -u plexmediaserver --since "1 hour ago"

Database Management

Locate Database

# Default locations
ls -la "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases/"

# Docker location
ls -la /path/to/config/Library/Application\ Support/Plex\ Media\ Server/Plug-in\ Support/Databases/

Backup Script

#!/bin/bash
# /usr/local/bin/plex-backup.sh

PLEX_DB="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases"
BACKUP_DIR="/backup/plex"
DATE=$(date +%Y%m%d_%H%M%S)
RETENTION_DAYS=30

# Create backup directory
mkdir -p "$BACKUP_DIR"

# Stop Plex for clean backup
sudo systemctl stop plexmediaserver
sleep 5

# Backup database
cp "$PLEX_DB/com.plexapp.plugins.library.db" "$BACKUP_DIR/library_$DATE.db"
cp "$PLEX_DB/com.plexapp.plugins.library.blobs.db" "$BACKUP_DIR/blobs_$DATE.db"

# Backup preferences
cp "/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Preferences.xml" "$BACKUP_DIR/Preferences_$DATE.xml"

# Start Plex
sudo systemctl start plexmediaserver

# Compress backups
tar -czf "$BACKUP_DIR/plex_backup_$DATE.tar.gz" -C "$BACKUP_DIR" \
    "library_$DATE.db" "blobs_$DATE.db" "Preferences_$DATE.xml"

# Remove uncompressed files
rm "$BACKUP_DIR/library_$DATE.db" "$BACKUP_DIR/blobs_$DATE.db" "$BACKUP_DIR/Preferences_$DATE.xml"

# Remove old backups
find "$BACKUP_DIR" -name "plex_backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete

echo "Backup completed: $BACKUP_DIR/plex_backup_$DATE.tar.gz"

Database Optimization

#!/bin/bash
# /usr/local/bin/plex-optimize.sh

PLEX_DB="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Plug-in Support/Databases"

# Stop Plex
sudo systemctl stop plexmediaserver
sleep 5

# Optimize main database
sqlite3 "$PLEX_DB/com.plexapp.plugins.library.db" "VACUUM;"
sqlite3 "$PLEX_DB/com.plexapp.plugins.library.db" "REINDEX;"

# Optimize blobs database
sqlite3 "$PLEX_DB/com.plexapp.plugins.library.blobs.db" "VACUUM;"

# Start Plex
sudo systemctl start plexmediaserver

echo "Database optimization completed"

Automation with Scripts

Library Scan Script

#!/bin/bash
# /usr/local/bin/plex-scan.sh

PLEX_URL="http://localhost:32400"
PLEX_TOKEN="your-token-here"

# Scan all libraries
curl -s "$PLEX_URL/library/sections/all/refresh?X-Plex-Token=$PLEX_TOKEN"

# Or scan specific library (get section ID from API)
# curl -s "$PLEX_URL/library/sections/1/refresh?X-Plex-Token=$PLEX_TOKEN"

Cron Jobs

# Edit crontab
crontab -e
# Daily library scan at 4 AM
0 4 * * * /usr/local/bin/plex-scan.sh >> /var/log/plex-scan.log 2>&1

# Weekly backup at 3 AM Sunday
0 3 * * 0 /usr/local/bin/plex-backup.sh >> /var/log/plex-backup.log 2>&1

# Monthly database optimization at 2 AM, 1st of month
0 2 1 * * /usr/local/bin/plex-optimize.sh >> /var/log/plex-optimize.log 2>&1

Tautulli Monitoring

Docker Installation

# Add to docker-compose.yml
tautulli:
  image: tautulli/tautulli:latest
  container_name: tautulli
  restart: unless-stopped
  ports:
    - "8181:8181"
  environment:
    - TZ=America/New_York
    - PUID=1000
    - PGID=1000
  volumes:
    - ./tautulli:/config

Native Installation

# Install dependencies
sudo apt install python3 python3-pip git

# Clone Tautulli
git clone https://github.com/Tautulli/Tautulli.git /opt/tautulli

# Create service
sudo nano /etc/systemd/system/tautulli.service
[Unit]
Description=Tautulli
After=network.target

[Service]
Type=simple
User=plex
ExecStart=/usr/bin/python3 /opt/tautulli/Tautulli.py --datadir /opt/tautulli
Restart=on-failure

[Install]
WantedBy=multi-user.target

Kometa (Plex Meta Manager)

Docker Setup

# Add to docker-compose.yml
kometa:
  image: kometateam/kometa:latest
  container_name: kometa
  restart: unless-stopped
  environment:
    - TZ=America/New_York
    - KOMETA_RUN=true
    - KOMETA_TIME=05:00
  volumes:
    - ./kometa/config:/config

Configuration

Create kometa/config/config.yml:

libraries:
  Movies:
    collection_files:
      - pmm: basic
      - pmm: imdb
    overlay_files:
      - pmm: resolution
      - pmm: audio_codec
  TV Shows:
    collection_files:
      - pmm: basic
      - pmm: imdb
    overlay_files:
      - pmm: resolution
      - pmm: status

plex:
  url: http://plex:32400
  token: YOUR_PLEX_TOKEN

tmdb:
  apikey: YOUR_TMDB_API_KEY
  language: en

ZFS Storage Configuration

Create ZFS Pool

# Create mirrored pool
sudo zpool create plex-data mirror /dev/sda /dev/sdb

# Create datasets
sudo zfs create plex-data/movies
sudo zfs create plex-data/tv
sudo zfs create plex-data/music

# Optimize for media
sudo zfs set recordsize=1M plex-data/movies
sudo zfs set recordsize=1M plex-data/tv
sudo zfs set atime=off plex-data

Snapshots for Backup

# Create snapshot
sudo zfs snapshot plex-data@backup_$(date +%Y%m%d)

# List snapshots
zfs list -t snapshot

# Automatic snapshots with zfs-auto-snapshot
sudo apt install zfs-auto-snapshot

Hardware Transcoding

Intel Quick Sync

# Check for Intel GPU
ls -la /dev/dri/

# Install drivers
sudo apt install intel-media-va-driver vainfo

# Verify
vainfo

# Add plex user to video group
sudo usermod -aG video plex

NVIDIA GPU

# Install NVIDIA drivers
sudo apt install nvidia-driver-535

# Install NVENC
sudo apt install libnvidia-encode-535

# Verify
nvidia-smi

# Docker GPU support
sudo apt install nvidia-docker2
sudo systemctl restart docker

AMD GPU

# Install AMDGPU drivers
sudo apt install mesa-va-drivers vainfo

# Verify
vainfo

# Add user to video group
sudo usermod -aG video plex

Network File Systems

NFS Mount

# Install NFS client
sudo apt install nfs-common

# Create mount point
sudo mkdir -p /mnt/media

# Mount NFS share
sudo mount -t nfs nas.local:/media /mnt/media

# Add to /etc/fstab
nas.local:/media /mnt/media nfs defaults,_netdev 0 0

CIFS/SMB Mount

# Install CIFS utilities
sudo apt install cifs-utils

# Create credentials file
sudo nano /etc/samba/credentials
username=your_username
password=your_password
sudo chmod 600 /etc/samba/credentials

# Add to /etc/fstab
//nas.local/media /mnt/media cifs credentials=/etc/samba/credentials,uid=plex,gid=plex,_netdev 0 0

API Automation

Python Script

#!/usr/bin/env python3
# plex-manager.py

from plexapi.server import PlexServer
import os

PLEX_URL = os.getenv('PLEX_URL', 'http://localhost:32400')
PLEX_TOKEN = os.getenv('PLEX_TOKEN')

plex = PlexServer(PLEX_URL, PLEX_TOKEN)

def list_libraries():
    for section in plex.library.sections():
        print(f"{section.key}: {section.title} ({section.type}) - {section.totalSize} items")

def refresh_library(name):
    section = plex.library.section(name)
    section.refresh()
    print(f"Refreshing {name}...")

def search(query):
    results = plex.search(query)
    for item in results:
        print(f"{item.type}: {item.title}")

if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1:
        if sys.argv[1] == "list":
            list_libraries()
        elif sys.argv[1] == "refresh" and len(sys.argv) > 2:
            refresh_library(sys.argv[2])
        elif sys.argv[1] == "search" and len(sys.argv) > 2:
            search(sys.argv[2])
    else:
        list_libraries()
pip3 install plexapi
export PLEX_TOKEN="your-token"
python3 plex-manager.py list
python3 plex-manager.py refresh Movies
python3 plex-manager.py search "inception"

Monitoring Stack

Prometheus + Grafana

# docker-compose.monitoring.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    volumes:
      - grafana-data:/var/lib/grafana

  plex-exporter:
    image: granra/plex_exporter:latest
    container_name: plex-exporter
    environment:
      - PLEX_SERVER=http://plex:32400
      - PLEX_TOKEN=your-token
    ports:
      - "9594:9594"

volumes:
  grafana-data:

Security Hardening

Fail2ban Configuration

# Create Plex filter
sudo nano /etc/fail2ban/filter.d/plex.conf
[Definition]
failregex = .*\[Auth\].*Failed.*<HOST>.*
ignoreregex =
# Add jail
sudo nano /etc/fail2ban/jail.d/plex.conf
[plex]
enabled = true
port = 32400
filter = plex
logpath = /var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Logs/Plex Media Server.log
maxretry = 5
bantime = 3600
findtime = 600

AppArmor Profile

sudo nano /etc/apparmor.d/usr.lib.plexmediaserver
#include <tunables/global>

/usr/lib/plexmediaserver/Plex\ Media\ Server {
  #include <abstractions/base>
  #include <abstractions/nameservice>
  
  /usr/lib/plexmediaserver/** r,
  /var/lib/plexmediaserver/** rw,
  /mnt/media/** r,
  /dev/dri/** rw,
  
  network inet stream,
  network inet dgram,
}

Congratulations! 🎉

You’ve mastered advanced Plex configuration on Linux! Your server now features:

  • ✅ Docker deployment with hardware acceleration
  • ✅ Automated backups and maintenance
  • ✅ Monitoring with Tautulli
  • ✅ Kometa for metadata management
  • ✅ Enterprise security hardening

You’re now a Plex Linux power user!