Skip to main content
Entirius
AI platform for e-commerce
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

HAProxy Configuration for KVM Services Public Access

This guide describes how to configure HAProxy on the Entirius KVM Server to publicly expose services running in KVM instances, such as n8n deployed using the N8N Deployment guide.

Prerequisites

This guide assumes you have completed:

  • KVM Server Install - Ubuntu 24.04 server with KVM, HAProxy, and WebVirtCloud
  • N8N Deployment - At least one n8n instance deployed using entirius-scripts-kvm-deployer

You should have:

  • HAProxy already installed and configured with basic settings
  • One or more KVM instances running services (e.g., n8n on port 80)
  • VM instances accessible on the bridge network (br0)

Overview

HAProxy will act as a reverse proxy to route incoming requests to appropriate KVM instances based on:

  • Host headers (domain-based routing)
  • Path prefixes (path-based routing)
  • Port-based routing (different services on different ports)

Step 1: Identify KVM Instance IPs

First, identify the IP addresses of your KVM instances:

# List all running VMs
sudo virsh list --all

# Get IP address for specific VM (replace with your VM name)
sudo virsh domifaddr vm-company-production-n8n

# Example output:
# Name       MAC address          Protocol     Address
# -------------------------------------------------------------------------------
# vnet0      52:54:00:xx:xx:xx    ipv4         192.168.122.100/24

Add these IPs to your /etc/hosts file for easy management:

sudo vim /etc/hosts

Add entries for your KVM instances:

# KVM Instances
192.168.122.100  n8n-prod.local
192.168.122.101  n8n-staging.local
192.168.122.102  api-service.local

Step 2: Configure HAProxy for KVM Services

Edit the HAProxy configuration:

sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.backup
sudo vim /etc/haproxy/haproxy.cfg

Here’s a complete configuration example that exposes multiple KVM services:

global
    log stdout local0
    chroot /var/lib/haproxy
    stats socket /run/haproxy/admin.sock mode 660 level admin
    stats timeout 30s
    user haproxy
    group haproxy
    daemon

defaults
    mode http
    log global
    option httplog
    option dontlognull
    option log-health-checks
    option forwardfor
    option http-server-close
    timeout connect 5000
    timeout client 50000
    timeout server 50000
    errorfile 400 /etc/haproxy/errors/400.http
    errorfile 403 /etc/haproxy/errors/403.http
    errorfile 408 /etc/haproxy/errors/408.http
    errorfile 500 /etc/haproxy/errors/500.http
    errorfile 502 /etc/haproxy/errors/502.http
    errorfile 503 /etc/haproxy/errors/503.http
    errorfile 504 /etc/haproxy/errors/504.http

# HAProxy Statistics Interface
listen stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 30s
    stats admin if TRUE

# Frontend for HTTP traffic
frontend http_frontend
    bind *:80

    # Domain-based routing for n8n instances
    acl is_n8n_prod hdr(host) -i n8n.yourdomain.com
    acl is_n8n_staging hdr(host) -i n8n-staging.yourdomain.com

    # Path-based routing examples
    acl is_api path_beg /api
    acl is_webhooks path_beg /webhook

    # Route to appropriate backends
    use_backend n8n_production if is_n8n_prod
    use_backend n8n_staging if is_n8n_staging
    use_backend api_services if is_api
    use_backend webhook_services if is_webhooks

    # Default backend (you can customize this)
    default_backend webvirtcloud_backend

# Frontend for HTTPS traffic
frontend https_frontend
    bind *:443 ssl crt /etc/haproxy/ssl/haproxy.pem

    # Same ACL rules as HTTP
    acl is_n8n_prod hdr(host) -i n8n.yourdomain.com
    acl is_n8n_staging hdr(host) -i n8n-staging.yourdomain.com
    acl is_api path_beg /api
    acl is_webhooks path_beg /webhook

    # Route to appropriate backends
    use_backend n8n_production if is_n8n_prod
    use_backend n8n_staging if is_n8n_staging
    use_backend api_services if is_api
    use_backend webhook_services if is_webhooks

    # Default backend
    default_backend webvirtcloud_backend

