Simplified Apache Redirecting

A graphic of a computer, lamp, and coffee cup with the Caxy logo.

tl;dr: Here is an easy way to configure Apache to redirect multiple domains to a single SSL version of a website with 'www' at the beginning of the URL, without using mod_rewrite.

The open internet is a magnificent technical achievement by mankind, but it also can be a dangerous place. If you run a website these days, there really is no excuse for not encrypting all the traffic too and from your site. For websites, this is done via SSL and SSL certificates.

Back in the day, arguments could be made that encrypting all traffic added an extra processing burden to a website that gets magnified if the site experiences high traffic. The increased processing power of modern CPUs has made this cost trivial. Back in the day, SSL certificates were expensive so an SSL certificate only came into consideration if the site needed it, and most of the time this was for any kind of e-commerce.

Today, thanks to Let's Encrypt, SSL certificates are free and easier than ever to set up. If you need any more convincing, there are more articles here and here. If you are not convinced, did you know Google has started giving sites a ranking boost for using SSL? Additionally, there is a case to be made for having one 'canonical' url for your website, and the canonical version being the one that starts with www. 

If you manage server running Apache, at some point you've probably had to delve into Apache's configuration. Apache's configuration can get incredibly sophisticated and complex. So sometimes cutting through all the information to come up with a simple configuration setup can be a challenge. 

The following is a straightforward way to structure an Apache config to get all the entry-points to your website to end up on the SSL/www URL for your site (for example: https://www.example.com)

Please note that there are a lot of options to accomplish the same things using Apache's RewriteEngine or mod_rewrite. So yes, one could create the same config that functions in the same way, using less lines of code and complicated Rewrite statements. I've chosen to avoid this at the cost of a longer config as I believe the longer config is more clear about what is going on. Additionally, there is a performance hit for invoking the RewriteEngine and Apache's own documentation recommends avoiding it if possible:

mod_rewrite should be considered a last resort, when other alternatives are found wanting. Using it when there are simpler alternatives leads to configurations which are confusing, fragile, and hard to maintain.

The way this works is that the server has two ports to listen for requests on: port 80 for http requests and port 443 for https requests. On each port, it needs to listen for both www and non-www urls for the domains you want to configure. And it needs to redirect all the requests to port 443 and the www version of the url. 

In this example, the main domain is example.com, and you want to redirect everything to https://www.example.com. You also have two extra domains (example1.com and example2.com) and you want both of these redirecting to the https://www.example.com

(This is an example of the Apache configuration file for one site. This example, on it's own, is not a functioning config. I assume you have access to these files and understand where they go and what else is needed.)

<VirtualHost *:80>
  # This catches the non-SSL requests to example.com and redirects to SSL.
  ServerName example.com
  ServerAlias www.example.com
  Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:80>
  # This is optional and for an extra domain that you want to redirect to the main domain
  ServerName example1.com
  ServerAlias www.example1.com
  Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:80>
  # This is also optional and for an extra domain that you want to redirect to the main domain
  ServerName example2.com
  ServerAlias www.example2.com
  Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:443>
  # This is for your main domain, to catch the non-www SSL requests and redirect to www.
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
  ServerName example.com
  Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:443>
  # This is for your extra domain, to catch the SSL requests (both www and non-www) and redirect 
  # to the main domain
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
  ServerName example1.com
  ServerAlias www.example1.com
  Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:443>
  # This is for your extra domain, to catch the SSL requests (both www and non-www) and redirect 
  # to the main domain
  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
  ServerName example2.com
  ServerAlias www.example2.com
  Redirect permanent / https://www.example.com/
</VirtualHost>

<VirtualHost *:443>
  # This is the main block in your config and where all the action should happen. 

  SSLEngine on
  SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
  SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem

  ServerName www.example.com

  DocumentRoot /var/www/html/www.example.com/docroot/

  # All the rest of the config goes in this block
  # The rest of the config has been stripped for the sake of this example. 

</VirtualHost>

<VirtualHost *:80> These blocks handle the unencrypted/http requests. So you'll need one of these to catch the www and non-www requests for your main domain and redirect them to the canonical url. You'll also need one of these for each of the extra domains you have that you want to redirect to the canonical domain and url. 

<VirtualHost *:443> These blocks handle the encrypted/https reqeusts. So you'll need one of these to catch requests to https://example com and redirect to https://www.example.com. You'll also need one of these for each of the extra domains to redirect to the main domain. 

What this config does not do, by itself, is prevent the browser errors that occur warning the user that the browser cannot validate the site. This will be covered in a follow-up post.