Skip to content

Instantly share code, notes, and snippets.

@hazcod
Last active December 12, 2024 05:45
Show Gist options
  • Save hazcod/3ef10a15f52c171a7839 to your computer and use it in GitHub Desktop.
Save hazcod/3ef10a15f52c171a7839 to your computer and use it in GitHub Desktop.
Apache2 reverse proxy vhost configuration for Plex. Rerquires modules ssl, proxy, wstunnel
This current configuration is based of at least Server Version 1.16.5.1488 and Web Version: 3.108.2.
This updated config file allows the playing of trailers and TV Show theme music where as the previous one did not.
## Requirements
1. Apache version > 2.4
2. A bunch of mod's enabled (proxy, ssl, proxy_wstunnel, http, dir, env, headers, proxy_balancer, proxy_http, rewrite)
3. Protocols h2 http/1.1 needs apachectl -V 2.4.17 and higher...
## Apache .conf file
```
DEFINE plex_url 127.0.0.1
DEFINE plex_port 32400
DEFINE public_url subdomain.plex.tv
DEFINE email [email protected]
ServerTokens Prod
SSLStaplingCache "shmcb:${APACHE_LOG_DIR}/stapling-cache(150000)"
SSLSessionCache "shmcb:${APACHE_LOG_DIR}/ssl_scache(512000)"
SSLSessionCacheTimeout 300
### If you have Google's Mod PageSpeed, disable it
#ModPagespeed Off
<VirtualHost *:80>
ServerName ${public_url}
DocumentRoot /var/www/offline
ServerAdmin ${email}
RewriteEngine on
RewriteCond %{SERVER_NAME} =${public_url}
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>
<VirtualHost *:443>
ServerName ${public_url}
DocumentRoot /var/www/offline
ServerAdmin ${email}
ErrorLog ${APACHE_LOG_DIR}/${public_url}.error.log
CustomLog ${APACHE_LOG_DIR}/${public_url}.access.log combined
SSLEngine On
SSLCertificateFile /etc/letsencrypt/live/${public_url}/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/${public_url}/privkey.pem
#Include /etc/letsencrypt/options-ssl-apache.conf
### Forbid the http1.0 protocol ###
Protocols h2 http/1.1
#Options -Includes -ExecCGI
#LimitRequestBody 512000
#FileETag None
#TraceEnable off
Timeout 360
ProxyRequests Off
ProxyPreserveHost On
ProxyTimeout 600
ProxyReceiveBufferSize 4096
SSLProxyEngine On
RequestHeader set Front-End-Https "On"
ServerSignature Off
SSLCompression Off
SSLUseStapling On
SSLStaplingResponderTimeout 5
SSLStaplingReturnResponderErrors Off
SSLSessionTickets Off
RequestHeader set X-Forwarded-Proto 'https' env=HTTPS
Header always set Strict-Transport-Security "max-age=15552000; preload"
Header always set X-Content-Type-Options nosniff
Header always set X-Robots-Tag none
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Content-Security-Policy "default-src 'self' https:; font-src 'self' data: ${plex_url} ${public_url}; media-src 'self' blob: data: https: ${plex_url} ${public_url} *.plex.direct *.plex.tv plex.tv; script-src 'self' 'unsafe-inline' 'unsafe-eval' ${plex_url} ${public_url} plex.tv *.plex.tv gstatic.com *.gstatic.com *.plex.direct; style-src 'self' ${plex_url} ${public_url} *.plex.direct 'unsafe-inline'; img-src 'self' data: blob: ${plex_url} ${public_url} plex.tv *.plex.tv *.plex.direct; worker-src *; frame-src 'none'; connect-src 'self' wss: https: ${plex_url} ${public_url} plex.tv *.plex.direct *.plex.tv;"
Header always set Feature-Policy "geolocation 'self'; midi 'self'; sync-xhr 'self'; microphone 'self'; camera 'self'; magnetometer 'self'; gyroscope 'self'; speaker 'self'; fullscreen 'self'; payment 'self'"
### Use next two for very secure connections ###
SSLHonorCipherOrder On
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH
SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
### Use next two for secure connections and supports more endpoints ###
#SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:ECDHE-RSA-AES128-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA128:DHE-RSA-AES128-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-GCM-SHA128:ECDHE-RSA-AES128-SHA384:ECDHE-RSA-AES128-SHA128:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA128:DHE-RSA-AES128-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA384:AES128-GCM-SHA128:AES128-SHA128:AES128-SHA128:AES128-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4
#SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
### Actually proxy the traffic and really the only important part ###
ProxyPassMatch ^/.well-known !
ProxyPass / http://${plex_url}:${plex_port}/
ProxyPassReverse / http://${plex_url}:${plex_port}/
ProxyPass /:/ ws://${plex_url}:${plex_port}/:/
ProxyPassReverse /:/ ws://${plex_url}:${plex_port}/:/
ProxyPass /:/ wss://${plex_url}:${plex_port}/:/
ProxyPassReverse /:/ wss://${plex_url}:${plex_port}/:/
LimitRequestBody 512000
FileETag None
TraceEnable off
#Header edit Set-Cookie ^(.*)$ ;HttpOnly;Secure
Timeout 60
<Location /:/websockets/notifications>
ProxyPass wss://${plex_url}:${plex_port}/:/websockets/notifications
ProxyPassReverse wss://${plex_url}:${plex_port}/:/websockets/notifications
</Location>
<Proxy *>
Require all granted
</Proxy>
RewriteEngine on
RewriteCond %{REQUEST_URI} !^/web
RewriteCond %{HTTP:X-Plex-Device} ^$
RewriteCond %{REQUEST_METHOD} !^(OPTIONS)$
RewriteCond %{QUERY_STRING} (^|&)X-Plex-Device=(&|$) [OR]
RewriteCond %{QUERY_STRING} !(^|&)X-Plex-Device=
RewriteRule ^/$ /web/$1 [R,L]
</VirtualHost>
```
@Waindor
Copy link

