VPN Exit Controller - Technical Architecture¶
Overview¶
The VPN Exit Controller is a sophisticated system that manages dynamic country-based VPN exit nodes using Tailscale mesh networking, Docker containers, and intelligent load balancing. The system provides HTTP/HTTPS proxy services through country-specific subdomains, enabling users to route traffic through different geographical locations.
System Architecture Diagram¶
Internet → Cloudflare → Proxmox LXC → Traefik → HAProxy → VPN Exit Nodes
↓ ↓ ↓ ↓ ↓ ↓
Users DNS/CDN Host System SSL Term Routing Tailscale+VPN
(10.10.10.20) (Port 443) (Port 8080) (100.x.x.x)
Network Flow Detail¶
1. User Request: https://proxy-us.rbnk.uk
│
2. Cloudflare DNS Resolution: 135.181.60.45
│
3. Proxmox Host: 135.181.60.45:443
│
4. Traefik (LXC 201): SSL termination + routing
│
5. HAProxy: Country-based backend selection
│
6. VPN Exit Node: Docker container with NordVPN + Tailscale
│
7. Final destination via NordVPN servers
Core Components¶
1. FastAPI Application (/opt/vpn-exit-controller/api/)¶
The central orchestration service built with FastAPI that manages the entire VPN exit node ecosystem.
Key Features: - RESTful API for node management - Web-based dashboard with real-time status - Authentication using HTTP Basic Auth - Background services for monitoring and metrics
Structure:
api/
├── main.py # FastAPI application entry point
├── routes/ # API route handlers
│ ├── nodes.py # Node management endpoints
│ ├── proxy.py # Proxy configuration endpoints
│ ├── load_balancer.py # Load balancing control
│ ├── metrics.py # Metrics and monitoring
│ └── failover.py # Failover management
└── services/ # Business logic services
├── docker_manager.py # Docker container orchestration
├── proxy_manager.py # HAProxy configuration management
├── load_balancer.py # Intelligent node selection
├── redis_manager.py # State and metrics storage
└── metrics_collector.py # Real-time metrics collection
2. Docker-based VPN Exit Nodes¶
Each VPN node runs in a dedicated Docker container combining NordVPN and Tailscale.
Container Architecture:
FROM ubuntu:22.04
RUN apt-get install openvpn tailscale iptables
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
Node Lifecycle: 1. Container starts with country-specific environment variables 2. OpenVPN connects to optimal NordVPN server for the country 3. Tailscale connects to mesh network as exit node 4. IP forwarding rules enable traffic routing 5. Health monitoring ensures connectivity
Resource Limits: - Memory: 512MB per container - CPU: 50% of one core - Swap: 1GB total (memory + swap)
3. Traefik SSL Termination and Reverse Proxy¶
Traefik handles SSL certificate management and initial request routing.
Configuration: - SSL certificates via Let's Encrypt + Cloudflare DNS challenge - Automatic certificate renewal - Security headers middleware - Docker provider for service discovery
Key Features: - Wildcard SSL certificate for *.rbnk.uk - Automatic service discovery through Docker labels - Prometheus metrics export - Dashboard at traefik-vpn.rbnk.uk
4. HAProxy Country-based Routing System¶
HAProxy provides intelligent country-based request routing and load balancing.
Routing Logic:
Request: https://proxy-us.rbnk.uk/path
↓
HAProxy ACL: hdr(host) -i proxy-us.rbnk.uk
↓
Backend Selection: proxy_us
↓
Server Selection: Load balancing among US nodes
Backend Configuration: - Round-robin load balancing per country - Health checks every 10 seconds - Automatic failover to backup servers - Dynamic configuration updates
Health Monitoring:
5. Redis Metrics and State Storage¶
Redis serves as the central data store for real-time metrics, connection tracking, and system state.
Data Structure:
node:{node_id} # Node metadata and configuration
metrics:{node_id}:current # Real-time node metrics
metrics:{node_id}:history # Historical metrics (1 hour window)
connections:{node_id} # Active connection counter
server_health:{server} # VPN server health and latency
Metrics Tracked: - CPU usage percentage - Memory usage in MB - Network I/O statistics - VPN connection status - Tailscale connectivity - Active proxy connections
VPN Node Architecture¶
Container Design¶
Each VPN exit node is a self-contained Docker container that provides secure routing through a specific country with integrated proxy services.
┌─────────────────────────────────────────────────────────────┐
│ VPN Exit Node Container │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌──────────────┐ ┌─────────────────────┐ │
│ │ OpenVPN │ │ Tailscale │ │ Proxy Services │ │
│ │ (NordVPN) │ │ (Exit Node) │ │ │ │
│ │ │ │ │ │ ┌─────────────────┐ │ │
│ │ Port: tun0 │ │ Port: ts0 │ │ │ Squid HTTP/S │ │ │
│ └─────────────┘ └──────────────┘ │ │ Port: 3128 │ │ │
│ │ │ │ └─────────────────┘ │ │
│ ┌─────────────────────────────────┐ │ ┌─────────────────┐ │ │
│ │ iptables Routing │ │ │ Dante SOCKS5 │ │ │
│ │ tun0 ←→ tailscale0 │ │ │ Port: 1080 │ │ │
│ └─────────────────────────────────┘ │ └─────────────────┘ │ │
│ │ ┌─────────────────┐ │ │
│ ┌─────────────────────────────────┐ │ │ Health Check │ │ │
│ │ DNS Configuration │ │ │ Port: 8080 │ │ │
│ │ NordVPN DNS: 103.86.96.100 │ │ └─────────────────┘ │ │
│ │ NordVPN DNS: 103.86.99.100 │ │ │ │
│ │ Fallback: 8.8.8.8, 1.1.1.1 │ └─────────────────────┘ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
NordVPN Integration¶
Server Selection: - Country-specific server pools - Automatic optimal server selection based on latency - Support for both TCP and UDP configurations - Service credentials authentication
Configuration Management:
configs/vpn/
├── us.ovpn # Default US configuration
├── us/ # Specific US servers
│ ├── us5063.nordvpn.com.tcp.ovpn
│ └── us5064.nordvpn.com.udp.ovpn
└── auth.txt # NordVPN service credentials
Tailscale Mesh Networking¶
Exit Node Configuration: - Advertises as exit node on Tailscale network with --advertise-exit-node - Uses --accept-dns=false to prevent DNS conflicts (fixes HTTPS errors in incognito mode) - Ephemeral auth key configuration for automatic device cleanup - Unique hostname: exit-{country}-{instance} - Userspace networking for container compatibility - Automatic IP assignment from 100.x.x.x range
Network Architecture:
Internet ←→ Tailscale Client ←→ Tailscale Mesh ←→ Exit Node ←→ NordVPN ←→ Destination
(100.x.x.x) (tun0) (VPN Server)
DNS Resolution Configuration: To resolve HTTPS errors in incognito mode and improve reliability:
- Tailscale DNS Disabled:
--accept-dns=falseprevents Tailscale from overriding DNS - NordVPN DNS Primary: Uses NordVPN's DNS servers (103.86.96.100, 103.86.99.100)
- Google DNS Fallback: Falls back to 8.8.8.8 and 1.1.1.1 if NordVPN DNS fails
- Container DNS Override: Manual
/etc/resolv.confconfiguration in containers
This configuration eliminates the "doesn't support secure connection" errors that occurred when using Tailscale's DNS resolution through the VPN tunnel.
Health Monitoring and Auto-Recovery¶
Health Checks: 1. Container status monitoring 2. VPN tunnel connectivity (ip route | grep tun0) 3. Tailscale connection status 4. Exit node advertisement verification
Auto-Recovery Process: 1. Health check failure detected 2. Container restart attempted (max 3 times) 3. If restart fails, node marked unhealthy 4. Load balancer redirects traffic to healthy nodes 5. Failed node removed after timeout
Proxy Routing System¶
Multi-Protocol Proxy Chain¶
The system provides a comprehensive proxy chain supporting HTTP/HTTPS and SOCKS5 protocols:
Client → HAProxy → Tailscale Mesh → VPN Container → Internet
↓ ↓ ↓ ↓ ↓
Request Routing Mesh Network Proxy Services Destination
Layer (100.x.x.x) (Squid/Dante) (via NordVPN)
Proxy Chain Components: 1. HAProxy: L7 load balancer with ACL-based country routing 2. Tailscale Mesh: Secure encrypted tunnel network (100.64.0.0/10) 3. VPN Container: Integrated Squid (HTTP/HTTPS) and Dante (SOCKS5) proxies 4. NordVPN: Exit point to internet with country-specific IP addresses
Country-based Subdomain Routing¶
The system uses DNS subdomains to route traffic through specific countries with multiple proxy protocols:
proxy-us.rbnk.uk → United States exit nodes
proxy-uk.rbnk.uk → United Kingdom exit nodes
proxy-de.rbnk.uk → Germany exit nodes
proxy-jp.rbnk.uk → Japan exit nodes
Available Proxy Protocols: - HTTP Proxy: http://<tailscale-ip>:3128 (Squid) - SOCKS5 Proxy: socks5://<tailscale-ip>:1080 (Dante) - Health Check: http://<tailscale-ip>:8080/health
HAProxy ACL-Based Routing (Updated)¶
HAProxy now uses ACL-based routing instead of regex for better performance and reliability:
# Country-specific ACLs using hostname matching
acl is_us_proxy hdr(host) -i proxy-us.rbnk.uk
acl is_uk_proxy hdr(host) -i proxy-uk.rbnk.uk
acl is_de_proxy hdr(host) -i proxy-de.rbnk.uk
# Route to appropriate backend
use_backend proxy_us if is_us_proxy
use_backend proxy_uk if is_uk_proxy
use_backend proxy_de if is_de_proxy
Backend Server Selection with Health Checks¶
For each country backend, HAProxy selects from available healthy nodes using HTTP health checks:
backend proxy_us
mode http
balance roundrobin
option httpchk GET /health HTTP/1.1\r\nHost:\ localhost
http-check expect status 200
# VPN container nodes with health checks
server us-node-1 100.86.140.98:3128 check inter 10s
server us-node-2 100.86.140.99:3128 check inter 10s
server us-backup 127.0.0.1:3128 backup
Health Check Updates for HAProxy 2.8: - Updated health check syntax for compatibility - HTTP health checks on port 8080 (/health endpoint) - 10-second check intervals with automatic failover
Load Balancing System¶
5 Load Balancing Strategies¶
- Round Robin: Sequential distribution across nodes
- Least Connections: Route to node with fewest active connections
- Weighted Latency: Prefer nodes with lower VPN server latency
- Random: Random node selection
- Health Score: Comprehensive scoring based on multiple factors
Health Score Calculation¶
The health score algorithm considers multiple factors:
def calculate_health_score(node):
score = 100.0 # Perfect score baseline
# Server latency (40% weight)
latency_score = max(50, 100 - (latency - 50) * 0.5)
score = score * 0.6 + latency_score * 0.4
# Connection count (30% weight)
connection_penalty = min(20, connection_count * 2)
connection_score = max(60, 100 - connection_penalty)
score = score * 0.7 + connection_score * 0.3
# CPU usage (20% weight)
cpu_score = max(60, 100 - cpu_percent)
score = score * 0.8 + cpu_score * 0.2
# Memory usage (10% weight)
memory_penalty = max(0, (memory_mb - 300) / 10)
memory_score = max(70, 100 - memory_penalty)
score = score * 0.9 + memory_score * 0.1
return score
Automatic Scaling Logic¶
Scale Up Conditions: - Average connections per node > 50 - Current node count < 3 for the country - At least one healthy server available
Scale Down Conditions: - Average connections per node < 10 - Current node count > 1 for the country - Target node has 0 active connections
Infrastructure Details¶
Proxmox LXC Container Setup¶
Container Configuration: - Container ID: 201 - OS: Ubuntu 22.04 - Internal IP: 10.10.10.20 - Public IP: 135.181.60.45 - Memory: 8GB - Storage: 100GB
Special Permissions Required:
Network Configuration¶
Network Stack:
┌─────────────────────────────────────┐
│ Internet (135.181.60.45) │
├─────────────────────────────────────┤
│ Proxmox Host │
│ ┌─────────────────────────────┐ │
│ │ LXC Container 201 │ │
│ │ IP: 10.10.10.20 │ │
│ │ ┌───────────────────────┐ │ │
│ │ │ Docker Network │ │ │
│ │ │ traefik_proxy │ │ │
│ │ │ vpn_network │ │ │
│ │ └───────────────────────┘ │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
Port Mapping: - 80 → Traefik HTTP - 443 → Traefik HTTPS - 8080 → FastAPI Application - 8081 → Traefik Dashboard - 8404 → HAProxy Stats
DNS Configuration with Cloudflare¶
DNS Records:
A rbnk.uk 135.181.60.45
A *.rbnk.uk 135.181.60.45
CNAME proxy-us.rbnk.uk rbnk.uk
CNAME proxy-uk.rbnk.uk rbnk.uk
CNAME proxy-de.rbnk.uk rbnk.uk
Cloudflare Settings: - Proxy enabled for DDoS protection - SSL/TLS: Full (strict) - Always Use HTTPS: On - HSTS enabled
Configuration Examples¶
Docker Compose for API Services¶
version: '3.8'
services:
api:
build: ./api
container_name: vpn-api
network_mode: host
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./configs:/configs
environment:
- TAILSCALE_AUTHKEY=${TAILSCALE_AUTHKEY}
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: vpn-redis
network_mode: host
volumes:
- redis-data:/data
restart: unless-stopped
Traefik Configuration¶
# traefik.yml
entryPoints:
web:
address: ":80"
websecure:
address: ":443"
certificatesResolvers:
cf:
acme:
email: "[email protected]"
storage: /letsencrypt/acme.json
dnsChallenge:
provider: cloudflare
Environment Variables¶
# Required environment variables
TAILSCALE_AUTHKEY=tskey-auth-xxxxx # Tailscale auth key
ADMIN_USER=admin # API admin username
ADMIN_PASS=Bl4ckMagic!2345erver # API admin password
SECRET_KEY=your-secret-key # FastAPI secret key
REDIS_URL=redis://localhost:6379 # Redis connection string
CF_DNS_API_TOKEN=cloudflare-token # Cloudflare API token
Monitoring and Observability¶
Metrics Collection¶
System Metrics: - Node count per country - Connection distribution - CPU and memory usage - Network throughput - VPN connection stability
Business Metrics: - Request success rate - Response time percentiles - Geographic usage distribution - Load balancing effectiveness
Health Monitoring¶
Health Check Endpoints: - /health - API service health - /api/nodes - Node status overview - /api/metrics - System metrics - HAProxy stats at :8404/stats - Traefik dashboard at :8081
Alerting and Failover¶
Automatic Failover Triggers: - Node health check failures - High CPU/memory usage - VPN connection loss - Tailscale connectivity issues
Recovery Actions: - Container restart (up to 3 attempts) - Node replacement with fresh container - Load balancer traffic redirection - Administrative notifications
Security Considerations¶
Network Isolation¶
- Each VPN node runs in isolated Docker container
- Network policies restrict inter-container communication
- VPN credentials stored securely in mounted volumes
Authentication and Authorization¶
- HTTP Basic Auth for API access
- Tailscale authentication for mesh network
- NordVPN service credentials for VPN access
SSL/TLS Configuration¶
- End-to-end encryption via Traefik
- Let's Encrypt certificates with automatic renewal
- Secure headers middleware
- HSTS enforcement
Deployment and Operations¶
Initial Setup¶
-
Proxmox LXC Creation:
-
Container Permissions:
-
Service Installation:
Maintenance Operations¶
Health Monitoring:
# Check service status
systemctl status vpn-controller
# View real-time logs
journalctl -u vpn-controller -f
# Check Docker containers
docker ps -a --filter label=vpn.exit-node=true
Configuration Updates:
# Update HAProxy configuration
curl -X POST http://localhost:8080/api/proxy/update-config
# Restart all nodes for a country
curl -X POST http://localhost:8080/api/nodes/us/restart-all
Backup and Recovery:
# Backup Redis data
docker exec vpn-redis redis-cli BGSAVE
# Backup configuration
tar -czf backup.tar.gz /opt/vpn-exit-controller/configs
This architecture provides a robust, scalable, and intelligent VPN exit node system that automatically manages geographic traffic routing while maintaining high availability and performance.