The Reverse Proxy Series — Part 3.1: Apache as an SSL reverse-proxy
SSL involves cryptography (SSL might also involve moving your hands to express yourself in Malaysia, but that’s another SSL). Cryptography is subject to export regulations by “the man”. This makes it somewhat illegal for the Apache Foundation to make available the pre-compiled binaries of Apache’s SSL support, which comprises of mod_ssl and OpenSSL. As a result of those restrictions you need to compile Apache+SSL on your own. While I don’t mind compiling Apache to get this working, I am aware that there are two reasons I’m willing to compile anything to make it work: (1) I’m used to UNIX; (2) I’m used to Linux. If you come from a Windows world you probably never had to compile anything; moreover you’re most likely to not even have access to development tools. Luckily for you, me and everyone else good people have pre-compiled Apache+SSL for us — Download their package .This package also contains binaries of OpenSSL, which you will also need to get things up and running. The download is a ZIP file which contains the entire Apache package — for simplicity’s sake, unpack it to c:apache.
First let’s make sure the basic settings in the httpd.conf file which came with the package are OK: look for the ServerRoot, DocumentRoot and Directory directives and verify they point to the directory you unpacked the Zip file in. For example, if you installed Apache in “d:apache”, and you find the following in the configuration file:
you should change the value to “d:/apache”. Note that you should use a UNIX-style slash (“/”), and not a Windows-style slash (“”). The default file listens to port 80 (for clear-text regular HTTP) — if you want it listening in some other port change it in the Listen directive. Now would be a good time to just start the Apache server and make sure it’s working by navigating to your server’s host-name with the port you set in the Listen directive (80 if you haven’t changed anything.) You should see the standard Apache greeting page.
Generating an SSL Certificate
If you have a bona-fida SSL certificate, use it. For testing purposes we’ll just generate our own using OpenSSL. If you have cygwin installed with OpenSSL you can just use it from there (use the same commands listed here but omit the “-config openssl.cnf” part). If you don’t have cygwin (or you don’t even know what the heck cygwin is), have no fear — the OpenSSL executable is included with Apache+SSL Win32 package. The only thing missing is a configuration file, but luckily for us the good people who created the aforementioned how-to guide have supplied us with one — download it — right click the link and select “Save As…” and save it in the bin/ directory under your Apache directory (the directory with Apache.exe and OpenSSL.exe) Open a command prompt in the bin/ directory of Apache. The next step is to run a series of commands to issue the SSL certificate. You will be asked all kinds of questions about the country you’re in, the company you work for, etc etc — in a test certificate it doesn’t really matter what you enter. What you should notice is that when you’re asked for a “Common name” (it sometimes even says “YOUR name”), what it means is the exact host name of the reverse-proxy server (for example, revproxy.company.com). Run the following commands:
openssl req -config openssl.cnf -new -out my-server.csr openssl rsa -in privkey.pem -out my-server.key openssl x509 -in my-server.csr -out my-server.cert -req -signkey my-server.key -days 365
Create a directory called SSL under the Apache conf/ directory, and move the files my-server.key and my-server.cert from where you ran OpenSSL in to the new directory. You should also move all the other generated files to a secure directory on your server.
Activating and configuring mod_ssl
A small checklist before we move forward:
- You have downloaded the Apache+SSL package and decompressed it to your hard-drive
- You have verified that the ServerRoot, DocumentRoot and Directory directives point to the right location
- You have generated the test certificates and placed them in conf/ssl (or in case you have a real SSL certificate you’ve placed its .cert and .key files in the same directory
- You drank a good cup of coffee today (optional)
If you passed the checklist, you’re good to go on to the next step. Open httpd.conf in your editor and find the LoadModule directive which loads mod_ssl; it should like something (if not exactly) like this:
#LoadModule ssl_module modules/mod_ssl.so
Remove the “#” to tell Apache to load the module. Now we need to actually enable SSL to our server. Firstly we want to make sure Apache listens on the SSL port, 443. To do that we’ll add a Listen directive to port 443, like so:
It would be best if you add the new Listen directive right below the Listen directive which handles port 80 (or 8080, or whichever port you use for HTTP). If you need this server to support only HTTPS you can simply change the
Listen 80 directive to
Listen 443 and be done with it. mod_ssl has its set of directive which configure it. Add the following directives somewhere in the httpd.conf file (doesn’t really matter where):
SSLMutex default SSLRandomSeed startup built in SSLSessionCache none
These three directives jump-start mod_ssl. You can read more about them in mod_ssl‘s documentation if you’re interested. (note: the Apache+SSL Win32 how-to lists
SSLMutex sem as the directive to use; “sem”, however, is only supported under POSIX or SystemV, both of which are from the UNIX world — it doesn’t work on Windows; default tells mod_ssl to use the best available locking mechanism according to the platform it runs on) The next set of directives to add are the following:
SSLEngine On SSLCertificateFile conf/ssl/my-server.cert SSLCertificateKeyFile conf/ssl/my-server.key
I’ve split these directives to two parts for a reason — if you’re using VirtualHosts in your Apache server you’ll want to put the second set of directives only in the websites which will run using SSL write references to the right SSL certificate for each website. (in a nutshell — the VirtualHost directive lets Apache serve different web-servers from a single Apache instance; you could, for example, have it reverse-proxy a few portals, or have it reverse-proxy using HTTP from one host name and using HTTPS from a different host name) You could test the SSL setup at this point — start Apache and navigate to https://hostname and see if you get the Apache welcome page.
Adding reverse-proxying to the mix
Now that we’ve got SSL up & running (finally!) it’s time to make sure the reverse-proxy still functions. We’ll start by configuring Apache to be an SSL terminator, which means end-users will connect using HTTPS to Apache, which will forward the requests to the internal server using HTTP, get the results back from the internal server using HTTP and send back over HTTPS to the client. Here’s how the mod_proxy directives should look like:
#Enable reverse-proxying ProxyVia on ProxyTimeout 600 #disable forward-proxying ProxyRequests Off #proxy /irj both ways ProxyPass /irj http://internal.company.com:50000/irj ProxyPassReverse /irj https://external.company.com/irj #proxy /logon both ways ProxyPass /logon http://internal.company.com:50000/logon ProxyPassReverse /logon https://external.company.com/logon
If this looks oddly familiar it’s because this is almost the same directives we used in the The Reverse Proxy Series — Part 2: IIS as a reverse-proxy in this series, almost being the key-word here. The only difference is the fact that in both
ProxyPassReverse directives we write “https://” instead of “http:// when referring to the reverse-proxy host. Yes, it’s that simple. The next (and last!) thing we need to do is make a tiny change to the ProxyMapping property in the J2EE engine. You can read all about that property and its purpose at the end of the The Reverse Proxy Series — Part 2: IIS as a reverse-proxy in this series. The only thing we need to change is to make sure the protocol is set to “https” instead of “http”, and the port set to the SSL port, 443, instead of 80. So, the property’s value would look something like this (your portal’s port might be different then 50000, and rev-proxy.corporate.com should be replaced by your reverse-proxy’s host name):
Make sure you click both “Update” and the save button (it has a disk icon) to apply the changes.
That should be it — Apache should be reverse-proxying your portal using SSL between end-users and the reverse-proxy. If you want to use SSL all the way you’ll need to enable SSL on the J2EE engine (I won’t get into that now; plenty of documentation about that), and change the mod_proxy directives to forward requests using https instead of http. If you’re having trouble with that kind of setup you might need to look into enabling mod_proxy_connect and using the AllowCONNECT directive of mod_proxy.
Find yourself tasked to reverse-proxy a portal which exposes web-applications from 4 other hosts? Think there’s no way you’re going to do it from one reverse-proxy? The next article will tell you how to use mod_rewrite to handle complex reverse-proxying scenarios.