[Apache] Reverse SSL Proxy not working

Dearest community,

For testing purposes I have only one vhost configured with the purpose of hosting my plex server behind an apache reverse proxy over SSL. The config looks like this:

ServerSignature Off
ServerTokens Prod

<VirtualHost *:80>
  ServerName plex.privatedomain.com
  # This VirtualHost redirects everything to HTTPS on port 443.
  RewriteEngine On
  RewriteCond %{HTTPS} off
  RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>

<VirtualHost *:443>
  ServerName plex.privatedomain.com
  ServerAlias ""
  Options -Includes -ExecCGI

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

  LimitRequestBody 512000
  SSLEngine On
  SSLCertificateFile /etc/letsencrypt/live/movies.privatedomain.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/movies.privatedomain.com/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://localhost:32400/:/websockets/notifications
		ProxyPassReverse wss://localhost:32400/:/websockets/notifications
	</Location>

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

	ProxyRequests Off
	ProxyPreserveHost On
	SSLProxyEngine On
	RequestHeader set Front-End-Https "On"
	ProxyPass / http://localhost:32400/
	ProxyPassReverse / http://localhost:32400/

	RewriteEngine on
	RewriteCond %{REQUEST_URI} !^/web
	RewriteCond %{HTTP:X-Plex-Device} ^$
	RewriteCond %{REQUEST_METHOD} !^(OPTIONS)$

	RewriteRule ^/$ /web/$1 [R,L]
</VirtualHost>

