architecture,

Recipe - Multiple Domains - Single IP

Sumeet Sumeet Follow Feb 20, 2020 · 13 mins read
Recipe - Multiple Domains - Single IP
Share this

I get many questions about hosting multiple domains with their own web applications on single static IP. This post describes how to do the same using specific tools. In fact this is what I have been using for my personal usage as well. However, I never needed to do this for any production. This can be of great use if you are limited on resources and want to do some experiments in your own personal space. I am limiting my scope here due to a purpose. There will be a continuation blog where I would write about how I introduced Docker containers and CI/CD in this setup.

Multiple Domain Hosting

Let’s assume we have 3 different web applications to be hosted using 3 different domain names but on single machine with a single static IP (Referring to the image). All of these need not be based on same technology or require same runtime, in fact some of them might also be just static HTML files - you can think of as many permutations and combinations possible - this still applies. In order to make this work, let us take a look at setting up this server itself, before we deploy these applications.

Pre Requisites

  1. Provision a machine with a static IP. Now-a-days the obvious choice is a virtual machine on a reliable cloud platform. Preferably with a stable Linux distro and suitable power (RAM and CPU). Ubuntu Bionic Beaver is my favourite yet.
  2. Log in to the machine and create a user with super user permission. You probably have root access when you provision a brand new machine. In order to avoid the accidental risk associated with broad privileges of root user - this is necessary. You can also count this as a best practice.

Nginx Installation

  1. Install Nginx to be used as reverse proxy to your servers. In our example we are considering NodeJS applications which act as servers themselves. Below are the steps to do the same for Debian based distro.
    sudo apt-get update
    sudo apt-get install nginx
    
  2. Firewall settings.
    sudo ufw allow 'Nginx HTTP'
    
  3. Check if everything is successful.
    sudo systemctl status nginx
    
  4. It should give below output where Active: active (running)
    ● nginx.service - A high performance web server and a reverse proxy serv
       Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor pr
       Active: active (running) since Wed 2020-02-19 16:07:11 UTC; 1 day 3h 
         Docs: man:nginx(8)
     Main PID: 27613 (nginx)
        Tasks: 2 (limit: 2362)
       CGroup: /system.slice/nginx.service
               ├─27613 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
               └─27617 nginx: worker process
    
  5. You should keep below commands to manage this nginx process (start, stop, restart, status) handy.
    sudo systemctl stop nginx
    sudo systemctl start nginx
    sudo systemctl restart nginx
    sudo systemctl disable nginx
    sudo systemctl enable nginx
    sudo systemctl status nginx
    
  6. Some of the important files in Nginx: we shall discuss more about them in upcoming sections here.
    /etc/nginx/nginx.conf       #main nginx config file
    /etc/nginx/sites-available/ #directory for your server blocks
    /var/log/nginx/error.log    #nginx error logs
    

Web application deployment

  1. Since our’s are simple NodeJS apps, we would install NodeJS into our server. To make sure you get the desired version of NodeJS version, first enable the NodeSource Package repository. Don’t forget to choose your version by replacing ‘xx.x’ in below command.
    curl -sL https://deb.nodesource.com/setup_xx.x | sudo -E bash -
    
  2. Install NodeJS, Git and build-essentials.
    sudo apt-get install nodejs
    sudo apt-get install build-essential
    sudo apt-get install git
    
  3. Verify the installation of nodejs, npm and git.
    node --version
    npm --version
    git --version
    

    Corresponding output:

    v10.16.3             #example
    6.9.0                #example
    git version 2.17.1   #example
    
  4. Clone your apps from remote source into a specified directories.
    cd /
    sudo mkdir apps
    cd /apps/
    sudo git clone https://github.com/username/abc.git
    sudo git clone https://github.com/username/pqr.git
    sudo git clone https://github.com/username/xyz.git
    

    You should have below directory structure by now

    root
       |_apps
          |_abc
          |_xyz
          |_pqr
    
  5. Navigate to every app repository just cloned - and install npm dependencies by running npm install.
  6. Install pm2. PM2 is process manager for nodejs applications. We will use it to manage our nodejs application processes.
    sudo npm install pm2
    
  7. For each app cloned in step# 4, navigate to their respective directories and start the applications using pm2. Everything “started” with pm2 below are the respective “index.js” files for those applications - we will live with this assumption for the sake of this post.
    pm2 start abc.js
    pm2 start xyz.js
    pm2 start pqr.js
    

    Check the status of pm2 process by running and make sure all 3 applications are running. It is very important that all of your apps use different ports. Referring to the image above, the 3 applications are running on 5000, 5001 and 5002 ports.

    pm2 list
    
  8. You can do a quick test by running a quick test by curling to your localhost on specified ports for respective applications.
    curl http://localhost:5000    #should return the expected response
    