# Backend for production n8n instance
backend n8n_production
    balance roundrobin
    option httpchk GET /healthz
    http-check expect status 200
    server n8n-prod 192.168.122.100:80 check

# Backend for staging n8n instance
backend n8n_staging
    balance roundrobin
    option httpchk GET /healthz
    http-check expect status 200
    server n8n-staging 192.168.122.101:80 check

# Backend for API services
backend api_services
    balance roundrobin
    option httpchk GET /health
    http-check expect status 200
    server api1 192.168.122.102:8000 check
    server api2 192.168.122.103:8000 check

# Backend for webhook services
backend webhook_services
    balance roundrobin
    server webhook1 192.168.122.100:80 check

# Backend for WebVirtCloud (management interface)
backend webvirtcloud_backend
    balance roundrobin
    server webvirtcloud 127.0.0.1:8080 check

Step 3: SSL Certificate Configuration

If you haven’t already configured SSL certificates, you can use Let’s Encrypt or create self-signed certificates:

Option A: Self-signed Certificate (for testing)

sudo mkdir -p /etc/haproxy/ssl
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
    -keyout /etc/haproxy/ssl/haproxy.pem \
    -out /etc/haproxy/ssl/haproxy.pem \
    -subj "/C=US/ST=State/L=City/O=Organization/CN=yourdomain.com"

sudo chown haproxy:haproxy /etc/haproxy/ssl/haproxy.pem
sudo chmod 600 /etc/haproxy/ssl/haproxy.pem

Option B: Let’s Encrypt Certificate (for production)

# Install certbot
sudo apt install certbot

# Stop HAProxy temporarily
sudo systemctl stop haproxy

# Generate certificate
sudo certbot certonly --standalone -d n8n.yourdomain.com -d n8n-staging.yourdomain.com

# Combine certificate and key for HAProxy
sudo cat /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem \
         /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem > \
         /etc/haproxy/ssl/haproxy.pem

sudo chown haproxy:haproxy /etc/haproxy/ssl/haproxy.pem
sudo chmod 600 /etc/haproxy/ssl/haproxy.pem

# Start HAProxy
sudo systemctl start haproxy

Step 4: Validate and Apply Configuration

Test the HAProxy configuration:

# Test configuration syntax
sudo haproxy -f /etc/haproxy/haproxy.cfg -c

If the configuration is valid, reload HAProxy:

# Reload HAProxy with new configuration
sudo systemctl reload haproxy

# Check HAProxy status
sudo systemctl status haproxy

# View HAProxy logs
sudo journalctl -u haproxy -f

Step 5: DNS Configuration

Configure your DNS to point to your server:

# DNS A Records (replace with your server's public IP)
n8n.yourdomain.com         IN A    YOUR.SERVER.PUBLIC.IP
n8n-staging.yourdomain.com IN A    YOUR.SERVER.PUBLIC.IP
api.yourdomain.com         IN A    YOUR.SERVER.PUBLIC.IP

For local testing, add entries to your local /etc/hosts:

YOUR.SERVER.IP  n8n.yourdomain.com
YOUR.SERVER.IP  n8n-staging.yourdomain.com
YOUR.SERVER.IP  api.yourdomain.com

Step 6: Firewall Configuration

Ensure your firewall allows the necessary ports:

# Allow HTTP and HTTPS traffic
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

# Allow HAProxy stats (optional, restrict as needed)
sudo ufw allow 8404/tcp

# Check firewall status
sudo ufw status

Step 7: Testing

Test your configuration:

# Test HTTP access to n8n
curl -H "Host: n8n.yourdomain.com" http://YOUR.SERVER.IP/

# Test HTTPS access
curl -k -H "Host: n8n.yourdomain.com" https://YOUR.SERVER.IP/

# Test API endpoint
curl -H "Host: api.yourdomain.com" http://YOUR.SERVER.IP/api/health

# Check HAProxy stats
curl http://YOUR.SERVER.IP:8404/stats

