HA Deployment
Although a standalone Nginx deployment is sufficient for most home lab needs, a high-availability (HA) deployment allows you to perform maintenance on the reverse proxy without affecting operational continuity.
The Nginx instance can be deployed as a VM or an LXC container.
This guide shows how to create a high-availability NGINX reverse proxy with:
- Active - Standby architecture
- A floating virtual IP automatically assigned to the active NGINX node
- Proxy configurations automatically synced between both Nginx nodes
Tested Environment
Role | Specs | Operating System | Nginx Version | Hostname | Interface 1 | Interface 2 |
---|---|---|---|---|---|---|
Active Proxy | 1 vCPU / 512 MB RAM / 8 GB Disk | Ubuntu 24.04 Server (Noble Numbat) | 1.24.0 | proxy1.aadya.tech | eth0: 10.12.20.61 | eth1: |
Standby Proxy | 1 vCPU / 512 MB RAM / 8 GB Disk | Ubuntu 24.04 Server (Noble Numbat) | 1.24.0 | proxy2.aadya.tech | eth0: 10.12.20.62 | eth1: |
Virtual IP Address (VIP): 10.12.99.50
Architecture
graph LR
User -->|Request| VIP(Virtual IP Address)
subgraph NGINX Reverse Proxy
VIP(Virtual IP Address)
RP1(Reverse Proxy 1)
RP2(Reverse Proxy 2)
VIP -- Active --> RP1
VIP -. Standby .-> RP2
end
subgraph Backend Servers
RP1 -->|Forward Request| app1[App 1]
RP1 -->|Forward Request| app2[App 2]
end
app1 -->|Response| RP1
app2 -->|Response| RP1
VIP -->|Response| User
Setting up Nginx Reverse Proxy
- Login as root and ensure system is up to date before starting the setup.
- Since the instances will serve as only a reverse proxy, full version of Nginx is not required.
Setting up Keepalived
- Install keepalived on both instances.
-
Configure keepalived on proxy1 by creating
/etc/keepalived/keepalived.conf
. This configuration checks Nginx status via eth0 (management interface) and assigns VIP to eth1 (DMZ interface). Unicast configuration is used here since eth0 and eth1 are on different subnets that cannot communicate directly./etc/keepalived/keepalived.confglobal_defs { enable_script_security script_user root } vrrp_script chk_nginx { script "/usr/bin/systemctl is-active --quiet nginx" interval 2 timeout 2 fall 2 rise 1 weight -20 } vrrp_instance VI_1 { state MASTER interface eth0 unicast_src_ip 10.12.20.61 unicast_peer { 10.12.20.62 } virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass P@ss-123 } virtual_ipaddress { 10.12.99.50/24 dev eth1 } track_script { chk_nginx } }
Tip
In case VIP is just a different IP on the same network interface, multicast can be used with following config.
Bashglobal_defs { enable_script_security script_user root } vrrp_script chk_nginx { script "/usr/bin/systemctl is-active --quiet nginx" interval 2 timeout 2 fall 2 rise 1 weight -20 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass P@ss-123 } virtual_ipaddress { 10.12.99.50/24 dev eth1 } track_script { chk_nginx } }
-
Configure keepalived on proxy2 by creating
/etc/keepalived/keepalived.conf
similar to above with the highlighted changes./etc/keepalived/keepalived.confglobal_defs { enable_script_security script_user root } vrrp_script chk_nginx { script "/usr/bin/systemctl is-active --quiet nginx" interval 2 timeout 2 fall 2 rise 1 weight -20 } vrrp_instance VI_1 { state BACKUP interface eth0 unicast_src_ip 10.12.20.62 unicast_peer { 10.12.20.61 } virtual_router_id 51 priority 90 advert_int 1 authentication { auth_type PASS auth_pass P@ss-123 } virtual_ipaddress { 10.12.99.50/24 dev eth1 } track_script { chk_nginx } }
- Enable services on both instances.
- Verify failover by stopping Nginx or restarting one instance — the VIP should automatically reassign to the other node.
Setting up Unison
- Install Unison on both instances.
unison-fsmonitor
is required to automatically watch for file changes. This is already compiled by the unison build script but for some reason Ubuntu doesn't include it. So that has to be manually installed on both instances.BashUNISON_VERSION=$(unison -version | awk '{print $3}') echo "Installed Unison version: " $UNISON_VERSION echo "Installing Unison FS Monitor." \ && apt install -y wget ocaml make \ && pushd /tmp \ && wget https://github.com/bcpierce00/unison/archive/v$UNISON_VERSION.tar.gz \ && tar -xzvf v$UNISON_VERSION.tar.gz \ && rm v$UNISON_VERSION.tar.gz \ && pushd unison-$UNISON_VERSION \ && make \ && cp -t /usr/local/bin ./src/unison ./src/unison-fsmonitor \ && popd \ && rm -rf unison-$UNISON_VERSION \ && cd ~ \ && apt autoremove -y --purge ocaml* make
- Setup SSH key based access by creating and copying over SSH keypairs between instances.
On proxy1 On proxy2 - Create folder for Unison configs on both instances.
- Create Unison Profile on proxy1 for Nginx
sites-available
andsites-enabled
directories: - Repeat step 4 on proxy2 replacing IP address on line 2 with IP address of proxy1.
- Create respective systemd services on both instances.
- Finally enable the created services on both instances.
Info
It's a good practice to create/edit proxy configs on the node that currently holds the VIP, i.e., the active node and let Unison sync it to the passive node.
Applying Nginx configuration
At this point you should have a HA deployment of Nginx where config can be applied by reloading Nginx on both instances.