May 1, 2020

Configuring Nginx to serve multiple domains

Prerequisites We assume that the server is running on Ubuntu 18.04; for other operating systems, kindly look for the equivalent commands for OS-specific features and paths. The configuration of Nginx will remain the same independent of the host OS.

Configuring Nginx to serve multiple domains

Prerequisites

We assume that the server is running on Ubuntu 18.04; for other operating systems, kindly look for the equivalent commands for OS-specific features and paths. The configuration of Nginx will remain the same independent of the host OS. We assume Nginx is already installed on the OS. If not,

sudo apt-get install nginx

should do the trick on Ubuntu.

We also assume you have static public IP for your server and a domain name pointing to it. You can get free domain names or buy some at cost price for your IP using freenom.com (Not a sponsored plug. See our post on this topic for more info).

Configuring multiple sites in Nginx

To create different sites to be served through Nginx, create configuration files in the sites-available folder of Nginx and then create a symbolic link for those files to be seen from the sites-enabled folder of Nginx. This process looks as follows on Ubuntu.

Create site-available files (Here we will configure two sites)

sudo nano /etc/nginx/sites-available/site1
sudo nano /etc/nginx/sites-available/site2

Add to each file* ( sitex corresponds to site1 or site2 depending on the file & ALL_CAPITALS denote value that the user needs to specify )

server {
  listen 80;
  server_name DOMAIN_NAMES_FOR_SITEX;
  location = /favicon.ico { access_log off; log_not_found off; }
  location SOME_RELATIVE_LOCATION_TO_SERVER_NAME { # Eg. sitex/static, static is the relative location
      root ROOT_FOLDER_RELATIVE_TO_WHICH_RELATIVE_LOCATION_NAMED_FOLDER_EXISTS; # eg. myfolder/static exists then root is myfolder
  }
  location LOCATION_TO_PASS_TO_ANOTHER_SERVER {  
      # OPTIONAL (SEE PROXY NOTE BELOW )
      include proxy_params;
      proxy_pass http://unix:/run/gunicorn.sock; # Eg. Pass traffic forward to a gunicorn server
  }
}

Once the files are created, link them to the site-enabled folder using

sudo ln -s /etc/nginx/sites-available/sitex /etc/nginx/sites-enabled

You can test your configuration files for syntax errors using

sudo nginx -t

If no errors are reported, you can restart the Nginx server.

sudo systemctl restart nginx
systemctl daemon-reload

 *We added a line "server{   listen 80; ... }" before the server_name line to enable access to the site using the insecure HTTP protocol. HTTP is typically unwanted, and we will see next, how a secure https access is configured.

Adding secure https access to your domains

We will use LetsEncrypt to set up a secure SSL certificate for our domain names. An excellent post describing the process in detail is available on the DigitalOcean community page [link to article]. I will not reinvent the wheel here and refer you to the page to set up certbot and obtain a secure SSL certificate for your domains as described there.

I will just briefly mention how the certbot can be used for our two sites, site1 and site2, used above.

1. Reload Nginx

sudo systemctl reload nginx

2. Obtain the SSL certificates  

( certbot requires incoming traffic through HTTP, so make sure that your firewall is not blocking it)

sudo certbot --nginx -d SITEX_DOMAIN -d www.SITEX_DOMAIN

When prompted for redirecting HTTP to HTTPS automatically, choose to redirect, i.e., given the options [1] No redirect, [2] Redirect, select "2". Certbot will automatically edit the Nginx configuration we did above for the SITEX domain name to listen to port 443 instead of port 80 and redirect traffic from port 80 to port 443 automatically.

3. Simulate an auto-renewal with certbot

Certbot automatically renews certificates when they are about to expire, and you can test this beforehand to make sure that you don't encounter any errors (the auto-renewal again requires HTTP access and shouldn't be blocked with a firewall)

sudo certbot renew --dry-run

If there are no errors, you are all set. If you get errors, kindly refer to the DigitalOcean community article linked above for troubleshooting or search for the encountered error on google or StackOverflow (typically others have also faced such errors before and you can find a fix there). If the above sources do not yield any result, you can ask a question in the comments below or post one on StackOverflow.
You can check the list of certificates using:

sudo certbot certificates

You can also delete any certificate and its associated files using

sudo certbot delete --cert-name NAME_OF_CERTIFICATE_TO_DELETE

4. Reload Nginx

sudo systemctl reload nginx

Now, if you repeated the above steps for both site1 and site2, you should have both the sites being served using the corresponding domain names over https.
Happy Coding!