Nginx as Application Load Balancer For OPC

Prev Next

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 nginx

Reload (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 wget

These 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.gz

Step 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/config

If 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 install

Important: --pid-path=/run/nginx.pid must 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 vts

You 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.conf

Paste 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 core

  • pid /run/nginx.pid — where Nginx writes its process ID file, must match systemd

  • vhost_traffic_status_zone — activates the VTS stats module

  • upstream 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 retries

  • server listen 80 — the main load balancer, receives all traffic and forwards to the upstream pool

  • server 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.conf

Expected output:

nginx: the configuration file /etc/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/conf/nginx.conf test is successful

Do 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 --force

This 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=60

Save and exit, then apply:


sudo systemctl daemon-reload
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl status nginx

Expected 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 cloudflared

You 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.