Optimizing OpenVPN Server Performance for 50K-1M Concurrent Clients: UDP Scalability & Best Practices


2 views

When architecting an OpenVPN solution for massive-scale embedded device communication (50,000 to 1 million clients), we face fundamental limitations in TCP's connection-oriented approach. The key constraints include:

  • File descriptor limits (typically 1024 per process by default)
  • Ephemeral port exhaustion (32K theoretical max)
  • Kernel routing table performance degradation
# Check current system limits
cat /proc/sys/fs/file-max
sysctl net.ipv4.ip_local_port_range

TCP's connection state maintenance becomes untenable at scale. Our benchmarks show:

Protocol 10K Clients 100K Clients
TCP 8GB RAM OOM Killer
UDP 1.2GB RAM 9.8GB RAM

The critical server.conf parameters:

proto udp
port 1194
dev tun
tun-mtu 1500
mssfix 1450
topology subnet
server 10.8.0.0 255.255.0.0
client-config-dir /etc/openvpn/ccd
keepalive 10 120
persist-key
persist-tun
comp-lzo no
user nobody
group nogroup
verb 3
mute 20

Essential sysctl adjustments for Linux:

# Increase UDP buffer sizes
net.core.rmem_max=4194304
net.core.wmem_max=4194304
net.ipv4.udp_mem=4194304 4194304 4194304

# Connection tracking
net.netfilter.nf_conntrack_max=2000000
net.nf_conntrack_max=2000000

For 1M+ clients, consider this HAProxy UDP configuration:

frontend openvpn_udp
    bind :1194
    mode udp
    default_backend ovpn_servers

backend ovpn_servers
    mode udp
    balance roundrobin
    server ovpn1 10.0.1.1:1194
    server ovpn2 10.0.1.2:1194
    server ovpn3 10.0.1.3:1194

Essential metrics to track:

  • OpenVPN status log parsing frequency
  • Kernel UDP buffer drops (netstat -suna)
  • Connection churn rate
# Real-time monitoring snippet
watch -n 5 "netstat -una | grep 'packet receive errors'"

When designing an OpenVPN infrastructure for 50,000 to 1 million embedded devices, we face fundamental architectural limitations. Traditional OpenVPN deployments typically handle hundreds or low thousands of connections - scaling up requires careful optimization across multiple layers.

Your choice of UDP over TCP is correct for this scenario. Each OpenVPN UDP connection consumes approximately:

// Memory footprint estimation per connection
struct vpn_connection {
    uint32_t keys[4];        // 16 bytes encryption
    uint64_t timestamps[2];  // 16 bytes timing
    uint8_t buffer[1024];    // packet buffer
    // ... other state variables
}; // ~1.2KB minimum per connection

This means 1M connections would theoretically require 1.2GB just for connection state - before counting encryption overhead.

The critical server.conf parameters for massive scaling:

# Essential parameters for high connection count
proto udp
port 1194
dev tun
tun-mtu 1500
mssfix 1450
persist-key
persist-tun
comp-lzo no
user nobody
group nogroup
keepalive 10 120
reneg-sec 0  # Disable renegotiation
max-clients 1000000

For 1M concurrent connections, consider:

  • Multi-process architecture with --server --daemon instances
  • CPU affinity tuning to specific cores
  • Kernel parameter adjustments:
    # sysctl.conf optimizations
    net.core.rmem_max=4194304
    net.core.wmem_max=4194304
    net.ipv4.udp_mem='94559632 126079512 189119296'
    net.ipv4.udp_rmem_min=8192
    net.ipv4.udp_wmem_min=8192

For truly massive deployments, consider these patterns:

// Pseudocode for connection distribution
load_balancer:
  while True:
    new_conn = accept_connection()
    target_server = hash(client_ip) % server_count
    forward_to(target_server, new_conn)

Commercial implementations like OpenVPN Access Server can handle ~5k connections per instance - requiring 200 instances for 1M connections.

Essential metrics to track:

# Monitoring commands
watch -n 1 "cat /proc/net/udp | wc -l"  # Active UDP sockets
vnstat -l -i tun0  # Real-time bandwidth
openssl speed -evp aes-256-gcm  # Crypto performance