Using SSL in Apache for Certain Pages
Friday, 05 September 2008 00:00

A commenter in an earlier thread had a terrific question that we thought would make for a good post. The question was essentially, "How can I require the use of SSL for some pages of my site, but not for others?"

Assuming that you are using Apache's web server, and even possibly using it as a reverse proxy to host a J2EE server behind it (such as Tomcat or JBoss), this is relatively easy to setup. There are probably a number of different ways to accomplish this, but our approach has been that if the user hits a page that requires SSL, we will do a redirect to send them to the HTTPS version of the page.

Again, in our earlier post, we had shown the setup to enable SSL in Apache. Let's build upon that configuration. You will need to edit your Apache config file (for Windows it is typically conf/httpd.conf, for Ubuntu it may be under apache2/sites-enabled/000-default). Say that you are starting with a configuration similar to this:

NameVirtualHost *:80
NameVirtualHost *:443

<VirtualHost *:80>
  ServerName www.domain.com
  <Location />
    ProxyPass http://appserver:8080/
    ProxyPassReverse http://www.domain.com/
  </Location>
</VirtualHost>
<VirtualHost *:443>
  ServerName www.domain.com
  SSLEngine on
  SSLCipherSuite ALL:!ADH:! EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
  SSLCertificateFile "C:/cert.pem"
  SSLCertificateKeyFile "C:/private.pem"
  BrowserMatch ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
  <Location />
    ProxyPass http://appserver:8080/
    ProxyPassReverse https://www.domain.com/
  </Location>
</VirtualHost>


From here, what we'd like to do is add in redirects so that if the user connects to the wrong port, they get redirected to the correct one. For this, the Redirect and RedirectMatch commands can come in handy.

As an example, let's say that you want the directory /secure to require SSL. You might add a line like this:

Redirect permanent /secure https://www.domain.com/secure

So that your configuration would look like this:

NameVirtualHost *:80
NameVirtualHost *:443

<VirtualHost *:80>
  ServerName www.domain.com
  <Location />
    Redirect permanent /secure https://www.domain.com/secure
    ProxyPass http://appserver:8080/
    ProxyPassReverse http://www.domain.com/
  </Location>
</VirtualHost>
<VirtualHost *:443>
  ServerName www.domain.com
  SSLEngine on
  SSLCipherSuite ALL:!ADH:! EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP:+eNULL
  SSLCertificateFile "C:/cert.pem"
  SSLCertificateKeyFile "C:/private.pem"
  BrowserMatch ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0
  <Location />
    ProxyPass http://appserver:8080/
    ProxyPassReverse https://www.domain.com/
  </Location>
</VirtualHost>

Again, we added this line to say that if the user connects to port 80, and is requesting anything under the /secure directory, to redirect them to the HTTPS version.

You can also use the RedirectMatch directive to use regular expressions to control which directories should require SSL. As an example, say that you wanted any directory that starts with a number to require SSL:

RedirectMatch permanent ^/(\d.*)$ https://www.domain.com/$1

If inclined, you can also update your configuration so that if the user hits the HTTPS version of their site for pages that don't require SSL, you can send them back to the plain HTTP version. We'll leave this as an exercise for the reader, but feel free to leave comments if you need some help.