Adding Reverse Proxy for Plex to Apache vhost


It is easy to find apache vhost definitions for reverse proxying plex traffic.
What this post does is show you how to include the parts needed, to provide a reverse proxy to plex, in an existing vhost. Why would you need this? I don’t know. I did, and it was as easy as adding a few bits to represent the web address.

Adding reverse proxy for plex to Apache vhost

So in your vhost, add these lines:

        <Proxy *>
                Order deny,allow
                Allow from all
        ProxyRequests Off
        ProxyPass               /web/
        ProxyPassReverse        /web/
        <LocationMatch '^/web\/.*$'>
                RequestHeader set Front-End-Https "On"
                RewriteEngine On
                RewriteCond     %{REQUEST_URI}          !^/web
                RewriteCond     %{HTTP:X-Plex-Device}   ^$
                RewriteCond %{REQUEST_METHOD}   !^(OPTIONS)$
                RewriteRule ^/$ /web/$1 [R,L]

So the difference in this snippet from a separate vhost definition is that you proxypass only the /web/ location over to your Plex media server.


	ServerAlias example www

	DocumentRoot	/var/www

	Options +Indexes
	IndexOptions IgnoreCase FancyIndexing FoldersFirst NameWidth=* DescriptionWidth=*
	IndexIgnore FOOTER.html repodata favicon.ico favicon.png
	ReadmeName FOOTER.html
	DirectoryIndex index.php index.html index.htm
	ServerSignature Off

	SetEnvIf Request_URI "ignoredfile.html" dontlog
	LogFormat "%V %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combinedvhost
	CustomLog logs/access_log combinedvhost env=!dontlog

	# Useful additions for a mirror server
	AddIcon /icons/rpm.png          .rpm
	AddIcon /icons/deb.png          .deb
	AddIcon /icons/repo.png         .repo
	AddType application/octet-stream .iso

	AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript
	BrowserMatch ^Mozilla/4 gzip-only-text/html
	BrowserMatch ^Mozilla/4\.0[678] no-gzip
	BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

	TraceEnable off
	<FilesMatch "\.acl$">
		Deny from All
	&ltDirectory "/var/www/example">
		AllowOverride None
		Order allow,deny
		Allow from all
		Options Indexes FollowSymLinks
       # Allows "" redirection to "" behavior
# RewriteEngine On
# RewriteCond %{HTTP_HOST} ^([^.]*)\.example\.no-ip\.biz$
# RewriteRule /(.*)$1 [R,L]

	# reference: welcome.conf, reverseproxyforplex.conf
	# reference:
	<Proxy *>
		Order deny,allow
		Allow from all
	ProxyRequests Off
	ProxyPass		/web/
	ProxyPassReverse	/web/
	<LocationMatch '^/web\/.*$'>
		RequestHeader set Front-End-Https "On"
	        RewriteEngine On
		RewriteCond	%{REQUEST_URI}		!^/web
		RewriteCond	%{HTTP:X-Plex-Device}	^$
		RewriteCond %{REQUEST_METHOD}	!^(OPTIONS)$	
		RewriteRule ^/$ /web/$1 [R,L]





Nagios plugin to count apache threads


At work I have a misbehaving web server. Sometimes it spawns the maximum number of apache threads (which has a hardcoded maximum of 256, no matter what you configure) and then occupies 100% of the processor. I have decided that the normal nagios checks for the http site and ssh and so on aren’t good enough for monitoring purposes.

So I wrote my own simple nagios check. And then I put it in an rpm for easy deployment.

The nagios check

Here is the code for check_apache_threads, although you can check the latest version at my github page.

