# Working apache reverse proxy configuration for Plex!

**URL:** <https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126>\
**Category:** General Discussions\
**Created:** [December 29, 2015, 7:55am UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126 "2015-12-29T07:55:16Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![hazcod](https://sea1.discourse-cdn.com/plex/user_avatar/forums.plex.tv/hazcod/32/84744_2.png) [@hazcod](https://forums.plex.tv/u/hazcod)\
**Post date:** [December 29, 2015, 7:55am UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/1 "2015-12-29T07:55:16Z")

</div>

I tried to setup plex (with docker) behind a reverse proxy, so Plex is only accessible from [https://plex.website.com/](https://plex.website.com/) and with my custom certificate. I had some troubles along the way, but in the end, I made it work!

Just wanted to share for you all. 🙂  
A big shout-out to rcombs for letting me know [Plex.tv](http://Plex.tv) does an OPTIONS on your web server.

Link: [Apache2 reverse proxy vhost configuration for Plex. Rerquires modules ssl, proxy, wstunnel · GitHub](https://gist.github.com/HazCod/3ef10a15f52c171a7839)  
(The link will typically have the latest version.)

`  
ServerSignature Off  
ServerTokens Prod

\<VirtualHost \*:80\>  
ServerName [plex.website.com](http://plex.website.com)

# This VirtualHost redirects everything to HTTPS on port 443.

RewriteEngine On  
RewriteCond %{HTTPS} off  
RewriteRule (.\*) https://%{HTTP\_HOST}%{REQUEST\_URI}

\<VirtualHost \*:443\>  
ServerName [plex.website.com](http://plex.website.com)  
ServerAlias “”  
Options -Includes -ExecCGI

RewriteEngine On  
RewriteCond %{THE\_REQUEST} !HTTP/1.1$  
RewriteRule .\* - [F]

LimitRequestBody 512000  
SSLEngine On  
SSLCertificateFile /etc/apache2/ssl/cert.pem  
SSLCertificateKeyFile /etc/apache2/ssl/privkey.pem  
SSLProtocol +TLSv1.2

Header always set Strict-Transport-Security “max-age=63072000; includeSubdomains; preload”  
Header always set X-Frame-Options DENY  
FileETag None  
TraceEnable off  
Header edit Set-Cookie ^(.\*)$ ;HttpOnly;Secure  
Header set X-XSS-Protection “1; mode=block”  
Timeout 60

```
<Location /:/websockets/notifications>
    ProxyPass wss://plex:32400/:/websockets/notifications #plex here is resolved to my plex container
    ProxyPassReverse wss://plex:32400/:/websockets/notifications #plex here is resolved to my plex container
</Location>

```

\<Proxy \*\>  
Order deny,allow  
Allow from all

```
ProxyRequests Off
ProxyPreserveHost On
ProxyPass / http://plex:32400/ #plex here is resolved to my plex container
ProxyPassReverse / http://plex:32400/ #plex here is resolved to my plex container

RewriteEngine on
RewriteCond %{REQUEST_URI} !^/web
RewriteCond %{HTTP:X-Plex-Device} ^$
RewriteCond %{REQUEST_METHOD} !^(OPTIONS)$
RewriteRule ^/$ /web/$1 [R,L]

```

`

---

<div class="post-metadata">

**Author:** ![Deddryk](https://avatars.discourse-cdn.com/v4/letter/d/9fc348/32.png) [@Deddryk](https://forums.plex.tv/u/Deddryk)\
**Post date:** [January 6, 2016, 10:34pm UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/2 "2016-01-06T22:34:48Z")

</div>

Very cool. I have a few questions though. Doesn’t this config open up your server to the entire world? (How) Are you doing access control?

Finally, I assume that this setup only works with a browser and not any plex apps, correct?

---

<div class="post-metadata">

**Author:** ![matteos1](https://sea1.discourse-cdn.com/plex/user_avatar/forums.plex.tv/matteos1/32/112702_2.png) [@matteos1](https://forums.plex.tv/u/matteos1)\
**Post date:** [January 22, 2016, 10:46am UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/3 "2016-01-22T10:46:05Z")

</div>

could you explain the procedure to implement this in apache?

---

<div class="post-metadata">

**Author:** ![Deddryk](https://avatars.discourse-cdn.com/v4/letter/d/9fc348/32.png) [@Deddryk](https://forums.plex.tv/u/Deddryk)\
**Post date:** [January 26, 2016, 7:09pm UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/4 "2016-01-26T19:09:35Z")

</div>

matteos, it depends on your operating system but most apache setups have something along the lines of Include \*.conf in some directory. In debian like systems (ubuntu, mint) you can add a new file called maybe plex.conf to /etc/apache2/sites-available/ and then run a2ensite plex. On redhat like systems (fedora, centos) just add that file to /etc/httpd/conf.d/. On windows I’m not sure, it would depend where you got it from, but likely there is a folder like c:\apache\conf.d or something similar.

---

<div class="post-metadata">

**Author:** ![petwri](https://avatars.discourse-cdn.com/v4/letter/p/3e96dc/32.png) [@petwri](https://forums.plex.tv/u/petwri)\
**Post date:** [February 1, 2017, 9:38pm UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/5 "2017-02-01T21:38:31Z")

</div>

@hazcod I tried your config, but it doesn’t seem to work. When going to [plex.mysite.com](http://plex.mysite.com), I can login, but afterwards my server never shows up. Only works on the same network. Any ideas?

---

<div class="post-metadata">

**Author:** ![badrobot](https://sea1.discourse-cdn.com/plex/user_avatar/forums.plex.tv/badrobot/32/7727_2.png) [@badrobot](https://forums.plex.tv/u/badrobot)\
**Post date:** [July 30, 2018, 9:56pm UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/6 "2018-07-30T21:56:52Z")

</div>

Seems way too complicated when you can just

\<VirtualHost \*:80\>  
ServerName your servername  
Redirect / [https://your](https://your) servername/  
RewriteEngine on  
RewriteCond %{SERVER\_NAME} = **your servername**  
RewriteRule ^ https://%{SERVER\_NAME}%{REQUEST\_URI} [END,NE,R=permanent]  
\</VirtualHost\>

\<IfModule mod\_ssl.c\>  
\<VirtualHost \*:443\>  
ProxyPass /plex [http://localhost:32400](http://localhost:32400)  
ProxyPassReverse /plex [http://localhost:32400](http://localhost:32400)  
ProxyPass /web [http://localhost:32400/web](http://localhost:32400/web)  
ProxyPassReverse /web [http://localhost:32400/web](http://localhost:32400/web)  
\</VirtualHost\>  
\</IfModule\>

---

<div class="post-metadata">

**Author:** ![jugzadmin](https://sea1.discourse-cdn.com/plex/user_avatar/forums.plex.tv/jugzadmin/32/145893_2.png) [@jugzadmin](https://forums.plex.tv/u/jugzadmin)\
**Post date:** [November 22, 2018, 2:08pm UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/7 "2018-11-22T14:08:23Z")

</div>

First off, the apache2 conf file is to have a web interface that is exactly like being on localhost:32400. You still must have port forwarding set up and wherever you are trying to access plex from must have that port open in order for everything to work properly. If you are slightly paranoid about security, you can use this (my) apache2 conf file:  
EDIT 5/9/18: Added blob: to media-src in Content-Security-Policy to allow trailers to play.

EDIT: Update as of 4/17/2019.  
You will need to be using Apache2 \>= 2.4.17 to use this and several mods (proxy, ssl, proxy\_wstunnel, http, dir, env, headers, proxy\_balancer, proxy\_http, rewrite I think is all of them).

EDIT: Update as of 2/18/2021.

- Updated Content Security Policy
- Added Permissions Policy
- Removed Rewrite
- Added `<Location>` sections
- gzip defalte for common files (javascript, xml, etc.)
- Updated Ciphers

## New config (February 2021)

```apache
    DEFINE plex_url 192.168.1.22
    DEFINE plex_port 32400
    DEFINE serv_name plex.domain.com
    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 ###
    <IfModule mod_pagespeed_ap24.c>
        ModPagespeed Off
    </IfModule>
<VirtualHost *:80>
    ServerName ${serv_name}
    Redirect / https://plex.domain.com
    ErrorLog ${APACHE_LOG_DIR}/plex.error.log
    CustomLog ${APACHE_LOG_DIR}/plex.access.log combined
</VirtualHost>
<VirtualHost *:443>
    ServerName ${serv_name}
    DocumentRoot /var/www/html
    ErrorLog ${APACHE_LOG_DIR}/plex.error.log
    CustomLog ${APACHE_LOG_DIR}/plex.access.log combined
### Let's Encrypt Section ###
    SSLCertificateFile /etc/letsencrypt/live/domain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/domain.com/privkey.pem
### Deny http1.0 requests ###
    Protocols h2 http/1.1
### Harden Security ###
    ProxyRequests Off
    ProxyPreserveHost On
    ProxyTimeout 600
    SSLProxyEngine On
    RequestHeader set Front-End-Https "On"
    ServerSignature Off
    SSLCompression Off
    SSLUseStapling On
    SSLStaplingResponderTimeout 20
    SSLStaplingReturnResponderErrors Off
    SSLSessionTickets Off
### Add headers ###
    RequestHeader set X-Forwarded-Proto 'https' env=HTTPS
    Header always set Strict-Transport-Security "max-age=15552000;"
    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 "same-origin"
    Header always set Permissions-Policy "geolocation=(self), midi=(self), sync-xhr=(self), microphone=(self), camera=(self), magnetometer=(self), gyroscope=(self), fullscreen=(self), payment=(self)"
### Content Security Policy for the overly paranoid - may break with Plex server updates (works with server version 1.21.3.4046 and 1.21.3.4021) ###
    Header always set Content-Security-Policy "default-src 'none'; base-uri 'self' ${serv_name}; font-src 'self' data: ${serv_name}; media-src 'self' data: blob: ${serv_name} https://*.plex.direct:32400 https://video.internetvideoarchive.net https://*.cloudfront.net; script-src 'self' 'unsafe-inline' 'unsafe-eval' domain.com ${serv_name}; style-src 'self' 'unsafe-inline' ${serv_name}; img-src 'self' data: blob: https: ${serv_name}; worker-src * blob:; frame-src 'self'; connect-src 'self' https: domain.com ${serv_name} wss://*.plex.direct:32400 wss://pubsub.plex.tv; object-src 'self' ${serv_name}; frame-ancestors 'self' domain.com ${serv_name}; form-action 'self' ${serv_name}; manifest-src 'self' ${serv_name}; script-src-elem 'self' 'unsafe-inline' domain.com ${serv_name} www.gstatic.com"
### Add secure ciphers ###
    SSLCipherSuite TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256
### Only enable TLSv1.2 and TLSv1.3 ###
    SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
### Tell clients to use server defined ciphers and orders ###
    SSLHonorCipherOrder On
### If path is for Let's Encrypt, don't proxy ###
    ProxyPassMatch ^/.well-known !
### Plex Specific Section ###
 ## Plex has A LOT of javascript, xml and html. This helps a lot, but if it causes playback issues with devices, disable this section
    <IfModule mod_deflate.c>
        AddOutputFilterByType DEFLATE text/html
        AddOutputFilterByType DEFLATE text/plain
        AddOutputFilterByType DEFLATE text/css
        AddOutputFilterByType DEFLATE application/javascript
        AddOutputFilterByType DEFLATE text/javascript
        AddOutputFilterByType DEFLATE application/x-javascript
        AddOutputFilterByType DEFLATE image/svg+xml
        AddOutputFilterByType DEFLATE image/x-icon
        AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
        AddOutputFilterByType DEFLATE application/x-font
        AddOutputFilterByType DEFLATE application/x-font-opentype
        AddOutputFilterByType DEFLATE application/x-font-otf
        AddOutputFilterByType DEFLATE application/x-font-truetype
        AddOutputFilterByType DEFLATE application/x-font-ttf
        AddOutputFilterByType DEFLATE font/opentype
        AddOutputFilterByType DEFLATE font/otf
        AddOutputFilterByType DEFLATE font/ttf
        AddOutputFilterByType DEFLATE application/rss+xml
        AddOutputFilterByType DEFLATE application/xhtml+xml
        AddOutputFilterByType DEFLATE application/xml
        AddOutputFilterByType DEFLATE text/xml
        BrowserMatch ^Mozilla/4 gzip-only-text/html
        BrowserMatch ^Mozilla/4\.0[678] no-gzip
        BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
        Header append Vary User-Agent
    </IfModule>
 ## Proxy all web traffic here ## 
    <Location />
        ProxyPass http://${plex_url}:${plex_port}/
        ProxyPassReverse http://${plex_url}:${plex_port}/
    </Location>
 ## Proxy all websocket requests here ## 
    <Location /:/>
        ProxyPass wss://${plex_url}:${plex_port}/:/
        ProxyPassReverse wss://${plex_url}:${plex_port}/:/
    </Location>
### Don't know if we still need this ###
    <Proxy *>
        Order deny,allow
        Allow from all
    </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>

```

## Need URL subpath?

Change to this:

```apache
    <Location /plex/>
        ProxyPass http://${plex_url}:${plex_port}/
        ProxyPassReverse http://${plex_url}:${plex_port}/
    </Location>
 ## Proxy all websocket requests here ## 
    <Location /plex/:/>
        ProxyPass wss://${plex_url}:${plex_port}/:/
        ProxyPassReverse wss://${plex_url}:${plex_port}/:/
    </Location>

```

## Old config (April 2019)

```apache
<IfModule mod_ssl.c>
	DEFINE plex_url 192.168.1.22
	DEFINE plex_port 32400
	DEFINE serv_name plex.domain.com
	ServerTokens Prod
	SSLStaplingCache "shmcb:${APACHE_LOG_DIR}/stapling-cache(150000)"
	SSLSessionCache "shmcb:${APACHE_LOG_DIR}/ssl_scache(512000)"
	SSLSessionCacheTimeout 300
	ModPagespeed Off
<VirtualHost *:80>
	ServerName ${serv_name}
	DocumentRoot /var/www/html
	ServerAdmin aw@hell.no
	RewriteEngine On
	RewriteCond %{SERVER_NAME} =${serv_name}
	RewriteCond %{HTTPS} Off
	RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
	ErrorLog ${APACHE_LOG_DIR}/${serv_name}.error.log
	CustomLog ${APACHE_LOG_DIR}/${serv_name}.access.log combined
</VirtualHost>
<VirtualHost *:443>
	ServerName ${serv_name}
	DocumentRoot /var/www/html
	ServerAdmin aw@hell.no
	ErrorLog ${APACHE_LOG_DIR}/${serv_name}.error.log
	CustomLog ${APACHE_LOG_DIR}/${serv_name}.access.log combined
### Let's Encrypt Section ###
	SSLCertificateFile /etc/letsencrypt/live/${serv_name}/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/${serv_name}/privkey.pem
	#Include /etc/letsencrypt/options-ssl-apache.conf
	Options -Includes -ExecCGI
### Deny http1.0 requests ###
	RewriteEngine On
	RewriteCond %{SERVER_PROTOCOL} ^HTTP/1\.0$
	#RewriteCond %{REQUEST_URI} !^/404/$
	RewriteRule ^ - [F]
### Harden Security ###
	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 "same-origin"
	Header always set Feature-Policy "accelerometer 'none'; camera 'none'; geolocation 'none'; gyroscope 'none'; magnetometer 'none'; microphone 'none'; payment 'none'; usb 'none';"
	Header always set Content-Security-Policy "default-src 'self' https:; font-src 'self' data: ${plex_url} ${serv_name}; media-src 'self' blob: ${plex_url} ${serv_name}; script-src 'self' 'unsafe-inline' ${plex_url} ${serv_name} plex.tv www.gstatic.com; style-src 'self' ${plex_url} ${serv_name}; img-src 'self' data: blob: ${plex_url} ${serv_name} plex.tv *.plex.tv; worker-src *; frame-src 'none'; connect-src 'self' wss: https: ${plex_url} ${serv_name} plex.tv *.plex.direct *.plex.tv;"
	SSLCipherSuite ECDHE+RSA+AES256+GCM+SHA512:DHE+RSA+AES256+GCM+SHA512:ECDHE+RSA+AES256+GCM+SHA384:DHE+RSA+AES256+GCM+SHA384:ECDHE+RSA+AES256+SHA384:EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4
	SSLProtocol All -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
	SSLHonorCipherOrder On
### Plex Specific Section ###
	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 *>
		Order deny,allow
		Allow from all
	</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>
</IfModule>

```

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/plex/original/3X/2/a/2acb9765406f63293d357b4ec509ec39aa28f2ad.png) [@system](https://forums.plex.tv/u/system)\
**Post date:** [January 7, 2020, 8:47pm UTC](https://forums.plex.tv/t/working-apache-reverse-proxy-configuration-for-plex/129126/8 "2020-01-07T20:47:02Z")

</div>