Sadly after I login my server cannot be found, see below the browser debug log. If anyone can help me figuring out what is going wrong I would be very grateful!

    myPlexAccessToken is not in VolatileWebStorage
    connections is not in PersistentWebStorage
    skipSignIn is not in PersistentWebStorage
    settingsv2 is not in PersistentWebStorage
    experience is not in PersistentWebStorage
    [UserManager] autoLogin false
    [Servers] Initializing...
    [Servers] Waiting for initial servers = [Anonymous], plex.tv
    [Primary Server] Waiting to set the primary server
    [Primary Server] Waiting for the last primary server, c13467b3a58c55650932dfdbbb32aa92d27c216b, to connect
    [Commands] Executing testServerConnection
    [Commands] Executing testServerConnection
    [Servers] Finished initialization
    [Cast] Loaded the cast api
    [Cast] No receivers are available
    [Connections] Testing connection for plex.tv at https://plex.tv/pms/:/ip
    [Connections] Testing connection for [Anonymous] at https://plex.privatedomain.com/
    [Connections] plex.tv connected at https://plex.tv/pms/:/ip
    [Connections] Active connection to plex.tv is https://plex.tv
    Mixed Content: The page at 'https://plex.privatedomain.com/web/index.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://plex.privatedomain.com/web/index.html'. This content should also be served over HTTPS.
    [Parser] Errors found while parsing XML document
    [Connections] [Anonymous] has an unexpected machine identifier at https://plex.privatedomain.com/
    [Connections] [Anonymous] is unavailable at https://plex.privatedomain.com/ (Status 200)
    [Connections] Prevented fallback to insecure connection for  [Anonymous]
    [Connections] All connections to [Anonymous] failed
    [Servers] Waiting for initial servers = plex.tv
    [Servers] Finding resources through plex.tv
    [Servers] Waiting for additional resources from plex.tv
    [CloudServerEventManager] Opening server event connection to plex.tv at wss://pubsub.plex.tv/sub/websockets/8807264/onn9jkkhqorhtzt948klf2yb9?X-Plex-Token=REDACTED
    [Companion] Registering player with plex.tv, clientID="onn9jkkhqorhtzt948klf2yb9"
    [Servers] plex.privatedomain.com was found through plex.tv
    [Commands] Executing testServerConnection
    [Servers] Waiting for additional resources from plex.tv
    [Servers] Plex server Mark was found through plex.tv
    [Commands] Executing testServerConnection
    [Servers] Waiting for additional resources from plex.tv
    [Servers] Waiting for additional resources from plex.tv
    [Servers] Found 7 resources through plex.tv
    [Servers] Found all servers = plex.tv
    [Commands] Executing lockUser
    [CloudServerEventManager] Opened server event connection to plex.tv at wss://pubsub.plex.tv/sub/websockets/8807264/onn9jkkhqorhtzt948klf2yb9?X-Plex-Token=REDACTED
    [Commands] Executing authenticateWithServer
    [Connections] Testing connection for plex.privatedomain.com at https://plex.privatedomain.com/
    [Connections] Aborting connection test for plex.privatedomain.com at http://192.168.0.240:32400/ due to mixed content prevention
    [Connections] Aborting connection test for plex.privatedomain.com at http://172.17.0.1:32400/ due to mixed content prevention
    [Connections] Testing connection for Plex server Mark at https://192-168-2-11.8c9fa4cb80ca4953a6d5dc9b49a95621.plex.direct:32400/
    Mixed Content: The page at 'https://plex.privatedomain.com/web/index.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://plex.privatedomain.com/web/index.html'. This content should also be served over HTTPS.
    [Parser] Errors found while parsing XML document
    [Connections] plex.privatedomain.com has an unexpected machine identifier at https://plex.privatedomain.com/
    [Connections] plex.privatedomain.com is unavailable at https://plex.privatedomain.com/ (Status 200)
    [Connections] Prevented fallback to insecure connection for  plex.privatedomain.com
    [Connections] All connections to plex.privatedomain.com failed
    [Servers] Found all servers = plex.tv
    [Primary Server] Waiting for any owned server to connect
    [Primary Server] Waiting for any eligible server to connect
    [Companion] No proxy found
    [Commands] Executing switchUser
    [Commands] Executing authenticateWithServer
    [Commands] Executing resetUser
    [Connections] Aborted pending connection test for Plex server Mark at https://192-168-2-11.8c9fa4cb80ca4953a6d5dc9b49a95621.plex.direct:32400/
    [Servers] Found all servers = plex.tv
    [CloudServerEventManager] Closing server event connection to plex.tv at wss://pubsub.plex.tv/sub/websockets/8807264/onn9jkkhqorhtzt948klf2yb9?X-Plex-Token=REDACTED
    [Servers] Resetting...
    [Servers] Initializing...
    [Servers] Waiting for initial servers = [Anonymous]
    [Primary Server] Waiting for the last primary server, c13467b3a58c55650932dfdbbb32aa92d27c216b, to connect
    [Commands] Executing testServerConnection
    [Servers] Finished initialization
    [Servers] Finding resources through plex.tv
    [Servers] Waiting for initial servers = [Anonymous]
    [CloudServerEventManager] Opening server event connection to plex.tv at wss://pubsub.plex.tv/sub/websockets/8807264/onn9jkkhqorhtzt948klf2yb9?X-Plex-Token=REDACTED
    [Commands] Executing resumePlayQueue
    [Commands] Executing persistPlayQueue
    [Servers] plex.privatedomain.com was found through plex.tv
    [Commands] Executing testServerConnection
    [Connections] Aborting connection test for plex.privatedomain.com at http://192.168.0.240:32400/ due to mixed content prevention
    [Connections] Testing connection for [Anonymous] at https://plex.privatedomain.com/
    [Commands] Executing testServerConnection
    [Servers] Waiting for initial servers = [Anonymous]
    [Servers] Plex server Mark was found through plex.tv
    [Commands] Executing testServerConnection
    [Connections] Testing connection for plex.privatedomain.com at https://plex.privatedomain.com/
    [Connections] Aborting connection test for plex.privatedomain.com at http://172.17.0.1:32400/ due to mixed content prevention
    [Connections] Testing connection for Plex server Mark at https://192-168-2-11.8c9fa4cb80ca4953a6d5dc9b49a95621.plex.direct:32400/
    [Servers] Waiting for initial servers = [Anonymous]
    [Servers] Waiting for initial servers = [Anonymous]
    [Servers] Found 7 resources through plex.tv
    [Servers] Waiting for initial servers = [Anonymous]
    [CloudServerEventManager] Opened server event connection to plex.tv at wss://pubsub.plex.tv/sub/websockets/8807264/onn9jkkhqorhtzt948klf2yb9?X-Plex-Token=REDACTED
    [Servers] Populate any server chose plex.tv where servers = [Anonymous], plex.privatedomain.com, plex.tv, Plex server Mark
    Mixed Content: The page at 'https://plex.privatedomain.com/web/index.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://plex.privatedomain.com/web/index.html'. This content should also be served over HTTPS.
    [Parser] Errors found while parsing XML document
    [Connections] [Anonymous] has an unexpected machine identifier at https://plex.privatedomain.com/
    [Connections] [Anonymous] is unavailable at https://plex.privatedomain.com/ (Status 200)
    [Connections] Prevented fallback to insecure connection for  [Anonymous]
    [Connections] All connections to [Anonymous] failed
    [Servers] Found all servers = plex.tv
    [Parser] Errors found while parsing XML document
    [Connections] plex.privatedomain.com has an unexpected machine identifier at https://plex.privatedomain.com/
    [Connections] plex.privatedomain.com is unavailable at https://plex.privatedomain.com/ (Status 200)
    [Connections] Prevented fallback to insecure connection for  plex.privatedomain.com
    [Connections] All connections to plex.privatedomain.com failed
    [Servers] Found all servers = plex.tv
    [Primary Server] Waiting for any owned server to connect
    [Primary Server] Waiting for any eligible server to connect
    [Companion] No proxy found
    [Connections] Plex server Mark is unavailable at https://192-168-2-11.8c9fa4cb80ca4953a6d5dc9b49a95621.plex.direct:32400/ (Status 0)
    [Connections] Prevented fallback to insecure connection for  Plex server Mark
    [Connections] All connections to Plex server Mark failed
    [Servers] Found all servers = plex.tv
    [Primary Server] Waiting for any eligible server
    [Connections] Retrying connection tests for plex.privatedomain.com in 1 seconds
    [Connections] Retrying server events connection for plex.privatedomain.com in 1 seconds
    [Primary Server] plex.privatedomain.com is now the primary server
    [Connections] Testing all 3 connection(s) for plex.privatedomain.com
    [Servers] Found all servers = plex.tv
    [Commands] Executing testServerConnection
    [Connections] Aborting connection test for plex.privatedomain.com at http://192.168.0.240:32400/ due to mixed content prevention
    [Commands] Executing testServerConnection
    [Connections] Retrying connection tests for plex.privatedomain.com in 2 seconds
    [Connections] Retrying server events connection for plex.privatedomain.com in 2 seconds
    [Connections] All connections to plex.privatedomain.com failed
    [Servers] Found all servers = plex.tv
    [Connections] Testing connection for plex.privatedomain.com at https://plex.privatedomain.com/
    [Connections] Aborting connection test for plex.privatedomain.com at http://172.17.0.1:32400/ due to mixed content prevention
    Mixed Content: The page at 'https://plex.privatedomain.com/web/index.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://plex.privatedomain.com/web/index.html'. This content should also be served over HTTPS.
    [Parser] Errors found while parsing XML document
    [Connections] plex.privatedomain.com has an unexpected machine identifier at https://plex.privatedomain.com/
    [Connections] plex.privatedomain.com is unavailable at https://plex.privatedomain.com/ (Status 200)
    [Connections] Prevented fallback to insecure connection for  plex.privatedomain.com
    [Connections] All connections to plex.privatedomain.com failed
    [Companion] No proxy found
    [Connections] Testing all 3 connection(s) for plex.privatedomain.com
    [Servers] Found all servers = plex.tv
    [Commands] Executing testServerConnection
    [Connections] Retrying connection tests for plex.privatedomain.com in 3 seconds
    [Connections] Retrying server events connection for plex.privatedomain.com in 3 seconds
    [Connections] Testing connection for plex.privatedomain.com at https://plex.privatedomain.com/
    [Connections] Aborting connection test for plex.privatedomain.com at http://192.168.0.240:32400/ due to mixed content prevention
    [Connections] Aborting connection test for plex.privatedomain.com at http://172.17.0.1:32400/ due to mixed content prevention
    Mixed Content: The page at 'https://plex.privatedomain.com/web/index.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://plex.privatedomain.com/web/index.html'. This content should also be served over HTTPS.
    [Parser] Errors found while parsing XML document
    [Connections] plex.privatedomain.com has an unexpected machine identifier at https://plex.privatedomain.com/
    [Connections] plex.privatedomain.com is unavailable at https://plex.privatedomain.com/ (Status 200)
    [Connections] Prevented fallback to insecure connection for  plex.privatedomain.com
    [Connections] All connections to plex.privatedomain.com failed
    [Servers] Found all servers = plex.tv
    [Connections] Testing all 3 connection(s) for plex.privatedomain.com
    [Servers] Found all servers = plex.tv
    [Commands] Executing testServerConnection
    [Connections] Retrying connection tests for plex.privatedomain.com in 4 seconds
    [Connections] Retrying server events connection for plex.privatedomain.com in 4 seconds
    [Connections] Testing connection for plex.privatedomain.com at https://plex.privatedomain.com/
    [Connections] Aborting connection test for plex.privatedomain.com at http://192.168.0.240:32400/ due to mixed content prevention
    [Connections] Aborting connection test for plex.privatedomain.com at http://172.17.0.1:32400/ due to mixed content prevention
    Mixed Content: The page at 'https://plex.privatedomain.com/web/index.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://plex.privatedomain.com/web/index.html'. This content should also be served over HTTPS.
    [Parser] Errors found while parsing XML document
    [Connections] plex.privatedomain.com has an unexpected machine identifier at https://plex.privatedomain.com/
    [Connections] plex.privatedomain.com is unavailable at https://plex.privatedomain.com/ (Status 200)
    [Connections] Prevented fallback to insecure connection for  plex.privatedomain.com
    [Connections] All connections to plex.privatedomain.com failed
    [Servers] Found all servers = plex.tv

