This guide explains how to configure High Availability (HA) for On-Prem Connector (OPC) using NGINX as a load balancer and reverse proxy. In this setup, NGINX distributes traffic between multiple OPC servers, helping ensure continued availability if one server becomes unavailable.
It also covers how to securely expose the setup using Cloudflare Tunnel, monitor backend server health, and view real-time traffic statistics through the NGINX dashboard.
Note: This document is intended as a general setup guide and covers only the specific configuration steps. Steps may vary depending on software versions, environment settings, or future updates. Scalefusion does not provide technical support for third-party software or infrastructure configurations referenced in this document.
Any tools or software mentioned are shared for guidance purposes only, and customers should choose the approach best suited to their environment.
1. Overview
What is a Load Balancer?
When users access an application, all requests hit a single entry point. Without a load balancer, if that one server goes down, the entire application becomes unavailable. A load balancer sits in front of multiple application servers and distributes incoming traffic across them — so if one server goes down, traffic automatically flows to the remaining healthy servers without any interruption to users.
Why Nginx as a Load Balancer?
Nginx is a lightweight, high-performance web server that also functions as a reverse proxy and load balancer. It is open-source, battle-tested at scale, and consumes very little memory. For this setup, Nginx is compiled with the VTS (Virtual Host Traffic Status) module which adds a real-time web dashboard showing traffic, health, and response statistics for each backend server — similar to HAProxy's stats page.
How Traffic Flows in This Setup
User Request
│
▼
Cloudflare (opc-ha-ngnix.xxxx.com)
│ Encrypted tunnel — no open inbound ports needed
▼
Nginx Load Balancer (192.168.14.74 :80)
│
├──► OPC Server 1 (192.168.14.157:28767)
│
└──► OPC Server 2 (192.168.14.217:28767)
Admin Browser ──► Nginx Stats Dashboard (192.168.14.74:8080/status)Cloudflare receives the public request and tunnels it securely to Nginx on your private network. Nginx decides which OPC server handles the request based on the configured algorithm. The stats page runs on a separate internal-only port so only admins on the local network can access it.
2. Infrastructure Details
Role | Hostname | IP Address | Port |
|---|---|---|---|
Load Balancer | ha-nginx | 192.168.14.74 | 80 (app), 8080 (stats) |
OPC App Server 1 | opc-1 | 192.168.14.157 | 28767 |
OPC App Server 2 | opc-2 | 192.168.14.217 | 28767 |
Public URL | opc-ha-xxx.xxxx.com | via Cloudflare | 80/443 |
3. Load Balancing Algorithms
Nginx supports multiple ways to distribute traffic. You configure this inside the upstream block in nginx.conf. Here is what each one does and when to use it.
Round Robin (Default)
Requests go to each server one by one in rotation. Server 1 gets request 1, Server 2 gets request 2, Server 1 gets request 3, and so on. No keyword needed — this is the default when nothing is specified.
upstream opc_backend {
server 192.168.14.157:28767;
server 192.168.14.217:28767;
}Best for: servers with identical hardware where requests take roughly equal time to process.
Least Connections
Each new request goes to whichever server currently has the fewest active connections. This is smarter than round robin when some requests take longer than others — it prevents one server from getting overloaded while the other sits idle.
upstream opc_backend {
least_conn;
server 192.168.14.157:28767;
server 192.168.14.217:28767;
}Best for: applications like OPC where request processing time varies. This is what we use.
Weighted
You assign a weight to each server. A server with weight 3 receives 3 requests for every 1 request sent to the server with weight 1.
upstream opc_backend {
server 192.168.14.157:28767 weight=3;
server 192.168.14.217:28767 weight=1;
}Best for: environments where one server has more CPU/RAM than the other.
IP Hash
The same client IP always routes to the same server. Every request from a specific user always lands on the same backend.
upstream opc_backend {
ip_hash;
server 192.168.14.157:28767;
server 192.168.14.217:28767;
}Best for: applications that store session data locally on the server and cannot share it between servers.
To switch algorithm on a running system:
sudo vi /etc/nginx/conf/nginx.conf
# Edit the upstream block, then:
nginx -t -c /etc/nginx/conf/nginx.conf
sudo systemctl reload nginxReload (not restart) applies config changes without dropping any active connections.
4. Installation and Setup
Step 1 — Install Build Dependencies
SSH into the load balancer server and run:
sudo apt-get update && sudo apt-get upgrade -y
sudo apt install -y git build-essential libpcre3-dev zlib1g-dev libssl-dev libgeoip-dev wgetThese are compiler tools and libraries Nginx needs to build from source. We build from source because the VTS stats module is not included in the standard apt package.
Step 2 — Download Nginx Source Code
cd ~
wget http://nginx.org/download/nginx-1.24.0.tar.gz
tar -xzf nginx-1.24.0.tar.gzStep 3 — Download the VTS Stats Module
git clone https://github.com/vozlt/nginx-module-vts.git /tmp/nginx-module-vts
# Confirm it downloaded correctly — you must see a file named 'config'
ls /tmp/nginx-module-vts/configIf you see No such file or directory, the clone failed. Check your internet connection and re-run the git clone command. Do not proceed to Step 4 until this file is confirmed present.
Step 4 — Compile Nginx with VTS Module
cd ~/nginx-1.24.0
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/sbin/nginx \
--conf-path=/etc/nginx/conf/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/run/nginx.pid \
--with-http_ssl_module \
--with-http_v2_module \
--with-http_gzip_static_module \
--add-module=/tmp/nginx-module-vts
make -j$(nproc)
sudo make installImportant:
--pid-path=/run/nginx.pidmust match what systemd expects. If these differ, Nginx will time out on startup. This is the most common setup mistake.
Verify VTS is compiled in:
/usr/sbin/nginx -V 2>&1 | grep vtsYou must see --add-module=/tmp/nginx-module-vts in the output before continuing.
Step 5 — Create the Nginx Configuration File
sudo mkdir -p /etc/nginx/conf
sudo vi /etc/nginx/conf/nginx.confPaste the following complete configuration:
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
vhost_traffic_status_zone;
upstream opc_backend {
least_conn;
server 192.168.14.157:28767 max_fails=3 fail_timeout=30s;
server 192.168.14.217:28767 max_fails=3 fail_timeout=30s;
}
server {
listen 80;
server_name _;
location / {
proxy_pass http://opc_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
server {
listen 8080;
allow 127.0.0.1;
allow 192.168.14.0/24;
allow all;
location /status {
vhost_traffic_status_display;
vhost_traffic_status_display_format html;
}
location /status/format/json {
vhost_traffic_status_display;
vhost_traffic_status_display_format json;
}
}
}What each block does:
worker_processes auto— Nginx automatically uses one worker per CPU corepid /run/nginx.pid— where Nginx writes its process ID file, must match systemdvhost_traffic_status_zone— activates the VTS stats moduleupstream opc_backend— defines both OPC servers with passive health checking. If a server fails 3 times within 30 seconds, Nginx stops sending it traffic for 30 seconds, then retriesserver listen 80— the main load balancer, receives all traffic and forwards to the upstream poolserver listen 8080— the stats dashboard, accessible only from localhost or the 192.168.14.x network
Test the configuration before proceeding:
/usr/sbin/nginx -t -c /etc/nginx/conf/nginx.confExpected output:
nginx: the configuration file /etc/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/conf/nginx.conf test is successfulDo not proceed if you see any errors. Fix the config and re-test.
Step 6 — Fix the systemd Service File
The default nginx systemd service does not know about your custom config path or PID location. You must override it or nginx will time out on startup.
sudo systemctl edit nginx.service --forceThis opens an editor. Paste exactly:
[Service]
PIDFile=/run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t -q -c /etc/nginx/conf/nginx.conf -g 'daemon on; master_process on;'
ExecStart=/usr/sbin/nginx -c /etc/nginx/conf/nginx.conf -g 'daemon on; master_process on;'
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=60Save and exit, then apply:
sudo systemctl daemon-reload
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginxExpected output shows Active: active (running). If it fails, go to Section 6 — Troubleshooting.
Step 7 — Install Cloudflare Tunnel
Cloudflare Tunnel creates a secure outbound connection from your server to Cloudflare's network. No inbound firewall ports need to be opened. The service install command automatically creates and starts the systemd service — no config file needs to be created manually.
# Add Cloudflare GPG key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-public-v2.gpg | sudo tee /usr/share/keyrings/cloudflare-public-v2.gpg >/dev/null
# Add Cloudflare apt repository
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-public-v2.gpg] https://pkg.cloudflare.com/cloudflared any main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
# Install cloudflared
sudo apt-get update && sudo apt-get install cloudflared -y
# Install as background service — replace with your actual token
sudo cloudflared service install <your-token>Verify it is running:
sudo systemctl status cloudflaredYou should see Active: active (running) and log lines showing Registered tunnel connection for multiple connection indexes. This means Cloudflare has established redundant connections.
5. Verification
Health Check URL
The OPC application exposes a heartbeat endpoint. Use this to confirm traffic is flowing end-to-end through Cloudflare → Nginx → OPC server.
Open in browser:
http://opc-ha-ngnix.xxxxx.com/opc/heart-beat/Expected response:

A response of OK confirms the full path is working — Cloudflare tunnel is up, Nginx is routing correctly, and the OPC backend server is healthy.