DNS Settings

  1. First step is to set up the name servers for the domain names you own from the registrar where you bought them. Get the name server urls from your hosting service provider (place where you provisioned your server virtual machine). Log into your registrar console and find manage DNS section. You will have a place to set up nameservers. Create custom nameserver records and add all the urls provided by the hosting service.
  2. Log in to your hosting service web console and find a section where you can create DNS records. There are several types of DNS records for various purposes that you can set you can find them in the link provided. However, we are concerned with A records which helps the internet traffic translate your domain name into an IP address. Make sure that the A records of all the domains point to the same IP address which is assigned to your virtual machine.

That’s pretty much it. It can take some time for this translation to be propagated to all the DNS servers around the world.

Setup up reverse proxy

  1. This is where the steps for the entire point of this post are described. I have faced multiple issues to achieve this thing - to an extent that out of frustration I have destroyed the VM (server) configured till now and created a new VM from scratch to redo the configurations. Below are the final set of steps which work for sure.
  2. In the ‘sites-available’ (/etc/nginx/sites-available/) folder of nginx installation there is a “default” file present. At this point you need to choose which would be your default application. As stated in the image above, application hosted on pqr.com domain is marked as default. You need to update the default file in this folder with respect to application belong to this domain OR application which is supposed to be accessed/hosted on this domain.
  3. Before editing this “default” file, make sure you create copies of this file for other applications to be hosted by executing below commands wrt to our example,
    sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/abc.com
    sudo cp /etc/nginx/sites-available/default /etc/nginx/sites-available/xyz.com
    

    So now we should have 3 files in /etc/nginx/sites-available/ directory as - default, abc.com, xyz.com.

  4. Open the default file in your favourite editor. Vim or nano. Find a block of code which is marked as “location”. Make sure you update it as below. Please notice that you also need to update the server_name with your domain names. These domain names should be the same as mentioned in your A records - we will discuss how to set A records in your DNS management. Please note, that since we want to serve the application running on port 5000 for pqr.com, we have made sure that we specify correct port in proxy_pass value.
    server_name abc.com www.abc.com;
    location / {
             proxy_pass http://localhost:5000;
             proxy_http_version 1.1;
             proxy_set_header Upgrade $http_upgrade;
             proxy_set_header Connection 'upgrade';
             proxy_set_header Host $host;
             proxy_cache_bypass $http_upgrade;
    }
    
  5. Repeat the same process for files abc.com and xyz.com. Make sure you assign correct values to server_name and correct port in proxy_pass. It is always going to be localhost and http as protocol. Requests which come from outside world as https, are first received at nginx, which queries appropriate applications using above location blocks.

Setting up SSL/TLS (out of the scope of this post)

This is something that you do for security. In order to make your web traffic secure you need to install appropriate certificates so that your sites can be reached over https.

  1. We would use ‘Let’s Encrypt's’ certbot to install and manage SSL/TLS certificates. Let’s Encrypt is a Certificate Authority and using certbot to install certificates is quick, easy and free.
  2. Log in to you server and install certbot.
    sudo add-apt-repository ppa:certbot/certbot
    sudo apt install python-certbot-nginx
    
  3. Allow https through firewall.
    sudo ufw allow 'Nginx Full'
    sudo ufw delete allow 'Nginx HTTP'
    
  4. Obtain the certificate for each of your applications.
    sudo certbot --nginx -d abc.com -d www.abc.com
    sudo certbot --nginx -d xyz.com -d www.xyz.com
    sudo certbot --nginx -d pqr.com -d www.pqr.com
    

    Running these commands will be followed by couple of questions, the options to which you can choose wisely - it’s not a rocket science. You should get a congratulatory message and you are good to go!

  5. Observe that all the nginx site-available config files have an additional block of code which is inserted by certbot to make your site secure.

Try out accessing these URLs from your web browser, and you should get respective responses.

Next Steps - This blog of mine is currently maintained very manually. I have not yet automated it - and I would like to automate it using CI/CD and Docker containers from DevOps world. This post marks the introduction and essential environment setup to do the same. The upcoming blog will be based on similar theme once I am successful. That blog will be posted automatically.

Join Newsletter
Get the latest news right in your inbox!
Sumeet
Written by Sumeet Follow
Hi, I am Sumeet, and I believe the world belongs to the doers. Here, I publish my technical tinkering experiences. I hope you like it!