My eye was falling on the following log entries:
Mixed Content: The page at 'https://plex.privatedomain.com/web/index.html' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://plex.privatedomain.com/web/index.html'. This request has been blocked; the content must be served over HTTPS.

In my Chrome browser I did allow this though:
You have recently allowed insecure content (such as scripts or iframes) to run on this site.

Any thoughts?

I basically have the exactly same setup and problem - please let me know if you find a solution!

I ended up getting this working (I think I was missing secure web-socket proxying). Here is my config in case it helps anyone! I’m using the latest version of Plex (DVR beta 2), and Apache 2.4. You’ll probably need mod_wstunnel, mod_proxy, and mod_ssl.

<VirtualHost *:80>
	ServerAdmin email@address.com
    ServerName www.subdomain.domain.com
    ServerAlias subdomain.domain.com
    Redirect permanent / https://subdomain.domain.com
</VirtualHost>

<VirtualHost *:443>
	ServerAdmin email@address.com
    ServerName www.subdomain.domain.com
    ServerAlias subdomain.domain.com

	SSLEngine on
	SSLCertificateFile	/etc/letsencrypt/live/www.subdomain.domain.com/fullchain.pem
	SSLCertificateKeyFile /etc/letsencrypt/live/www.subdomain.domain.comt/privkey.pem
    SSLProtocol +TLSv1.2

	<Location />
		AuthType Digest 
		AuthName "www.subdomain.domain.com"
		AuthUserFile /etc/apache2/.htpasswd
		require valid-user
	</Location>

	ProxyRequests Off
	ProxyPreserveHost On

    ProxyPass /:/ ws://localhost:32400/:/
    ProxyPassReverse /:/ ws://localhost:32400/:/

    ProxyPass /:/ wss://localhost:32400/:/
    ProxyPassReverse /:/ wss://localhost:32400/:/

	ProxyPass / http://localhost:32400/
	ProxyPassReverse / http://localhost:32400/

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

    <Proxy *>
		Require all granted
    </Proxy>

</VirtualHost>

@fallen751 said:
I ended up getting this working (I think I was missing secure web-socket proxying). Here is my config in case it helps anyone! I’m using the latest version of Plex (DVR beta 2), and Apache 2.4. You’ll probably need mod_wstunnel, mod_proxy, and mod_ssl.

I tried your vhost-setting, Plex seems to be available from the outside world, it’s just that when I am not in the same network, server settings are not available, and I can’t reach my server from within the Android app. Any ideas?

An extremely opinionated apache2 configuration file:

EDIT: Update as of 4/17/2019.
You will need to be using Apache2 >= 2.4.11 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):

<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>