Php – Give PHP a fake request URL and protocol with Apache2 and mod_php

apache-2.2mod-phpPHP

I run a web server with multiple users. The machine provides Apache-based virtual hosts to a bunch of users, who can serve static content or use PHP. No other forms of server-side scripting are available.

Here's how a typical request is handled:

Flow chart of request handling

HTTPS traffic has its SSL stripped by Pound, which acts as a reverse proxy and forwards the request on to Varnish, which also acts as a reverse proxy, finally forwarding the request on to Apache.

By the time the HTTPS traffic reaches Apache, the protocol, port, and full URL have changed from, say, https://example.com:443/ to http://example.com:8443/. This is a result of all the proxies before Apache.

Is there a way I can trick the PHP scripts into thinking the request came from the original URL, port, and protocol, without modifying the PHP code?

This is important because the users will wish to run Joomla, WordPress, and other PHP-based CMSes which detect the URL and cause trouble with redirects, links, etc.

I could probably patch mod_php and build it from source with the necessary changes for my specific scenario, but is there a better way to give the PHP scripts fake environmental variables, perhaps via some setting in php.ini?

Best Answer

The easiest way I can find to do this is by dropping mod_php and using a CGI script instead. This allows you to call php-cgi (a CGI-targeted version of the PHP interpreter) from a shell script which is executed on page load.

Here is an example bash script which sets the SERVER_PORT and HTTPS environment variables based on the X-Forwarded-Proto header, and then calls php-cgi:

#!/bin/bash
# HTTPS fix (WARNING: THIS HEADER CAN BE FAKED BY THE CLIENT)
if [[ "$HTTP_X_FORWARDED_PROTO" == "https" ]]; then
        export SERVER_PORT=443
        export HTTPS="on"
else
        export SERVER_PORT=80
fi

php-cgi

Of course, you must be careful because the X-Forwarded-Proto header can be sent by the client, so unless you have something sitting between Apache and the client sanitizing that header, you should not trust it! (you probably also want to firewall off Apache, or better yet, have it only listen on loopback)

All you need to do is have Apache use this bash script for every file with a .php extension (mod_cgi and mod_actions let you do this).

Related Topic