Amazon.co.uk Widgets

Apache Virtual hosts using Let's Encrypt for Ubuntu 22.04 (22.0.4.1 LTS)

Virtual Hosts with SSL, isn't that hard?

The Apache HTTP Server has always had a virtual hosts feature to serve multiple differently named websites from the same server. Setting it up with SSL is more complex than it perhaps ought to be, and that is probably historical given that the project it named after HTTP it was centred around http and https was originally an additional, often expensive and complex configuration step.

This seems outmoded to me. Traffic encrypted to the web browser with https is mandatory for any serious web presence. http is an insecure protocol that should really be a secondary consideration. Anyway, it is what it is.

With virtual hosts, each individual site appears to the end-user to have a different identity even though it is served from the same server. Hosting providers use this technology to provide resilience, security, scale, analytics and for many other reasons but it is also useful for developers who want to have a replica small scale development or staging environment perhaps for multiple websites. A development environment is my reason for building out Apache 2 virtual hosts with separate Let's Encrypt certificates on my Ubuntu Linux machine.

To make it work, you need to think about setting out the directory structure on your Linux machine, the Virtual Hosts configuration files for Apache2, and a properly resolving DNS record to the Linux machine hosting your virtual host site. Setting it up is easy enough but takes a little bit of concentration on the details of all these moving parts. Adding SSL to these virtual hosts is far less tricky than it once was because 'Let's Encrypt' does most of the heavy lifting now.

You'll need

  • Ubuntu Desktop 22.04.1 LTS updated to latest.
  • An administratrive user that can 'sudo'.
  • Let's Encrypt 'certbot' installed and a good understanding of Linux locations and editing tools.
  • An IP address on your Linux machine that is reachable from the Internet. This can either be fixed or dynamic via 'ddclient'.
  • Local DNS, sometimes called 'split DNS', perfectly set up for your local area network or a hosts file with entries for the names pointing at the local IPv4 address of the Linux machine.
  • The domains you wish to use for your virtual hosts set up to use that IP address or an alias that resolves to it.

TL:DR I now have two dev sites on my local Ubuntu Desktop. Both have valid Let's Encrypt SSL certificates and are working well locally and via the Internet. It took about 45 minutes to set up.

How you can set up Apache 2 Virtual hosts using Let's Encrypt for Ubuntu 22.04

1. Set out the directory structure for the individual web sites on your Linux machine

Apache looks for the site to serve in \var\www and may already have a site or holding page in /var/www/html. Create the virtual host directories in in \var\www. We will use the convention of using a public_html folder as the document root to denote content that is going to be visible on the Internet. The root level of your virtual host can be used for private scripts and utilities that won't be visible on the Internet. Replace virtual_host_domain_name_one  and virtual_host_domain_name_two with the real domain names you plan to use.

% sudo mkdir -p /var/www/virtual_host_domain_name_one/public_html
% sudo mkdir -p /var/www/virtual_host_domain_name_two/public_html

2. Set the file permissions

By default this Apache installation uses www-data as the Apache user. This is a development machine, so the developer user needs to be able to control all the files and the Apache web server user needs to be able to serve them. I suppose you could enable the user www-data but I have my own local user.

% cd /var/www

% sudo chown -R $USER:www-data /var/www/ *

3. Create A first default page for each virtual host

Ceate a minimal HTML5 document for each index.html file. It will be replaced so this is just for testing.

<html lang="en">  
  <head>
    <meta charset="utf-8">
    <title>Virtual Host</title>
  </head>
  <body>
    <p>Hello, world</p>
  </body>
</html>

Set its ownership to $USER:www-data and copy it to the public_html folder for each virtual host.and

% cd /var/www/virtual_host_domain_name_one/public_html
% cp index.html ../../virtual_host_domain_name_two/public_html

4. Create virtual host configuration files for Apache2

Apache uses configuration files called conf files to set our the virtual host information it needs to find the directories you created and make them available through the web server.

You can find them in /etc/apache2/sites-available You can see one of mine below. It sets the name of the server, the admin email address, the document root we created on the filesystem, and places error and access logs in the servers directory above the public html directory. Then it has some directory options for security, and a rewrite rule to make all web requests use SSL. (SSL will be set up shortly using Let's Encrypt). Just replace virtual_host_domain_name_one with your domain name to use it. Create one for each host, taking care to ensure the directories are the ones you previously created.

<VirtualHost *:80>
  ServerName virtual_host_domain_name_one
  ServerAdmin admin@virtual_host_domain_name_one
  DirectoryIndex index.html index.php 
  DocumentRoot /var/www/virtual_host_domain_name_one/public_html 
  ErrorLog /var/www/virtual_host_domain_name_one/error.log 
  CustomLog /var/www/virtual_host_domain_name_one/access.log combined 
  
<Directory /var/www/virtual_host_domain_name_one/public_html> 
      Options FollowSymLinks 
      AllowOverride All 
      Require all granted 
  </Directory> 
RewriteEngine on 
RewriteCond %{SERVER_NAME} =virtual_host_domain_name_one
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent] 
</VirtualHost>

5. Enable the site

Once you create the conf file you need to enable it using a2ensite so that the apache web server can see it. % sudo a2ensite virtual_host_domain_name_one does this. Check for any errors, and restart the Apache web server and your virtual host is enabled. Next you can apply an SSL certificate to it automatically using Lets Encrypt, but there are a couple of things to do first.

6. DNS

There is a saying among the cloud technical support community that the answer to any Internet problem "is always DNS!", and it is often true. DNS resolution is the process by which your domain name is looked up and an IP address found for it. If it is not set up properly then your site won't work. If it is set up properly but your site is behind a router or firewall and the router or firewall is not set up properly it will not work. If it is set up properly your site will probably still not work from your internal network but will probably work from the Internet. It seems complicated but honestly there are just a few steps to take to make sure it works reliably and well.

  • Log in to your DNS provider
  • Set up an A record for virtual_host_domain_name_one and point it at the external IPv4 address of your router/firewall
  • Continue to the next step to set up Port Forwarding for port 443 (and Port 80), to the internal IPv4 address of your Linux machine

7. Port forwarding

Router port forwarding (This is a Ubiquiti Edge Router Lite - yours will be different and that isn't the real IP address)

8. Development machine /etc/hosts file

Also, unless you have a DNS server in your own environment you'll need to add virtual_host_domain_name_one and virtual_host_domain_name_two to your local Linux hosts file /etc/hosts so that they resolve correctly on this local machine if you want to use them say from a web browser installed locally.

127.0.0.1	localhost virtual_host_domain_name_one virtual_host_domain_name_two 

9. Get your SSL certificates from Let's Encrypt

Assuming you've done all that and installed Let's Encrypt it is awesomely simple!

Once you are satisfied your connectivity is working then you can run the certbot tool.

sudo certbot
[sudo] password for yourusername: 
Saving debug log to /var/log/letsencrypt/letsencrypt.log

Which names would you like to activate HTTPS for?
We recommend selecting either all domains, or all domains in a VirtualHost/server block.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: virtual_host_domain_name_one
2: virtual_host_domain_name_two
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel): 

That's it. You should now be able to 'see' your `Hello, world` page in a secure browser.

Success - Click the Padlock in the toolbar to see the certificate details

If it isn't working check that your domain name is really resolving to your server IP address, and check you don't have a firewall blocking access. Add an inbound firewall rule if necessary.


References

See also: