Skip to content

Configuration Guide

This guide covers all configuration options for VPN Exit Controller, including environment variables, service settings, and advanced tuning parameters.

Configuration Overview

VPN Exit Controller uses a hierarchical configuration system:

  1. Environment Variables (.env file)
  2. Service Configuration (systemd, Docker)
  3. Application Settings (API, load balancer, etc.)
  4. Runtime Configuration (via API)

Environment Variables

Essential Configuration

Create a .env file in the project root:

# Copy template
cp .env.example .env

# Edit configuration
nano .env

Core Settings

NordVPN Configuration

# Service credentials from NordVPN dashboard
NORDVPN_USER=your_service_username
NORDVPN_PASS=your_service_password

# Optional: Preferred protocol
NORDVPN_PROTOCOL=udp  # or tcp
NORDVPN_TECHNOLOGY=openvpn_udp  # or nordlynx

Getting NordVPN Credentials

  1. Log in to NordVPN Dashboard
  2. Navigate to Manual Configuration
  3. Generate service credentials
  4. Use these credentials (not your account login)

Tailscale Configuration

# Auth key for automatic node registration (use ephemeral keys for auto-cleanup)
TAILSCALE_AUTH_KEY=tskey-auth-xxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx

# Optional: Custom hostname prefix
TAILSCALE_HOSTNAME_PREFIX=vpn-exit

# Optional: Exit node advertisement
TAILSCALE_ADVERTISE_EXIT_NODE=true
TAILSCALE_ADVERTISE_ROUTES=10.0.0.0/8,192.168.0.0/16

# DNS Configuration (Important: prevents HTTPS errors in incognito mode)
TAILSCALE_ACCEPT_DNS=false  # Disables Tailscale DNS override

API Configuration

# API Authentication
API_USERNAME=admin
API_PASSWORD=strong_secure_password_here

# API Server Settings
API_HOST=0.0.0.0
API_PORT=8080
API_WORKERS=4
API_RELOAD=false  # Set to true for development

# CORS Settings
API_CORS_ORIGINS=["https://vpn-docs.rbnk.uk", "https://admin.rbnk.uk"]

Redis Configuration

# Redis Connection
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0
REDIS_PASSWORD=redis_password_if_set

# Redis Settings
REDIS_MAX_CONNECTIONS=50
REDIS_DECODE_RESPONSES=true
REDIS_SOCKET_TIMEOUT=5
REDIS_CONNECTION_TIMEOUT=10

Proxy Server Configuration

# Proxy service settings
PROXY_HTTP_PORT=3128           # Squid HTTP/HTTPS proxy port
PROXY_SOCKS_PORT=1080          # Dante SOCKS5 proxy port
PROXY_HEALTH_PORT=8080         # Health check endpoint port

# DNS Configuration for VPN containers
VPN_DNS_PRIMARY=103.86.96.100   # NordVPN DNS server 1
VPN_DNS_SECONDARY=103.86.99.100 # NordVPN DNS server 2
VPN_DNS_FALLBACK_1=8.8.8.8      # Google DNS fallback 1
VPN_DNS_FALLBACK_2=1.1.1.1      # Google DNS fallback 2

# Squid proxy settings
SQUID_ACCESS_LOG=none           # Disable access logging for privacy
SQUID_CACHE_ENABLED=false       # Disable caching for privacy
SQUID_MAX_CONNECTIONS=1000      # Maximum concurrent connections

# SOCKS5 proxy settings  
DANTE_MAX_CONNECTIONS=1000      # Maximum concurrent connections
DANTE_LOG_LEVEL=error           # Logging level (error, warning, info, debug)

DNS Resolution Fix

The VPN containers are configured with specific DNS servers to resolve the "doesn't support secure connection" errors that occurred in incognito mode:

  1. Primary: NordVPN DNS servers (103.86.96.100, 103.86.99.100)
  2. Fallback: Google DNS (8.8.8.8, 1.1.1.1) if NordVPN DNS fails
  3. Tailscale DNS Disabled: --accept-dns=false prevents conflicts

Advanced Settings

Load Balancing

# Default strategy: round_robin, least_connections, weighted_latency, random, health_score
DEFAULT_LOAD_BALANCING_STRATEGY=health_score

# Auto-scaling
AUTO_SCALING_ENABLED=true
AUTO_SCALING_MIN_NODES=1
AUTO_SCALING_MAX_NODES=5
AUTO_SCALING_TARGET_CPU=70
AUTO_SCALING_TARGET_CONNECTIONS=100

# Connection limits
MAX_CONNECTIONS_PER_NODE=50
CONNECTION_DRAIN_TIMEOUT=30

Health Monitoring

# Health check intervals (seconds)
HEALTH_CHECK_INTERVAL=30
HEALTH_CHECK_TIMEOUT=10
HEALTH_CHECK_RETRIES=3
HEALTH_CHECK_BACKOFF_FACTOR=2

# Failover settings
FAILOVER_ENABLED=true
FAILOVER_THRESHOLD=3  # Failed health checks before failover
FAILOVER_COOLDOWN=300  # Seconds before retry

Speed Testing

# Speed test configuration
SPEED_TEST_ENABLED=true
SPEED_TEST_INTERVAL=3600  # Run every hour
SPEED_TEST_TIMEOUT=60
SPEED_TEST_SERVERS=["fast.com", "speedtest.net", "google.com"]

# Test file sizes
SPEED_TEST_DOWNLOAD_SIZE=10MB
SPEED_TEST_UPLOAD_SIZE=5MB

Metrics and Logging

# Logging
LOG_LEVEL=INFO  # DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_FORMAT=json  # json or text
LOG_FILE=/var/log/vpn-controller/app.log
LOG_ROTATION=daily
LOG_RETENTION_DAYS=30

# Metrics
METRICS_ENABLED=true
METRICS_RETENTION_HOURS=168  # 7 days
METRICS_AGGREGATION_INTERVAL=60  # seconds

Security Settings

# API Security
API_RATE_LIMIT_ENABLED=true
API_RATE_LIMIT_PER_MINUTE=100
API_RATE_LIMIT_BURST=20

# IP Whitelisting (comma-separated)
API_WHITELIST_IPS=10.0.0.0/8,192.168.0.0/16
API_BLACKLIST_IPS=

# Session Management
SESSION_TIMEOUT=3600  # 1 hour
SESSION_SECURE_COOKIE=true
SESSION_SAME_SITE=strict

Domain and SSL Configuration

# Domain settings
DOMAIN=rbnk.uk
API_SUBDOMAIN=vpn-api
DOCS_SUBDOMAIN=vpn-docs

# Cloudflare
CF_API_TOKEN=your_cloudflare_api_token
CF_ZONE_ID=your_zone_id
CF_PROXY_ENABLED=true

# SSL/TLS
[email protected]
SSL_STAGING=false  # Set to true for Let's Encrypt staging

Service Configuration

Systemd Service

Edit /etc/systemd/system/vpn-controller.service:

[Unit]
Description=VPN Exit Controller API
After=network.target redis.service docker.service
Wants=redis.service docker.service

[Service]
Type=exec
User=root
Group=docker
WorkingDirectory=/opt/vpn-exit-controller

# Environment
Environment="PATH=/opt/vpn-exit-controller/venv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
EnvironmentFile=/opt/vpn-exit-controller/.env

# Process management
ExecStart=/opt/vpn-exit-controller/venv/bin/python -m uvicorn api.main:app --host 0.0.0.0 --port 8080
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

# Restart policy
Restart=always
RestartSec=10
RestartPreventExitStatus=0

# Resource limits
LimitNOFILE=65536
LimitNPROC=4096

# Security
PrivateTmp=true
NoNewPrivileges=true

[Install]
WantedBy=multi-user.target

Docker Configuration

Docker Compose Override

Create docker-compose.override.yml for local settings:

version: '3.8'

services:
  vpn-controller:
    environment:
      - LOG_LEVEL=DEBUG
      - API_RELOAD=true
    volumes:
      - ./custom-configs:/app/custom-configs
    ports:
      - "8081:8080"  # Different port for development

Docker Resource Limits

services:
  vpn-controller:
    deploy:
      resources:
        limits:
          cpus: '2.0'
          memory: 2G
        reservations:
          cpus: '0.5'
          memory: 512M

HAProxy Configuration

Load Balancer Tuning

Edit /opt/vpn-exit-controller/proxy/haproxy.cfg:

global
    # Performance tuning
    maxconn 10000
    nbproc 4
    nbthread 8
    cpu-map auto:1/1-8 0-7

    # Timeouts
    timeout connect 5s
    timeout client 30s
    timeout server 30s
    timeout tunnel 1h

    # SSL/TLS tuning
    tune.ssl.default-dh-param 2048
    ssl-default-bind-ciphers ECDHE+AESGCM:ECDHE+AES256:ECDHE+AES128
    ssl-default-bind-options no-sslv3 no-tlsv10 no-tlsv11

Backend Configuration

backend proxy_us
    # Load balancing algorithm
    balance leastconn  # or roundrobin, source, uri

    # Health checks
    option httpchk GET /health HTTP/1.1\r\nHost:\ localhost
    http-check expect status 200

    # Connection settings
    option http-server-close
    option forwardfor
    http-reuse safe

    # Servers with advanced options
    server vpn-us-1 10.0.0.11:8888 check inter 5s rise 2 fall 3 weight 100
    server vpn-us-2 10.0.0.12:8888 check inter 5s rise 2 fall 3 weight 100 backup

Traefik Configuration

Dynamic Configuration

Create traefik/dynamic/vpn-controller.yml:

http:
  routers:
    vpn-api:
      rule: "Host(`vpn-api.rbnk.uk`)"
      service: vpn-api
      entryPoints:
        - websecure
      tls:
        certResolver: cf
      middlewares:
        - rate-limit
        - security-headers

  services:
    vpn-api:
      loadBalancer:
        servers:
          - url: "http://localhost:8080"
        healthCheck:
          path: /api/health
          interval: 30s
          timeout: 10s

  middlewares:
    rate-limit:
      rateLimit:
        average: 100
        burst: 50
        period: 1m

    security-headers:
      headers:
        customFrameOptionsValue: SAMEORIGIN
        contentTypeNosniff: true
        browserXssFilter: true
        stsSeconds: 31536000
        stsIncludeSubdomains: true
        stsPreload: true

Application Configuration

API Settings

Create api/config.py for application-specific settings:

from pydantic_settings import BaseSettings
from typing import List, Optional

class Settings(BaseSettings):
    # API Settings
    title: str = "VPN Exit Controller API"
    version: str = "1.0.0"
    description: str = "Professional VPN node management system"
    docs_url: str = "/api/docs"
    redoc_url: str = "/api/redoc"

    # Feature flags
    enable_metrics: bool = True
    enable_webhooks: bool = True
    enable_speed_tests: bool = True
    enable_auto_scaling: bool = True

    # Performance tuning
    connection_pool_size: int = 100
    request_timeout: int = 30
    background_task_workers: int = 4

    class Config:
        env_file = ".env"
        case_sensitive = False

settings = Settings()

Runtime Configuration API

Configure settings via API without restart:

# Update load balancing strategy
curl -X PUT -u admin:password \
  -H "Content-Type: application/json" \
  -d '{"key": "load_balancing.strategy", "value": "health_score"}' \
  https://api.vpn.yourdomain.com/api/config

# Update health check interval
curl -X PUT -u admin:password \
  -H "Content-Type: application/json" \
  -d '{"key": "health_check.interval", "value": 60}' \
  https://api.vpn.yourdomain.com/api/config

Configuration Best Practices

Environment Management

  1. Development Environment

    # .env.development
    LOG_LEVEL=DEBUG
    API_RELOAD=true
    SSL_STAGING=true
    

  2. Production Environment

    # .env.production
    LOG_LEVEL=INFO
    API_RELOAD=false
    SSL_STAGING=false
    

  3. Environment Loading

    # Load specific environment
    export ENV=production
    source .env.$ENV
    

Secret Management

Security Best Practice

Never commit secrets to version control. Use secure secret management solutions.

Options for secret management:

  1. HashiCorp Vault

    import hvac
    client = hvac.Client(url='https://vault.company.com')
    nordvpn_pass = client.read('secret/vpn/nordvpn')['data']['password']
    

  2. AWS Secrets Manager

    import boto3
    client = boto3.client('secretsmanager')
    secret = client.get_secret_value(SecretId='vpn-controller-secrets')
    

  3. Environment Variable Encryption

    # Encrypt secrets
    echo "password" | openssl enc -aes-256-cbc -base64 -out secret.enc
    
    # Decrypt at runtime
    export API_PASSWORD=$(openssl enc -aes-256-cbc -d -base64 -in secret.enc)
    

Configuration Validation

Validate configuration on startup:

def validate_config():
    """Validate all configuration settings"""
    errors = []

    # Check required variables
    required = ['NORDVPN_USER', 'NORDVPN_PASS', 'TAILSCALE_AUTH_KEY']
    for var in required:
        if not os.getenv(var):
            errors.append(f"Missing required: {var}")

    # Validate formats
    if os.getenv('API_PORT'):
        try:
            port = int(os.getenv('API_PORT'))
            if not 1 <= port <= 65535:
                errors.append("Invalid port range")
        except ValueError:
            errors.append("API_PORT must be integer")

    if errors:
        raise ConfigurationError("\n".join(errors))

Monitoring Configuration

Use these commands to verify configuration:

# Check loaded environment
./scripts/check-config.sh

# Validate configuration
python -m api.config validate

# Test configuration changes
curl -u admin:password https://api.vpn.yourdomain.com/api/config/test

Next Steps


Configuration Tips

  • Always use .env.example as a template
  • Keep production secrets in a secure vault
  • Monitor configuration changes with audit logs
  • Test configuration changes in staging first
  • Document all custom configuration options