Skip to content

Instantly share code, notes, and snippets.

@pR0Ps
Last active November 28, 2024 06:15
Show Gist options
  • Save pR0Ps/92217e826bdbf7e5e65db5baf0026c23 to your computer and use it in GitHub Desktop.
Save pR0Ps/92217e826bdbf7e5e65db5baf0026c23 to your computer and use it in GitHub Desktop.
Nginx config for running a public, read-only, multi-user, account-less Plex instance
# Goals:
# - Allow access without having to deal with Plex accounts
# - Only allow read-only access (no changing tags, fixing matches, etc)
# - Don't leak information between users (what has been watched, play progress, etc)
# - Prevent users from claiming the server, changing settings, or acessing internal information
# - Allow administration of the server for people with SSH access to it
# Basic setup instructions:
# - Install Nginx on the same server as Plex and load this config file (usually just a matter of
# dropping it into `/etc/nginx/conf.d`)
# - Configure Plex to accept auth-less access from localhost (through the UI or by setting
# `allowedNetworks` in the server settings)
# - Block access to Plex for anything except localhost using `iptables` (make sure the rules
# persist across reboots!):
# ```
# iptables -A INPUT ! -i lo -p tcp --dport 32400 -j DROP
# ip6tables -A INPUT ! -i lo -p tcp --dport 32400 -j DROP
# ```
# - Visit `http://yourserver` to confirm everything works (also confirm that
# `http://yourserver:32400` _doesn't_ work)
# - Deploy it to your users (add HTTPS, some sort of access control, forward ports, etc)
# Administration
# - Forward local port `32400` to the server using SSH
# (`ssh -L 127.0.0.1:32400:127.0.0.1:32400 yourserver`)
# - Load `http://127.0.0.1:32400` in a browser and administrate away
# Should work for all recent versions of the Plex server (API doesn't seem to change much)
# Latest confirmed working version: 1.41.2.9200
upstream plex {
server 127.0.0.1:32400;
}
server {
listen 80;
listen [::]:80;
# Make Plex think everything is coming from localhost
# This bypasses IP/domain checks and login redirection
proxy_set_header Host "127.0.0.1";
proxy_set_header Referer "http://127.0.0.1";
proxy_set_header Origin "http://127.0.0.1";
proxy_set_header X-Real-IP "127.0.0.1";
proxy_set_header X-Forwarded-For "127.0.0.1";
# Prevent Plex from responding to requests with compressed data as this would prevent the
# inline modifications to the responses from working.
proxy_set_header Accept-Encoding "";
# Use a CSP to prevent the browser from loading any external content (*.plex.tv, analytics, etc.)
add_header Content-Security-Policy "default-src 'self' 'unsafe-inline' data: blob:";
# Default to only allowing GET requests to Plex.
# (prevents the majority of ways of changing the server's state)
location / {
if ($request_method != "GET") {
return 403;
}
# Rewrite the bare domain to the web interface (unless it's an API call)
set $rewrite 1;
if ($arg_X-Plex-Client-Identifier != '') {
set $rewrite 0;
}
if ($http_x_plex_client_identifier != '') {
set $rewrite 0;
}
if ($rewrite = 1){
rewrite ^/$ $scheme://$http_host/web/index.html redirect;
}
# Rewrite the "myPlexSigninState" key of API responses to tell the frontend that the
# server is claimed, preventing the "server is unclaimed and not secure" warning
# from showing up. This key is returned in requests to both `/` and
# `/media/providers`
sub_filter_types application/json text/xml;
sub_filter_last_modified off;
sub_filter_once on;
sub_filter '"myPlexSigninState":"none"' '"myPlexSigninState":"ok"'; # JSON
sub_filter 'myPlexSigninState="none"' 'myPlexSigninState="ok"'; # XML
proxy_pass http://plex;
}
# Allow GET/POST/PUT/DELETE requests to the playQueues endpoint.
# This allows users full control over their individual play queues.
location /playQueues {
proxy_pass http://plex;
}
# Allowing PUT requests to the /library/parts endpoint allows enabling
# subtitles. Unfortunately this setting is persisted different sessions
# so one user changing the setting affects others. It is therefore
# disabled by default.
#location /library/parts/ {
# proxy_pass http://plex;
#}
#####
# Disable a bunch of endpoints that use GET requests to modify things or return sensitive
# information
#####
# Prevent all websocket traffic as it's not required and can return data like server logs
location /:/websockets/ {
return 403;
}
# Disable claiming the server or changing the settings
location /myplex {
return 403;
}
# Disable access to server/library preferences
location ~* ^/(.+/)?prefs {
return 403;
}
# Disable marking media as played
location ~* ^/:/(un)?scrobble {
return 403;
}
# Disable saving of progress in stream
location ~* ^/:/(timeline|progress) {
return 403;
}
# Disable emptying the trash or starting a manual rescan
location ~* ^/library/sections/.+/(refresh|emptyTrash) {
return 403;
}
# Disable access to the file browser
location /services/browse {
return 403;
}
# Disable access to currently-running activities
location /activities {
return 403;
}
# Disable access to account information
location /accounts {
return 403;
}
# Disable access to device information
location /devices {
return 403;
}
# Disable access to client information
location /clients {
return 403;
}
# Disable access to server status
location /status {
return 403;
}
# Disable access to update information
location /updater {
return 403;
}
# Disable generating access tokens for the server
location /security {
return 403;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment