Advanced

How to Set Up a Plex Reverse Proxy with Nginx

Configure Nginx as a reverse proxy for Plex with SSL/TLS, custom domain, WebSocket proxying, and security headers.

Running Plex behind a reverse proxy gives you control over how your media server faces the internet. Instead of exposing port 32400 directly, you can serve Plex through a custom domain with a valid SSL certificate, add security headers, and consolidate multiple services behind a single IP address. Nginx is the most popular choice for this role, and configuring it for Plex is straightforward once you understand the handful of quirks involved.

Why Use a Reverse Proxy for Plex

A reverse proxy sits between the internet and your Plex server, accepting incoming connections and forwarding them to Plex on the backend. This architecture offers several practical advantages:

Prerequisites

Before you begin, make sure you have the following in place:

Step 1 -- Configure Plex for Reverse Proxy

Before touching Nginx, you need to tell Plex that it will be accessed through a proxy. Open the Plex web interface, go to Settings > Network, and configure two settings:

Custom server access URLs: Add https://plex.example.com:443 to the list. This tells Plex to advertise this URL to clients so they can find your server through the proxy.

Treat these IP ranges as local (LAN Networks): Add the IP of your Nginx server (e.g., 172.17.0.0/16 for Docker, or 127.0.0.1/32 if Nginx runs on the same machine). This ensures Plex treats proxied connections as local, avoiding unnecessary bandwidth restrictions and enabling full-quality streaming.

Step 2 -- Obtain an SSL Certificate

Run Certbot to obtain a free SSL certificate from Let's Encrypt:

sudo certbot certonly --nginx -d plex.example.com

Certbot will verify domain ownership, generate the certificate, and save it to /etc/letsencrypt/live/plex.example.com/. Certificates renew automatically via a systemd timer. You can verify the renewal process works with sudo certbot renew --dry-run.

Step 3 -- Write the Nginx Configuration

Create a new site configuration file at /etc/nginx/sites-available/plex.conf. The following configuration handles HTTPS termination, WebSocket proxying (required for Plex Companion and some client communications), and security headers:

upstream plex_backend {
    server 127.0.0.1:32400;
    keepalive 32;
}

server {
    listen 80;
    server_name plex.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name plex.example.com;

    ssl_certificate /etc/letsencrypt/live/plex.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/plex.example.com/privkey.pem;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 1d;

    # Security headers
    add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
    add_header X-Content-Type-Options "nosniff" always;
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header Referrer-Policy "no-referrer-when-downgrade" always;

    # Large uploads (for camera upload feature)
    client_max_body_size 100M;

    # Disable buffering for streaming
    proxy_buffering off;

    location / {
        proxy_pass http://plex_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Timeouts for long-lived connections
        proxy_read_timeout 86400s;
        proxy_send_timeout 86400s;
    }
}

Step 4 -- Enable the Site and Test

Symlink the configuration into sites-enabled, test the syntax, and reload Nginx:

sudo ln -s /etc/nginx/sites-available/plex.conf /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

If nginx -t reports no errors, navigate to https://plex.example.com in your browser. You should see the Plex web interface served over HTTPS with a valid certificate.

WebSocket Proxying -- Why It Matters

Plex uses WebSocket connections for real-time features like Plex Companion (controlling playback from your phone), server notifications, and session updates. Without proper WebSocket proxying, these features will silently fail. The key lines in the configuration above are the Upgrade and Connection headers, along with proxy_http_version 1.1. If you omit these, Plex will appear to work but Companion will not function and the dashboard will not update in real time.

Security Hardening

The configuration above includes essential security headers, but you can go further depending on your threat model:

Rate Limiting

Add a rate limiting zone to prevent brute-force attacks against the Plex login:

# In the http block of nginx.conf
limit_req_zone $binary_remote_addr zone=plex_limit:10m rate=5r/s;

# In the server block
location / {
    limit_req zone=plex_limit burst=20 nodelay;
    # ... rest of proxy config
}

Geo-Blocking

If you only share your server with people in specific countries, you can use the Nginx GeoIP2 module to block all other traffic at the proxy level, before it reaches Plex.

Fail2Ban Integration

Configure Fail2Ban to monitor the Nginx access log for repeated failed authentication attempts and automatically ban offending IP addresses. This adds an active defense layer beyond rate limiting.

Common Issues and Solutions

Clients cannot find the server remotely. Ensure you have added the custom access URL in Plex settings and that Plex's own remote access is disabled (since Nginx now handles external access). Some clients may need to be signed out and back in to pick up the new URL.

Streaming works but is slow. Check that proxy_buffering off is set. Without this, Nginx will attempt to buffer the entire stream before forwarding it, which causes massive delays for large files.

502 Bad Gateway errors. Verify that Plex is running and listening on port 32400. Check sudo systemctl status plexmediaserver and ensure no firewall rules block localhost connections.

Certificate renewal fails. Make sure port 80 is accessible for the Let's Encrypt HTTP-01 challenge. The redirect from port 80 to 443 should not interfere with Certbot because it handles the .well-known/acme-challenge path before the redirect fires.

Docker Considerations

If Plex runs in Docker, replace 127.0.0.1:32400 in the upstream block with the container's IP or Docker network hostname. When using Docker Compose, both containers can share a network, and you can reference Plex by its service name (e.g., plex:32400). Ensure the Nginx container exposes ports 80 and 443, while the Plex container does not need to expose port 32400 to the host at all.

A reverse proxy is one of those configurations that takes 20 minutes to set up but pays dividends for years. Your Plex server gets a clean URL, a trusted certificate, better security, and the flexibility to grow alongside other self-hosted services on your network.

Phlix -- The Photo Browser for Plex

If you use Plex for photos, Phlix gives you a chronological timeline, year scrubber, 4K AirPlay slideshows, and offline downloads. Free to browse, Pro from $6.99/yr.

Download Phlix Free

iOS 17+ · Works with any Plex Media Server

Related Articles