--- title: "🌐 Multi-Server Web Cluster & Load Balancing" description: "Comprehensive architecture and deployment guide for scaling Ring2All Web GUI, Client Portal, and API across multiple load-balanced servers using Cloudflare." --- > Enterprise guide for deploying multiple Ring2All Web and API nodes behind Cloudflare and Nginx for high availability, zero-downtime maintenance, and horizontal scaling. --- ## Table of Contents 1. [Architectural Overview](#1-architectural-overview) 2. [Why Ring2All is 100% Stateless](#2-why-ring2all-is-100-stateless) 3. [Cloudflare Load Balancing Options](#3-cloudflare-load-balancing-options) 4. [Step-by-Step Multi-Node Deployment](#4-step-by-step-multi-node-deployment) 5. [Nginx Configuration on Web Nodes](#5-nginx-configuration-on-web-nodes) 6. [Database & Redis Clustering Requirements](#6-database--redis-clustering-requirements) 7. [Operational Verification & Failover Testing](#7-operational-verification--failover-testing) 8. [Summary & Key Advantages](#8-summary--key-advantages) --- ## 1. Architectural Overview In high-density service provider environments, the web management layer (Ring2All PBX Admin, User Portal, Switchboard Console, and BSS Client Portal) can be scaled horizontally across multiple independent Linux instances without requiring distinct domain names. A single canonical domain (e.g., `*.ring2all.com` or `app.ring2all.com`) serves all web traffic, distributed intelligently across backend nodes by **Cloudflare Edge Load Balancing**: ```mermaid flowchart TD subgraph Clients["Global Ingress (Internet)"] Browser1["Client Browser A
mycompany.ring2all.com"] Browser2["Client Browser B
acme.ring2all.com"] MobileApp["User Portal Mobile PWA"] end subgraph Edge["Cloudflare Anycast Global Edge Network"] CF_WAF["Cloudflare WAF & DDoS Shield"] CF_SSL["Universal SSL Termination (*.ring2all.com)"] CF_LB["Cloudflare Load Balancer / Round-Robin Pool"] end subgraph WebCluster["Stateless Web & API Tier (Port 443 / 80)"] Node1["Web Node 01 (198.51.100.20)
Nginx + softswitch-web + softswitch-api"] Node2["Web Node 02 (198.51.100.21)
Nginx + softswitch-web + softswitch-api"] NodeN["Web Node N (198.51.100.2N)
Horizontal Scale on Demand"] end subgraph DataTier["Centralized State & Storage Layer"] PG[("PostgreSQL 17 HA Cluster
ss_admin | ss_telephony | ss_billing")] Redis[("Redis Cluster / PubSub
Session Cache & WebSocket Broker")] end subgraph TelephonyTier["Perimeter VoIP (Bypasses Web Proxy)"] SBC["Ring2All SBC (Kamailio 6.1)
sbc.ring2all.com (Port 5060/5061)"] end Browser1 --> CF_WAF Browser2 --> CF_WAF MobileApp --> CF_WAF CF_WAF --> CF_SSL CF_SSL --> CF_LB CF_LB -- "Round-Robin / Health Check" --> Node1 CF_LB -- "Round-Robin / Health Check" --> Node2 CF_LB -- "Round-Robin / Health Check" --> NodeN Node1 --> PG Node2 --> PG NodeN --> PG Node1 --> Redis Node2 --> Redis NodeN --> Redis ``` --- ## 2. Why Ring2All is 100% Stateless Unlike legacy PBX platforms that store web sessions in server memory files (`/tmp/sess_*`), Ring2All's application tier is designed with **zero in-memory session lock-in**: 1. **Cryptographic JWT Authentication (Stateless)**: * When an administrator or tenant user logs in, the API issues a signed JSON Web Token (JWT). * **Any Web Node** can decode and cryptographically verify the token using the shared cluster secret key (`JWT_SECRET`). * Request #1 can hit **Web Node 01** and Request #2 can hit **Web Node 02** without requiring sticky sessions or session re-authentication. 2. **Single Page Application (SPA) Decoupling**: * The frontend interfaces (`softswitch-web`, `softswitch-portal`, `softswitch-switchboard`, `softswitch-bss-client`) compile into static HTML5, CSS3, and JavaScript bundles. * Static assets are heavily cached across Cloudflare's 300+ Edge data centers. Over 80% of asset requests never reach your origin servers. 3. **Centralized Data & Cache Tier**: * Real-time events, WebSockets, and database transactions are offloaded to **PostgreSQL 17** and **Redis**, leaving the Node.js Fastify API threads free to execute sub-millisecond JSON operations. --- ## 3. Cloudflare Load Balancing Options You can implement multi-server web distribution using either of the following two Cloudflare configurations: ### Option A: Cloudflare Anycast Round-Robin (100% Free on all Cloudflare Plans) By creating multiple `A` records with the same hostname pointing to distinct server IPs, Cloudflare distributes incoming HTTPS connections evenly across your origins: | Record Type | Host / Name | Origin Server IP | Cloudflare Proxy Status | | :--- | :--- | :--- | :--- | | **A** | `*` *(Wildcard)* | `198.51.100.20` *(Web Node 01)* | **☁️ Proxied (Orange Cloud)** | | **A** | `*` *(Wildcard)* | `198.51.100.21` *(Web Node 02)* | **☁️ Proxied (Orange Cloud)** | | **A** | `*` *(Wildcard)* | `198.51.100.22` *(Web Node 03)* | **☁️ Proxied (Orange Cloud)** | * **How it works:** Cloudflare Anycast automatically balances client HTTP sessions among the configured origin IPs. * **Cost:** Included at zero additional charge in standard Cloudflare accounts. --- ### Option B: Cloudflare Load Balancer (With Active Health Checks & Auto-Failover) For mission-critical telecom carriers, the **Cloudflare Load Balancing** add-on provides automated health monitoring and sub-3-second failover: 1. **Origin Pool Configuration**: * Create pool: `ring2all-web-cluster`. * Add Origins: `node-01` (`198.51.100.20`), `node-02` (`198.51.100.21`). * Weight: `1:1` (or customized by server capacity). 2. **Health Monitor**: * Path: `/health` (or `/api/health`). * Expected Response Code: `200 OK`. * Interval: Every `15 seconds`. * Timeout: `3 seconds`. 3. **Autonomous Failover**: * If `node-01` fails or undergoes routine OS maintenance, Cloudflare automatically stops routing requests to it within 3 seconds. * **Zero User Interruption:** 100% of traffic immediately routes to `node-02` without connection dropouts or 502 Bad Gateway errors. --- ## 4. Step-by-Step Multi-Node Deployment ### Step 1: Provision Web Server Instances Deploy 2 or more Linux servers (Debian 13 or Ubuntu 24.04 LTS) with standard system specs: * **vCPU:** 4 cores. * **RAM:** 8 GB. * **Disk:** 50 GB NVMe SSD. ### Step 2: Install Ring2All Web & API Packages On **each** web node, install the system packages: ```bash # Update repository and install application packages sudo apt update sudo apt install -y softswitch-web softswitch-api softswitch-portal softswitch-switchboard nginx ``` ### Step 3: Synchronize Cluster Secrets in `.env` Ensure that `/opt/softswitch-api/.env` on **all web nodes** contains identical cryptographic and database credentials: ```ini # /opt/softswitch-api/.env (Must match across ALL Web Nodes) NODE_ENV=production PORT=3000 HOST=127.0.0.1 # Shared Cryptographic JWT Key (CRITICAL: Must be identical) JWT_SECRET="r2a_prod_super_secret_cluster_token_98374291834" # Centralized PostgreSQL 17 Cluster Connection DATABASE_URL="postgres://ring2all_app:SecureClusterPass@192.168.10.31:5432/ss_telephony" ADMIN_DATABASE_URL="postgres://ring2all_app:SecureClusterPass@192.168.10.31:5432/ss_admin" BILLING_DATABASE_URL="postgres://ring2all_app:SecureClusterPass@192.168.10.31:5432/ss_billing" # Shared Redis Cluster REDIS_HOST="192.168.10.31" REDIS_PORT=6379 REDIS_PASSWORD="ClusterRedisAuthPass2026" ``` ### Step 4: Enable and Start Systemd Services On each web node: ```bash sudo systemctl daemon-reload sudo systemctl enable --now softswitch-api sudo systemctl restart nginx ``` --- ## 5. Nginx Configuration on Web Nodes Every web node runs a lightweight local Nginx reverse proxy that handles incoming traffic forwarded from Cloudflare: ```nginx # /etc/nginx/sites-available/ring2all-cluster-node.conf server { listen 80; listen [::]:80; server_name *.ring2all.com ring2all.com; # Trust Cloudflare proxy IP headers set_real_ip_from 173.245.48.0/20; set_real_ip_from 103.21.244.0/22; set_real_ip_from 103.22.200.0/22; set_real_ip_from 103.31.4.0/22; set_real_ip_from 141.101.64.0/18; set_real_ip_from 108.162.192.0/18; set_real_ip_from 190.93.240.0/20; set_real_ip_from 188.114.96.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17; set_real_ip_from 162.158.0.0/15; set_real_ip_from 104.16.0.0/13; set_real_ip_from 104.24.0.0/14; set_real_ip_from 172.64.0.0/13; set_real_ip_from 131.0.72.0/22; real_ip_header CF-Connecting-IP; # Static Web Frontend root /opt/softswitch-web/dist; index index.html; # Gzip Compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml application/xml; # Health Check Endpoint for Cloudflare Load Balancer location = /health { access_log off; return 200 "healthy\n"; add_header Content-Type text/plain; } # API Proxy location /api/ { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto; proxy_connect_timeout 3s; proxy_read_timeout 60s; } # SPA Routing Fallback location / { try_files $uri $uri/ /index.html; } } ``` --- ## 6. Database & Redis Clustering Requirements To sustain thousands of concurrent web requests across multiple nodes without connection pool starvation: 1. **PostgreSQL Connection Pool Optimization (`pgbouncer`)**: * Install `pgbouncer` on the PostgreSQL database cluster to manage thousands of lightweight connection handles from all web nodes. * Configure transaction pooling mode (`pool_mode = transaction`) in `pgbouncer.ini`. 2. **Redis Centralized Cache**: * Configure Redis persistence (`appendonly yes`) or Redis Sentinel for high availability. * Real-time WebSocket notifications (active call dashboards, BLF state changes) broadcast over Redis Pub/Sub so that a user connected to **Node 01** instantly receives state updates generated by **Node 02**. --- ## 7. Operational Verification & Failover Testing ### 1. Verify Node Health Locally On each individual web node, execute: ```bash curl -I http://127.0.0.1/health # Expected: HTTP/1.1 200 OK curl -I http://127.0.0.1/api/health # Expected: HTTP/1.1 200 OK ``` ### 2. Verify Cloudflare Edge Load Balancing From an external computer, inspect the HTTP headers: ```bash curl -svo /dev/null https://app.ring2all.com/health # Expected: # < HTTP/2 200 # < cf-ray: ... # < server: cloudflare ``` ### 3. Simulate Node Failure (Zero-Downtime Test) 1. Stop the web service on **Node 01**: ```bash sudo systemctl stop nginx ``` 2. Immediately browse to `https://app.ring2all.com` or send 100 consecutive HTTP requests via `ab` / `wrk`. 3. Cloudflare automatically shunts 100% of traffic to **Node 02**. The user session remains completely active with zero errors. 4. Restart **Node 01**: ```bash sudo systemctl start nginx ``` 5. Cloudflare automatically resumes traffic distribution to Node 01 within 15 seconds. --- ## 8. Summary & Key Advantages | Feature / Benefit | Single Server | Multi-Server with Cloudflare | | :--- | :--- | :--- | | **Domain Management** | 1 Domain | **Identical Single Domain** (`*.ring2all.com`) | | **High Availability** | None (Single Point of Failure) | **Active-Active Cluster (N+1)** | | **DDoS & Web Shield** | Local iptables/nftables only | **Enterprise Cloudflare Global WAF** | | **Maintenance Downtime** | Requires scheduled outages | **Zero-Downtime Rolling Restarts** | | **VoIP Telephony Impact** | Co-located on same box | **VoIP completely isolated on Kamailio SBC** | | **Horizontal Scalability** | Vertical upgrade only | **Add new web nodes in < 5 minutes** |