
Set up subdomains with Apache and Nginx
Sublet
The shortage of addresses and the quest for efficient resource usage established web server virtualization well before the topic of virtual machines and containers gained its current prominence. In this article, I demonstrate how to use different fully qualified domain names (FQDNs) on the same physical system with virtual hosts.
Virtual Hosts
In the mid-1990s, a single web server (usually the Apache server, which quickly became the de facto standard on Linux) typically ran with a single IP address. Once installed and configured, it reliably delivered a web page – always the same page – after requests to that IP address.
Not only was it impractical to have a separate computer for each web server, no matter how small, but IPv4 addresses were becoming scarce. Virtualized hosts didn't exist yet, so in version 1.1 the Apache developers conjured up the strategy of virtual hosts as a solution. Suddenly it didn't matter how many FQDNs pointed to the same IP address: The web server took care of the correct distribution of requests.
That's why the web browser doesn't just contact the plain vanilla IP address that it gets from the domain name server (DNS) after resolving the FQDN, it additionally specifies the desired host name directly after the GET
request with a HOST
specification (e.g., over Telnet on port 80, as in Listing 1).
Listing 1: Virtual Host Output
$ telnet www.wintermeyer.de 80 Trying 89.221.14.204... Connected to www.wintermeyer.de. Escape character is '^]'. GET / HTTP/1.1 HOST: www.wintermeyer.de HTTP/1.1 301 Moved Permanently Server: nginx/1.10.3 Date: Fri, 27 Nov 2020 14:00:25 GMT Content-Type: text/html Content-Length: 185 Connection: keep-alive Location: https://www.wintermeyer.de/ <html> <head><title>301 Moved Permanently</title></head> <body bgcolor="white"> <center><h1>301 Moved Permanently</h1></center> <hr><center>nginx/1.10.3</center> </body> </html>
In this example, the web server responded with a 301 Moved Permanently HTTP response, which means that the resource no longer exists and the new URL should be used because the server no longer delivers the web page over HTTP, but only has an SSL-encrypted version over HTTPS. To make life as easy as possible for end users and search engines, the server operator then defines a 301 redirect. In this case, the browser tries a second request to the new URL. For temporary rather than permanent redirection, you need to use HTTP status code 302.
With SSL encryption, you have no way around this functionality, even if you have the luxury of a dedicated IP address for your web server.
Apache vs. Nginx
Even though Apache was one of the pioneers, if not the decisive pioneer for stable and fast web servers on Linux, Nginx has a slightly higher market share today. As of January 2021, it accounts for 33.3 percent of all web servers worldwide, compared with 26.4 percent for Apache [1]. As you can see, both web servers are very popular in the community, so in the following examples, I look at the configuration for both Nginx (with Server
blocks) and Apache (with VirtualHost
blocks).
The starting point will be a freshly installed Debian 10.6 "Stable," on which I configure virtual hosts for the imaginary domains http://www.example1.de and http://www.example2.de. The packages from the distribution's repository will come into play. The IP address for the server is 192.168.2.120.
Apache
The first task is to install the web server. In Apache's case, you can use:
# apt-get update # apt-get -y install apache2
To check that the web server is installed and running, enter:
systemctl status apache2
The default website can be retrieved by pointing a web browser to http://192.168.2.120. The website returned is located in the /var/www/html/index.html
file.
For each of the two new web pages, you create a separate directory:
# mkdir /var/www/www.example1.de # mkdir /var/www/www.example2.de
In each of the two directories, store an index.html
with the content from Listing 2, each with an appropriately customized domain name. Then, set the permissions to rwx-rx-rx
Listing 2: index.html
<html> <head> <title>Test for www.example1.de</title> </head> <body> <h1>Test for www.example1.de</h1> </body> </html>
# chmod -R 755 /var/www/www.example{1,2}.de
for these directories.
Configuring Apache
The configurations for the web servers available and enabled on the system are located in the directories shown in Listing 3. Now you need to create a minimal basic configuration for http://www.example1.de in /etc/apache2/sites-available/www_example1_de.conf
(Listing 4), and do the same for http://www.example2.de.
Listing 3: Configuration Directories
# tree /etc/apache2/sites-* /etc/apache2/sites-available --- 000-default.conf default-ssl.conf /etc/apache2/sites-enabled --- 000-default.conf -> ../sites-available/000-default.conf
Listing 4: Minimal Configuration
<VirtualHost *:80> ServerName www.example1.de DocumentRoot /var/www/www.example1.de/ </VirtualHost>
The two configurations are not yet live, however, so you either need to link the configuration files manually with /etc/apache2/sites-enabled/
or use the a2ensite
tool:
# a2ensite www_example1_de.conf
The next step is to tell Apache to parse the new configuration and make the virtual hosts available:
# systemctl reload apache2
Again, you can use Telnet to test this, as in Listing 1.
To disable a virtual host, you could delete the corresponding link with rm
; however, it is better to use the appropriate tool and parse the changed configuration:
# a2dissite www_example1_de.conf # systemctl reload apache2
To make your work as easy as possible as an admin, you will want to use only one FQDN per configuration file, but feel free to use it for both HTTPS and HTTP. Technically you could put 100 different FQDNs in one file, but that would be far more confusing.
Redirects with Apache
One simple example of the use of virtual hosts for the same FQDN is redirecting all http://example1.de to http://www.example1.de, which might also work the other way around, depending on what the marketing department or in-house search engine optimization guru thinks is more fashionable at the moment. The file /etc/apache2/sites-available/www_example1_en.conf
has to contain the code from Listing 5. To test, run:
Listing 5: Redirects
<VirtualHost *:80> ServerName example1.de Redirect permanent / http://www.example1.de/ </VirtualHost> <VirtualHost *:80> ServerName www.example1.de DocumentRoot /var/www/www.example1.de/ </VirtualHost>
curl -I http://example1.de
This command outputs the headers and initially returns a 301 Moved Permanently status message stating the new location, http://www.example1.de. The command
curl -I http://www.example1.de
should then generate the output from Listing 6.
Listing 6: Accessing a Redirected Website
HTTP/1.1 200 OK Date: Sat, 28 Nov 2020 08:25:05 GMT Server: Apache/2.4.38 (Debian) Last-Modified: Fri, 27 Nov 2020 17:20:15 GMT ETag: "85-5b519dfafde34" Accept-Ranges: bytes Content-Length: 133 Vary: Accept-Encoding Content-Type: text/html
Nginx
Nginx also needs to be set up according to the previous example,
apt-get -y install nginx
which you can check with systemctl
as demonstrated earlier to make sure it is up and running. The default page is at http://192.168.2.120, which resides in the /var/www/html/index.nginx-debian.html
file.
For the two new Nginx web pages, you will again be creating separate directories, storing suitable index.html
files, and setting appropriate permissions in each case, as demonstrated in the Apache example.
Configuring Nginx
The configuration for the web servers available and enabled on the system is located in the directories shown in Listing 7. Now you can create a minimal basic configuration for http://www.example1.de in the /etc/nginx/sites-available/www.example1.de
file (Listing 8), and do the same for www.example2.de
.
Listing 7: Configuration Directories
# tree /etc/nginx/sites-* /etc/nginx/sites-available --- default /etc/nginx/sites-enabled --- default -> /etc/nginx/sites-available/default
Listing 8: Minimal Configuration
server { listen 80; server_name www.example1.de; root /var/www/www.example1.de; index index.html; }
Again, you need to fire up both configurations by first manually linking the configuration files:
# ln -s /etc/nginx/sites-available/www.example1 .de/etc/nginx/sites-enabled/
Then, tell Nginx to parse the new configuration, making the virtual hosts available:
# systemctl reload nginx
Again, test the new configuration manually over Telnet as before. To disable a virtual host, just use rm
to delete the matching link and reparse the configuration. In terms of the number of FQDNs per configuration file, the same applies as for Apache.
Redirects in Nginx
As a simple example of the use of virtual hosts for the same FQDN, you will again be redirecting all http://example1.de to http://www.example1.de (Listing 9). After reloading the configuration, it's time for another test with curl -I
.
Listing 9: sites-available/www.example1.de
server { listen 80; server_name example1.de; return 301 http://www.example1.de$request_uri; } server { listen 80; server_name www.example1.de; root /var/www/www.example1.de; index index.html; }
SSL with Let's Encrypt
Let's Encrypt [2] is the easiest way to get SSL working on your web server. Fortunately, the approach is identical for Apache and Nginx, except for one small parameter in the script call.
The installation of Let's Encrypt relies on the Snap package manager, which can be installed with:
# apt-get -y install snapd [... New registration ...]
At this point you have to log off and log back on again to make sure that all paths are set correctly; then, set up Let's Encrypt with the commands:
# snap install core # snap install --classic certbot # ln -s /snap/bin/certbot /usr/bin/certbot
The next command is a call to Certbot with either --apache
or --nginx
as parameters. For Apache, that would be:
# certbot --apache
At this point, Certbot asks for a valid email address and then for the FQDN to be activated. The Certbot script automatically configures the FQDN selected in this process and adjusts the Apache or Nginx configuration accordingly.
The charming thing about this process is that the system now takes care of updating the certificates without any further intervention. The new web server can now only be reached at https://www.example1.de, and it automatically redirects requests to http://www.example1.de to HTTPS with a 301.