Waindor commented Aug 3, 2023

Thank you for this vhost configuration! After applying this configuration, I constantly got an error in /var/log/apache2/error.log containing these two lines:
"AH00898: Error during SSL Handshake with remote server returned by /:/websockets/notifications"
"AH01097: pass request body failed to <Local Plex Server IP Address>"
In the browser console it said that it could not connect to "wss://plex.<domain>.<tld>/:/websockets/notifications?X-Plex-Token=<token>" as well.

I then figured out what to change in the configuration to fix it. These errors made me unable to see new content popping up on the dashboard after scanning libraries. I had to refresh the page to see the new content. Context menus would also stop working randomly. Here are the changes I did to fix this:

The configuration below now contains "ws" instead of "wss":
Header always set Content-Security-Policy "default-src 'self' https:; font-src 'self' data: ${plex_url} ${public_url}; media-src 'self' blob: data: https: ${plex_url} ${public_url} *.plex.direct *.plex.tv plex.tv; script-src 'self' 'unsafe-inline' 'unsafe-eval' ${plex_url} ${public_url} plex.tv *.plex.tv gstatic.com *.gstatic.com *.plex.direct; style-src 'self' ${plex_url} ${public_url} *.plex.direct 'unsafe-inline'; img-src 'self' data: blob: ${plex_url} ${public_url} plex.tv *.plex.tv *.plex.direct; worker-src *; frame-src 'none'; connect-src 'self' ws: https: ${plex_url} ${public_url} plex.tv *.plex.direct *.plex.tv;"

I have commented out these lines since I don't think they are necessary. It does not affect the problem, though:

#ProxyPass /:/ wss://${plex_url}:${plex_port}/:/
#ProxyPassReverse /:/ wss://${plex_url}:${plex_port}/:/

The two lines inside the Location directive now contains ws instead of wss:

<Location /:/websockets/notifications>
        ProxyPass ws://${plex_url}:${plex_port}/:/websockets/notifications
        ProxyPassReverse ws://${plex_url}:${plex_port}/:/websockets/notifications