# File: /usr/lib64/nagios/plugins/check_apache_threads
# Author:
# Startdate: 2017-01-09 15:53
# Title: Nagios Check for Apache Threads
# Purpose: For a troublesome dmz wordpress host
# Package: nagios-plugins-apache-threads
# History:
# Usage:
# In nagios/nconf, use this checkcommand check command line: $USER1$/check_by_ssh -H $HOSTADDRESS$ -C "$USER1$/check_apache_threads -w $ARG1$ -c $ARG2$"
# Reference: general design /usr/lib64/nagios/plugins/check_sensors
# general design
# case -w
# Improve:
PROGNAME=`basename $0`
PROGPATH=`echo $0 | sed -e 's,[\\/][^\\/][^\\/]*$,,'`
print_usage() {
cat <<EOF
Usage: $PROGNAME -w <thresh_warn> -c <thresh_crit>
print_help() {
print_revision $PROGNAME $REVISION
echo ""
echo ""
echo "This plugin checks for the number of active apache threads."
echo ""
exit $STATE_OK
# Total httpd threads
tot_apache_threads="$( ps -ef | grep -ciE "httpd$" )"
while test -n "${1}";
case "$1" in
exit $STATE_OK
print_revision $PROGNAME $REVISION
exit $STATE_OK
-v | --verbose)
verbosity=$(( verbosity + 1 ))
-w | --warning | -c | --critical)
if [[ -z "$2" || "$2" = -* ]];
# Threshold not provided
echo "$PROGNAME: Option '$1' requires an argument."
elif [[ "$2" = +([0-9]) ]];
# Threshold is a number
# use for a percentage template, from reference 2
#elif [[ "$2" = +([0-9])% ]]; then
# # Threshold is a percentage
# thresh=$(( tot_mem * ${2%\%} / 100 ))
# Threshold is not a number or other valid input
echo "$PROGNAME: Threshold must be an integer."
case "$1" in *-w*) thresh_warn=$thresh;; *) thresh_crit=$thresh;; esac
shift 2
exit $STATE_OK
echo "$PROGNAME: Invalid option '$1'"
if test -z "$thresh_warn" || test -z "$thresh_crit";
# One or both values were unspecified
echo "$PROGNAME: Threshold not set"
elif test "$thresh_crit" -le "$thresh_warn";
echo "$PROGNAME: Critical value must be greater than warning value."
if test "$verbosity" -ge 2;
# Print debugging information
/bin/cat <<EOF
Debugging information:
Warning threshold: $thresh_warn
Critical threshold: $thresh_crit
Verbosity level: $verbosity
Apache threads: ${tot_apache_threads}
if test "${tot_apache_threads}" -gt "${thresh_crit}";
# too many apache threads
echo "APACHE CRITICAL - $tot_apache_threads"
elif test "${tot_apache_threads}" -gt "${thresh_warn}";
echo "APACHE WARNING - $tot_apache_threads"
# fine
echo "APACHE OK - $tot_apache_threads"
exit $STATE_OK

Walking through the code

I included the code above so it gets cached by web crawlers. You should look at the code on github so you get the proper indentations, and line numbers.

So the general format of this script I got from a local file, check_sensor, and Reference 1 below.

The call provides nagios-related definitions, including the exit codes that you see used like $STATE_OK.

The shell script is pretty self-explanatory, really. The variables are initialized and the actual checked value is calculated (ps -ef | grep httpd). About half the script (lines 51-100) is parsing the parameters, which is a nice, simple solution if you have predictable and simplified input (like from nagios) and you don’t do the proper parameter parsing that includes -XvalueofXhere with no space between the flag and the value.

Some sanity checking for threshholds (102-113) and debugging information if given enough verbosity (115-125), and then the actual results are determined in 127-140.

Final thoughts

The hardest part of using this plugin is not writing, using, or deploying the shell script. The hardest part is getting the script to run. To use this check properly, you actually need to write a nagios checkcommand like so:
$USER1$/check_by_ssh -H $HOSTADDRESS$ -C "$USER1$/check_apache_threads -w $ARG1$ -c $ARG2$"
With the arguments as the numbers for your thresholds. I used the values 50 and 150 for warning and critical.

Any questions?



  1. General design
  2. case -w

Adding ADFS integration to Apache


ADFS is Microsoft Active Directory Federated Services. It is a single sign-on solution, and this post explains how to tie in Apache 2.4 (CentOS 7) to ADFS. All of this works even with SELinux enforcing!

The test environment described by this document includes the following.

