Loadbalancing using VagrantBox and Nginx

Prerequisite: Readers should be conversant with the concept of load balancers and be familiar with Linux (Ubuntu).

Setting Up the VagrantBoxes

Start by installing VirtualBox and Vagrant.

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
$ brew install --cask virtualbox
$ brew install --cask vagrant
$ brew install --cask vagrant-manager
$ vagrant init ubuntu/xenial64

In your terminal, navigate to any directory of your choice and create a VagrantBox (create two VagrantBoxes in different directories).

$ vagrant up
$ vagrant ssh

Enable port forwarding in one of the VagrantBoxes, by editing the Vagrantfile located in the directory your box was created.

Note In both VagrantFiles, uncomment the config.vm.network "public_network" and pick 1 which is WiFi, this is to allow your VMs to be on the same network:

Vagrant.configure("2") do |config|
  config.vm.box = "your_box_name"
  config.vm.network "forwarded_port", guest: 8000, host: 8000
  config.vm.network "forwarded_port", guest: 80, host: 80
end

Exit out of the Vagrantfile and run,

$ vagrant reload

For the second box, remember to uncomment the config.vm.network "public_network" and pick 1 which is WiFi, while editing the Vagrantfile:

Vagrant.configure("2") do |config|
  config.vm.box = "your_box_name"
  config.vm.network "forwarded_port", guest: 8080, host: 8080
end

Exit out of the Vagrantfile and run,

$ vagrant reload

The snippet specifies forwarding ports 80, 8080 and 8000 from the guest machine to ports 80 (load balancing), 8080 and 8000 (for the individual websites) on the host machines.

This means that any traffic coming to ports 80, 8080 and 8000 on your host machine will be redirected to ports 80, 8080 and 8000 respectively on the guest machine. This enables access to the websites' URLs from a browser.

Setting Up Nginx and the Websites

Install Nginx (from source) on both boxes, by running this script. Save the script and grant it execute permission.

#!/bin/sh

# Install Dependencies
sudo apt update -y && sudo apt-get install -y git build-essential libpcre3 libpcre3-dev zlib1g zlib1g-dev libssl-dev libgd-dev libxml2 libxml2-dev uuid-dev

# Download Nginx Source Code
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -zxvf nginx-1.24.0.tar.gz
cd nginx-1.24.0

# Build & Install Nginx
sudo ./configure \
    --prefix=/etc/nginx \
    --conf-path=/etc/nginx/nginx.conf \
    --error-log-path=/var/log/nginx/error.log \
    --http-log-path=/var/log/nginx/access.log \
    --pid-path=/run/nginx.pid \
    --sbin-path=/usr/sbin/nginx \
    --with-http_ssl_module \
    --with-http_v2_module \
    --with-http_stub_status_module \
    --with-http_realip_module \
    --with-file-aio \
    --with-threads \
    --with-stream \
    --with-stream_ssl_preread_module
sudo make && sudo make install

# Set NGINX systemd service file path
nginx_service_file="/lib/systemd/system/nginx.service"

# Create NGINX systemd service file
sudo tee $nginx_service_file > /dev/null <<EOT
[Unit]
Description=Nginx Custom From Source
After=syslog.target network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
ExecStop=/bin/kill -s QUIT \$MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOT

# Enable and Start Nginx service
sudo systemctl daemon-reload
sudo systemctl enable nginx
sudo systemctl start nginx

Run the script:

$ chmod u+x script.sh
$ ./script.sh

Clone the repository on the boxes

$ git clone https://github.com/Mbaoma/deimos-internship.git

Setting Up Box One as a Web server and Load Balancer

Move the website's folder into the /var/www/html folder and start the app:

$ cd Module\1
$ sudo mv /website1 /var/www/html
$ cd /var/www/html/website1
$ sudo apt-get update
$ sudo apt-get install nodejs npm -y
$ npm install
$ npm install express
$ sudo ln -s /usr/bin/nodejs /usr/bin/node
$ nohup node main.js &

Setup the configuration by editing the default file in the sites-available folder,

$ sudo nano /etc/nginx/sites-available/default

Then copy and paste this snippet in the file:

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html/website2;
    index index.html index.htm;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
        proxy_pass http://localhost:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Since I will also be using this VagrantBox (Virtual Machine), as my load balancer; I have to edit the configuration in the /etc/nginx/sites-enabled/default

# Create a symbolic link to enable the configuration
$ sudo ln -s /etc/nginx/sites-enabled/default
$ sudo nano /etc/nginx/sites-enabled/default

Copy ad paste this snippet into the file:

#setup loadbalancing

# Define the load balancing configuration
load_balancing_config='
http {
    upstream backend {
        server <vm-ip>:80;
        server <vm-ip>:8000;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://backend;
            proxy_set_header Host $host;
        }
    }
}

You can get the VM's IP by running:

$ ip addr show

In another box, move the website's folder into the /var/www/html folder and start the app:

$ cd Module\1
$ sudo mv /website2 /var/www/html
$ cd /var/www/html/website2
$ sudo apt-get update
$ sudo apt-get install nodejs npm -y
$ npm install
$ npm install express
$ sudo ln -s /usr/bin/nodejs /usr/bin/node
$ nohup node main.js &

At each step, when you set up a configuration, confirm if your configuration is correct by running:

# Verify the Nginx configuration
$ sudo nginx -t
$ sudo systemctl daemon-reload

# Restart Nginx for the changes to take effect
$ sudo systemctl restart nginx

Confirm if all works as expected

VM 1 - http://localhost:8080/ or http://<ivm-ip>:8080/

image

VM 2 - http://localhost:8000/ or http://<vm-ip>:8000/

image

Load balancer - http://<vm1-ip>

image

image

Refer to this repository, for more information and troubleshooting.

Toodles and good luck ✨.