Advanced Configuration Examples

Load Balancing Multiple n8n Instances

If you have multiple n8n instances for high availability:

backend n8n_production
    balance roundrobin
    option httpchk GET /healthz
    http-check expect status 200
    server n8n-prod-1 192.168.122.100:80 check
    server n8n-prod-2 192.168.122.101:80 check weight 2
    server n8n-prod-3 192.168.122.102:80 check backup

Sticky Sessions

For applications requiring session persistence:

backend n8n_production
    balance roundrobin
    cookie SERVERID insert indirect nocache
    server n8n-prod-1 192.168.122.100:80 check cookie n8n1
    server n8n-prod-2 192.168.122.101:80 check cookie n8n2

Rate Limiting

To prevent abuse:

frontend http_frontend
    # Rate limiting: 10 requests per 10 seconds per IP
    stick-table type ip size 100k expire 30s store http_req_rate(10s)
    http-request track-sc0 src
    http-request deny if { sc_http_req_rate(0) gt 10 }

Monitoring and Logging

HAProxy Stats Page

Access the stats page at: http://YOUR.SERVER.IP:8404/stats

This provides real-time monitoring of:

  • Backend server status
  • Request rates and response times
  • Connection counts
  • Health check results

Log Analysis

Monitor HAProxy logs:

# Follow HAProxy logs
sudo journalctl -u haproxy -f

# Analyze access patterns
sudo grep "n8n.yourdomain.com" /var/log/haproxy.log | tail -20

# Check for errors
sudo grep "HTTP/5" /var/log/haproxy.log

Troubleshooting

Common Issues

  1. 503 Service Unavailable

    • Check if KVM instances are running: sudo virsh list
    • Verify instance IPs: sudo virsh domifaddr VM_NAME
    • Test direct access: curl http://192.168.122.100:80
  2. SSL Certificate Issues

    • Check certificate validity: openssl x509 -in /etc/haproxy/ssl/haproxy.pem -text -noout
    • Verify certificate permissions: ls -la /etc/haproxy/ssl/
  3. Health Check Failures

    • Check if health check endpoints exist
    • Verify firewall rules on KVM instances
    • Test health checks manually: curl http://192.168.122.100/healthz

Debugging Commands

# Check HAProxy configuration
sudo haproxy -f /etc/haproxy/haproxy.cfg -c

# View real-time connections
sudo ss -tlnp | grep haproxy

# Check backend server connectivity
sudo netcat -zv 192.168.122.100 80

# Monitor HAProxy stats via CLI
echo "show stat" | sudo socat stdio /run/haproxy/admin.sock

Security Considerations

  1. Access Control: Restrict HAProxy stats page access
  2. SSL Configuration: Use strong SSL/TLS settings
  3. Rate Limiting: Implement rate limiting for public endpoints
  4. Monitoring: Set up alerts for service failures
  5. Firewall: Ensure only necessary ports are exposed

Maintenance

Adding New Services

  1. Deploy new KVM instance using entirius-scripts-kvm-deployer
  2. Get instance IP: sudo virsh domifaddr NEW_VM_NAME
  3. Add backend configuration to HAProxy
  4. Add routing rules to frontend
  5. Test and reload HAProxy configuration

SSL Certificate Renewal (Let’s Encrypt)

# Create renewal script
sudo vim /etc/cron.monthly/renew-haproxy-ssl
#!/bin/bash
certbot renew --quiet
cat /etc/letsencrypt/live/n8n.yourdomain.com/fullchain.pem \
    /etc/letsencrypt/live/n8n.yourdomain.com/privkey.pem > \
    /etc/haproxy/ssl/haproxy.pem
chown haproxy:haproxy /etc/haproxy/ssl/haproxy.pem
chmod 600 /etc/haproxy/ssl/haproxy.pem
systemctl reload haproxy
sudo chmod +x /etc/cron.monthly/renew-haproxy-ssl

This configuration provides a robust reverse proxy setup for exposing KVM-based services publicly while maintaining security and monitoring capabilities.