Root URL: (

Protected subdirectory:

Warning! ADFS Configuration changes can take a few minutes to take effect.

Adding ADFS integration to Apache

This guide assumes you have a functional apache environment.

Configuring apache

Install mod_auth_mellon from the regular centos repository. Also include php.

yum -y install mod_auth_mellon php

Set up mellon with the sample hostname and url using the provided tool.

mkdir -p /etc/httpd/mellon
cd /etc/httpd/mellon
/usr/libexec/mod_auth_mellon/ ""

This script outputs 3 files to the current directory.

This certificate is a self-signed certificate, but other options can be used and should be considered for production environments. Be aware that the certificates are also dumped into the xml file that will be shared with the ADFS host, so be sure to share any new certificates there as well.

Collect the ADFS metadata and store it locally. Such metadata is usually available at a URL similar to the following.

Here is a copy-pastable line for people like me.

wget -O /etc/httpd/mellon/FederationMetadata.xml

Build the apache Mellon config.

cat <<EOF >/etc/httpd/conf.d/auth_mellon.conf
MellonCacheSize 100
MellonLockFile /var/run/mod_auth_mellon.lock
MellonPostTTL 900
MellonPostSize 1073741824
MellonPostCount 100
MellonPostDirectory "/var/cache/mod_auth_mellon_postdata"

My test environment uses a modular ssl directives include file:

cat <<EOFSSL >/etc/httpd/sites/all-ssl.cnf
SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLHonorCipherOrder on

<Files ~ "\.(cgi|shtml|phtml|php3?)$">
        SSLOptions +StdEnvVars
<Directory "/var/www/cgi-bin">
        SSLOptions +StdEnvVars

SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key

SetEnvIf User-Agent ".*MSIE 4\.0b2.*"                 nokeepalive ssl-unclean-shutdown                 downgrade-1.0 force-response-1.0

LogLevel warn
ErrorLog logs/ssl_error_log
CustomLog logs/ssl_access_log combinedvhost

<Directory "/var/www/html/notfound/">
        AllowOverride None
        Order allow,deny
        Allow from all

# END OF FILE all-ssl.cnf

In the apache config, probably /etc/httpd/sites/sample.conf, modify the virtual host.

cat <<EOF >/etc/httpd/sites/sample.conf


        ServerAlias     sample

        # Redirect everything to the https site
        RewriteEngine   On
        RewriteRule ^(.*)$      https://%{HTTP_HOST}%{REQUEST_URI}



        ServerAlias     sample
        DocumentRoot /var/www/html/

        Include sites/all-ssl.cnf

        <Directory "/var/www/html/">
            AllowOverride None
            Order allow,deny
            Allow from all
            Options Indexes FollowSymLinks

        <Location /auth1/>
                # Mellon auth which goes to ADFS
                Include sites/adfs.cnf
                MellonCond "groups" "WebAppUsers_grp" [REG,SUB,NC]

Make the post dump location, which is not necessary but might be useful in the future.

mkdir -p /var/cache/mod_auth_mellon_postdata
chown apache:apache /var/cache/mod_auth_mellon_postdata
chmod 0700 /var/cache/mod_auth_mellon_postdata

Building the include files

We already built the all-ssl.cnf include file, so we just need the adfs include file.

cat <<EOF >/etc/httpd/sites/adfs.cnf
# File: /etc/httpd/sites/adfs.cnf
MellonEnable "auth"
Require valid-user
AuthType "Mellon"
MellonVariable "cookie"
#MellonSamlResponseDump On

MellonSPPrivateKeyFile /etc/httpd/mellon/
MellonSPCertFile /etc/httpd/mellon/
MellonSPMetadataFile /etc/httpd/mellon/
MellonIdPMetadataFile /etc/httpd/mellon/FederationMetadata.xml
MellonMergeEnvVars On ":"
MellonEndpointPath /auth1/endpoint

Here, the MellonMergeEnvVars On “:” means that any multiple-value attribute (like Groups) will be added to one colon-delimited string instead of being assigned to “Mellon_Groups_1” “Mellon_Groups_2” and so on. It’s how the MellonCond works in the virtual host configuration.

Building example sites

Build the index file for the protected directory.

cat <<EOF >/var/www/html/
<head><title>Authorized zone</title></head>
<h1>Welcome to the authorized zone.</h1>
You should only be able to see this if you are authenticated and authorized.

Make a php troubleshooting file.

cat <<EOF >${thisfile}
chown apache:apache ${thisfile}
chmod 644 ${thisfile}

This little php file will show the apache environment variables that are available for use in the apache directives. The important ones here will be the ones prepended with “MELLON_.”

Configuring ADFS to share data

On the ADFS server, add a new relying party trust.

Run the AD FS management tool.

Navigate in the tree structure to AD FS –> Trust relationships –> Relying party trusts.

Select on the action menu “Add relying party trust…”

The easiest way to do this is to use the xml file generated by that script earlier.

Do not configure multi-factor authentication.

Permit all users to access this relying party.

Edit the properties of the relying party trust –> Advanced tab.

Set value “Secure hash algorithm” to SHA-1.

Adding claim rules

Right-click this relying party trust and select “Edit Claim Rules.”

Add a rule of type “Transform incoming claim.”

Incoming claim type: Windows account name
Outgoing claim type: Name ID
Outgoing name ID format: Transient Identifier
Radio button: Pass through all claim values

The rule text looks like:

c:[Type == ""]
 => issue(Type = "", Issuer = c.Issuer, OriginalIssuer = c.OriginalIssuer, Value = c.Value, ValueType = c.ValueType, Properties[""] = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient");

Reference: Specific example of mellon configuration

Add custom rule “Get all groups user belongs to.”

c:[Type == "", Issuer == "AD AUTHORITY"]
 => add(store = "Active Directory", types = (""), query = ";tokenGroups;{0}", param = c.Value);

The add command instead of issue passes the information on to the next rule.

Reference: Custom rules sharing

Add custom rule “Filter your groups only.”

c:[Type == "", Value =~ ".*WebAppUsers_grp.*|.*IT.*"]
 => issue(Type = "groups", Value = c.Value, Issuer = c.Issuer);

The type name of “groups” means that mellon will provide an apache environment variable of “MELLON_groups” which we are performing the condition statement on in the virtual host.

The regex in the first part is looking for any group name that has “IT” in it at all or “WebAppUsers_grp” which is probably pretty specific to just that one group.

What this does is limit the groups being sent so instead of those 538 AD groups possible that that one user is in, it will pass back only the 28 IT department-related ones and the WebAppUsers_grp.

After the apachectl configtest, give apache graceful a shot!

The above link (modified for you of course) should redirect to the AD FS login page and then send authenticated users back!

The benefits here include using apache as a reverse proxy to tomcat applications (local or otherwise) and providing a layer of authentication.


  1. Official mellon page
  2. Specific example of mellon configuration
  4. ADFS saml rules
  5. Regex is allowed in claims
  7. Custom rules sharing