How to Redirect an HTTPS Website From WWW to non-WWW (or the other way around)

I like to run my sites without a www. You’re looking at this site like that i.e. https://bash-prompt.net.

Some traffic always arrives at https://www.bash-prompt.net which sometimes breaks things, especially with dynamic sites.

This problem can be solved using the Apache module mod_rewrite. But I’ve had problems with that and it’s an overcomplicated way to do things.

The problem is more easily solved using Apache’s Redirect directive supplied by mod_alias.

What we’re going to do is to:

  1. Generate an SSL certificate for both WWW and non-WWW hostnames.
  2. Create a new VirtualHost for the undesired hostname (www or non-www) that redirects the visitor.

Generate a multi-hostname SSL certificate

This is required because traffic arriving at the WWW hostname e.g. https://www.example.com first has to complete the HTTPS interaction before it can receive the redirect response from Apache.

You can get a wildcard SSL from Let’s Encrypt but it’s more work than getting a multi-hostname certificate.

You can read my guide on doing that here or use the following command (for example.com and www.example.com hostnames):

# certbot certonly --expand -d example.com -d www.example.com

You can now use this certificate and key in the WWW and non-WWW VirtualHost files.

Step 2 - Preparation

First, make sure that the mod_alias module is enabled and reload Apache:

# a2enmod alias
# systemctl reload apache2

Next, remove the undesired hostname (usually it’s a ServerAlias) from the existing VirtualHost file. In the following I want to redirect all traffic from https://www.example.com to https://example.com.

This would be the relevant section of the VirtualHost file for this site:

<VirtualHost 1.2.3.4:443>

    DocumentRoot /var/www/example-com
    ServerName   example.com
    ServerAlias  www.example.com

</VirtualHost>

This becomes:

<VirtualHost 1.2.3.4:443>

    DocumentRoot /var/www/example-com
    ServerName   example.com

</VirtualHost>

Step 3 - Create the new, redirecting HTTPS WWW VirtaulHost

Create a new VirtualHost file for https://www.example.com which will include the Redirect instruction and the certificate you just generated:

<VirtualHost 1.2.3.4:443>

    DocumentRoot /var/www/example-com
    ServerName   www.example.com

    Redirect permanent / https://example.com

    SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf

</VirtualHost>

Reload Apache again to get the new config live.

Apache will now reply with an instruction to the requesting client that the requested URL/page/file etc has a new location with a 301 Permanent Move response.

Here’s the curl output for requesting https://www.bash-prompt.net:

# curl -Ia http://www.bash-prompt.net/guides/openssl-benchmark/index.html
HTTP/1.1 301 Moved Permanently
Date: Mon, 31 Jul 2023 07:47:59 GMT
Server: Apache/2.4.57 (Debian)
Location: https://bash-prompt.net/guides/openssl-benchmark/index.html
Cache-Control: max-age=172800
Expires: Wed, 02 Aug 2023 07:47:59 GMT
Content-Type: text/html; charset=iso-8859-1

Everything after the hostname i.e. /guides/openssl-benchmark/index.html is preserved in the redirect response.