</Location>

Restart Apache, and the errors should no longer appear, at least for systems with similar setup and configuration described below. Maybe someone finds this helpful.

Setup:
Debian 12
Apache 2.4.57
Plex Media Server 4.108.0
My setup uses no SSL certificate for Plex itself, only for Apache with reverse proxy.

@felmey
Copy link

felmey commented Dec 12, 2024

I'm having a strange problem with my reverse proxy... If I use a web browser on my local network, the cover art doesn't show up in Plex... If I use a browser from outside my network, the cover art displays fine. If I'm on the local network and bypass the reverse proxy and go directly to the plex server, the cover art displays. And if I use app.plex.tv from inside or outside my network, the cover art is displayed... If I use the Plex app itself, both inside and outside my local network, the cover art is displayed fine (although I had to logoff and relogin to get it to get it to display on the Shield's Plex App). Does anyone happen to have any ideas what might be going on? I've been trying to figure this out for days ... Bottom line, I'm not getting cover art on plex when using a web browser within my local network when going through the reverse proxy.

@LateWiksi
Copy link

LateWiksi commented Dec 12, 2024

I'm having a strange problem with my reverse proxy... If I use a web browser on my local network, the cover art doesn't show up in Plex... If I use a browser from outside my network, the cover art displays fine. If I'm on the local network and bypass the reverse proxy and go directly to the plex server, the cover art displays. And if I use app.plex.tv from inside or outside my network, the cover art is displayed... If I use the Plex app itself, both inside and outside my local network, the cover art is displayed fine (although I had to logoff and relogin to get it to get it to display on the Shield's Plex App). Does anyone happen to have any ideas what might be going on? I've been trying to figure this out for days ... Bottom line, I'm not getting cover art on plex when using a web browser within my local network when going through the reverse proxy.

I had similar issues. Not anymore.

Here's what I have as my Apache2 config for Plex.
Put under root domain e.g. felmey.net config. Plex is then accessible via felmey.net/plex.
Plex server IP in this config is 10.50.0.10

# Plex (Media Server)
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/plex 
RewriteCond %{REQUEST_URI} !^/plex/web
RewriteCond %{HTTP:X-Plex-Device} ^$
RewriteCond %{REQUEST_METHOD} !^(OPTIONS)$
RewriteCond %{QUERY_STRING} (^|&)X-Plex-Device=(&|$) [OR]
RewriteCond %{QUERY_STRING} !(^|&)X-Plex-Device=
RewriteRule ^/$ /plex/web/$1 [R,L]

<Location /web>
	ProxyPass https://10.50.0.10:32400/web retry=0
	ProxyPassReverse https://10.50.0.10:32400/web
	SetOutputFilter proxy-html
	ProxyHTMLURLMap https://10.50.0.10:32400/web
</Location>

RewriteRule ^/web$ /plex/web/ [R]
RewriteRule ^/web/(.*)$ /plex/web/$1 [R,L]

<Location /media>
	ProxyPass https://10.50.0.10:32400/media retry=0
	ProxyPassReverse https://10.50.0.10:32400/media
	SetOutputFilter proxy-html
	ProxyHTMLURLMap https://10.50.0.10:32400/media
</Location>
RewriteRule ^/media$ /plex/media/ [R]

<Location /plex/:>
	ProxyPass wss://10.50.0.10:32400/:
	ProxyPassReverse wss://10.50.0.10:32400/:
</Location>
RewriteRule ^/plex:$ /plex/:/ [R]

<Location /plex>
	ProxyPass https://10.50.0.10:32400 retry=0
	ProxyPassReverse https://10.50.0.10:32400
	SetOutputFilter proxy-html
	ProxyHTMLURLMap https://10.50.0.10:32400
</Location>

RewriteRule ^/plex$ /plex/ [R]
RewriteRule ^/plex/$ /plex/web/ [R]

With this config I haven't had any issues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment