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.
Contents
- Apache Virtual hosts using Let's Encrypt for Ubuntu 22.04 (22.0.4.1 LTS)
- Virtual Hosts with SSL, isn't that hard?
- 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
- 2. Set the file permissions
- 3. Create A first default page for each virtual host
- 4. Create virtual host configuration files for Apache2
- 5. Enable the site
- 6. DNS
- 7. Port forwarding
- 8. Development machine /etc/hosts file
- 9. Get your SSL certificates from Let's Encrypt
References
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
virtual_host_domain_name_one
is properly set up to resolve to your server external IP address from your DNS provider and is reachable via the Internet! On a local area network you will have to forward the SSL port 443 to your local machines IPv4 address through your router or firewall. Let's Encrypt is rate limited so test your connectivity before running the live certificate creation!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!
too many failed authorizations recently
. Test your connectivity before trying to get your certificate. The Let's Encrypt documentation site has tons of details on how to do that.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.
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:
- Let's encrypt is a nonprofit Certificate Authority providing TLS certificates to 300 million websites
- DDclient is a Perl client used to update dynamic DNS entries for accounts on Dynamic DNS Network Service Provider.
- The Apache HTTP Server Project is an effort to develop and maintain an open-source HTTP server for modern operating systems including UNIX and Windows