Last active
July 29, 2021 03:07
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 | |
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 ""; | |
# 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; | |
} | |
# Modify the JavaScript frontend | |
location /web/js/ { | |
sub_filter_types text/javascript; | |
sub_filter_last_modified off; | |
sub_filter_once off; | |
# Rewrite the Plex auth URL to prevent the frontend from redirecting the user to | |
# app.plex.tv to sign in. Makes all these requests just load the main page instead. | |
sub_filter 'https://app.plex.tv/auth' '$scheme://$http_host/'; | |
# Cause the request to the privacy API endpoint on plex.tv to fail. This prevents | |
# the frontend from retriving the domain of the analytics server, stopping analytics | |
# from being sent to it. | |
sub_filter '/user/privacy' '/'; | |
# Prevent the frontend from initiating any websocket connections. Websockets aren't | |
# required for anything and bypass this proxy and it's modifications. | |
# TODO: This seems fragile and could break in an update - find a better way | |
sub_filter '!!window.WebSocket' '!!0'; | |
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 | |
##### | |
# 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