High Availability (HA) refers to systems that are designed to be operational and accessible for a high percentage of time, minimizing downtime and ensuring continuous service availability. This is often achieved through redundancy, failover mechanisms, and load balancing.
- Apache (Web Server) Acts as the backend server that processes HTTP requests and serves web content. In this setup, multiple Apache web servers are used to serve the same content, ensuring that if one server fails, another can continue serving users without disruption.
- Nginx (Load Balancer)
Sits in front of the web servers and distributes incoming client requests across multiple backend Apache servers. This helps balance the load, prevent any single server from being overwhelmed, and improves the responsiveness of the web service - Keepalived (Failover Management) Works together with Nginx to provide fault tolerance. It manages a Virtual IP Address (VIP) that floats between two Nginx instances (Master and Backup). If the master load balancer fails, Keepalived promotes the backup node to master and assigns the VIP to it, ensuring uninterrupted access for users.
In this module, we will implement a High Availability Web Server Architecture that ensures reliable and uninterrupted web service delivery through the combination of load balancing, redundancy, and failover mechanisms.
The following diagram illustrates the high-level architecture of the High Availability Web Server setup

-
Client sends request to the Virtual IP (VIP) managed by Keepalived.
-
The VIP routes traffic to one of the Load Balancer nodes (Nginx):
-
If Load Balancer Master is available, it handles the traffic.
-
If the Master fails, Keepalived shifts the VIP to the Backup node.
-
-
Nginx forwards the request to one of the two Apache Web Servers, which serve the actual web content.
-
Keepalived ensures failover between the two Load Balancer nodes without service disruption.
| No | Virtual Machine | Spesifikasi | NAT | Host-Only | Internal Network |
|---|---|---|---|---|---|
| 1 | Load Balancer Master | 1 vCPU, 1 GB RAM | DHCP | 192.168.56.50/24 | 10.10.10.50/24 |
| 2 | Load Balancer Slave | 1 vCPU, 1 GB RAM | DHCP | 192.168.56.51/24 | 10.10.10.51/24 |
| 3 | Web Server 1 | 1 vCPU, 1 GB RAM | DHCP | 192.168.56.52/24 | 10.10.10.52/24 |
| 4 | Web Server 2 | 1 vCPU, 1 GB RAM | DHCP | 192.168.56.53/24 | 10.10.10.53/24 |
Each VM must be configured with three interfaces: NAT, Host-Only, and Internal Network. Edit file:
sudo vim /etc/netplan/50-cloud-init.yamlExample configuration for Load Balancer Master:
# This file is generated from information provided by the datasource. Changes
# to it will not persist across an instance reboot. To disable cloud-init's
# network configuration capabilities, write a file
# /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg with the following:
# network: {config: disabled}
network:
ethernets:
enp0s3: # NAT Interface (DHCP)
dhcp4: true
enp0s8: # Host-Only Interface (Static IP)
addresses:
- 192.168.56.50/24
dhcp4: false
enp0s9: # Internal Network Interface (Static IP)
addresses:
- 10.10.10.50/24
dhcp4: false
version: 2Apply the configuration changes
sudo netplan apply๐ Repeat this step on each VM, adjusting the IP addresses based on the table above.
Assign a unique hostname to each virtual machine based on its role, to help easily identify them
# For Load Balancer Master
sudo hostnamectl set-hostname lb-master
# For Load Balancer Slave
sudo hostnamectl set-hostname lb-slave
# For Web Server 1
sudo hostnamectl set-hostname web1
# For Web Server 2
sudo hostnamectl set-hostname web2๐ Reboot each VM so the terminal prompt updates to reflect the new hostname
sudo rebootTo allow all VMs to resolve each other's hostnames, edit the /etc/hosts file on each VM:
10.10.10.50 lb-master
10.10.10.51 lb-slave
10.10.10.52 web1
10.10.10.53 web2Save and exit. This will allow you to ping and communicate with each node using its hostname.
These steps should be executed on both Web Server 1 and Web Server 2
Update System Packages
sudo apt update -yInstall Apache Web Server
sudo apt install apache2 -yEnable Apache to Start Apache service
sudo systemctl enable --now apache2check Apache Service Status
sudo systemctl status apache2To test the Apache server with PHP, install the following packages
sudo apt install php libapache2-mod-php -yCreate a new directory for the website
sudo mkdir -p /var/www/websiteCreate an index.php file with sample content
sudo vim /var/www/website/index.phpExample content for Web Server 1
<h1>WEB 1</h1>
<?php phpinfo(); ?>on Web Server 2, cahnge the heading to "WEB 2" to help identify which server is responding during load balancing tests.
Create a new virtual host file
sudo vim /etc/apache2/sites-available/website.confAdd following Configuration
<VirtualHost *:80>
ServerAdmin webmaster@localhost
DocumentRoot /var/www/website
ServerName dinus.local
<Directory /var/www/website>
Options Indexes FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>Disable the default configuration
sudo a2dissite 000-default.confEnable the custom virtual host
sudo a2ensite website.confReload Apache to apply changes
sudo systemctl reload apache2To ensure load balancing and automatic failover, we will install Nginx and Keepalived on both Load Balancer Master and Load Balancer Slave nodes.
Update the package list
sudo apt update -yInstall Nginx
sudo apt install nginx -yInstall Keepalived
sudo apt install keepalived -yEnable and start both services
sudo systemctl enable --now nginx && sudo systemctl enable --now keepalivedCreate a new configuration file on both Load Balancer (Load Balancer Master and Load Balancer Slave) nodes
sudo vim /etc/nginx/conf.d/loadbalancer.confAdd the following configuration to set up Nginx as a load balancer
upstream web_backend {
server 10.10.10.52; # Web Server 1
server 10.10.10.53; # Web Server 2
}
server {
listen 80;
server_name dinus.local;
location / {
proxy_pass http://web_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}Check Nginx syntax for any errors
sudo nginx -tReload Nginx to apply the new configuration
sudo systemctl reload nginxNow we will configure Keepalived on both Load Balancer nodes to ensure automatic failover
edit the Keepalived configuration file
sudo vim /etc/keepalived/keepalived.confPaste the following configuration
vrrp_instance VI_1 {
interface enp0s8
state MASTER
priority 500
advert_int 1
unicast_src_ip 192.168.56.50
unicast_peer {
192.168.56.51
}
virtual_router_id 33
virtual_ipaddress {
192.168.56.100/24
}
authentication {
auth_type PASS
auth_pass udinus
}
}edit the Keepalived configuration file
vrrp_instance VI_1 {
interface enp0s8
state BACKUP
priority 100
advert_int 1
unicast_src_ip 192.168.56.51
unicast_peer {
192.168.56.50
}
virtual_router_id 33
virtual_ipaddress {
192.168.56.100/24
}
authentication {
auth_type PASS
auth_pass udinus
}
}After configuring both nodes,restart the Keepalived service on both Load Balancer nodes
sudo systemctl restart keepalivedVerify that the Virtual IP (VIP) is assigned to the Master node
ip aNow that everything is configured, we can test the High Availability setup
-
open a web browser and navigate to the Virtual IP address (192.168.56.100)

-
Refresh the page several times. You should see alternating content like WEB 1 and WEB 2, which confirms that Nginx is distributing traffic between both backend web servers.

-
try power off the Load Balancer Master node (lb-master) and refresh the page again. The VIP should automatically switch to the Load Balancer Slave node (lb-slave), and you should still be able to access the web application without interruption.

-
Or you can also test by stopping the Nginx service on the Master node and checking if the Slave node takes over.
sudo systemctl stop nginx- After stopping the Nginx service on the Master node, refresh the web page. The VIP should automatically switch to the Slave node, and you should still be able to access the web application without interruption.

In this module, we successfully implemented a High Availability Web Server Architecture using Apache, Nginx, and Keepalived. This setup ensures that web services remain available even in the event of server failures, providing a robust solution for maintaining continuous service delivery.