Skip to content

bayars/haproxy-dynamic-socket

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

HAProxy + Terraform Deployer for Guacamole VMs (GCP)

Dynamic HAProxy load balancer that creates separate ACLs and backends for each controller. Deploys Guacamole VMs in GCP using Terraform with automatic HAProxy configuration.

Architecture

┌─────────────────────────────────────┐
│   HAProxy                           │  :80   - HTTP traffic
│                                     │  :9999 - Stats
│   Frontend: console_frontend       │
│   ├─ ACL: guac_access_controller1  │──► Backend: backend_controller1
│   ├─ ACL: guac_access_controller2  │──► Backend: backend_controller2
│   └─ ACL: guac_access_controllerN  │──► Backend: backend_controllerN
└─────────────────────────────────────┘
         │
         ├─► /console/controller1/* ──► backend_controller1 ──► VM1 (35.1.2.3:8080)
         ├─► /console/controller2/* ──► backend_controller2 ──► VM2 (35.1.2.4:8080)
         └─► /console/controllerN/* ──► backend_controllerN ──► VMN (...)

┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│  Deployer 1  │  │  Deployer 2  │  │  Deployer N  │
│  (Terraform) │  │  (Terraform) │  │  (Terraform) │
└──────┬───────┘  └──────┬───────┘  └──────┬───────┘
       │                 │                 │
       ├─► Creates GCP VMs with Guacamole
       ├─► Generates controller config snippet
       ├─► Rebuilds HAProxy config
       └─► Graceful reload (near-zero downtime)

Key Features

  • Separate ACL + Backend per Controller: Each controller gets its own dedicated backend
  • Dynamic Configuration: Config generated from snippets, validated, and gracefully reloaded
  • GCP-Optimized: Ready-to-use Google Cloud Platform examples
  • Multiple Deployers: Run concurrent deployers safely
  • URL Routing: Access each VM at /console/<controller_id>/
  • Near-Zero Downtime: Graceful reload when adding/removing controllers
  • WebSocket Support: Optimized for Guacamole connections

How It Works

1. Controller Registration

When Terraform deploys a VM:

# 1. Create controller config snippet
/scripts/manage-controller.sh add controller123 35.1.2.100 8080

# This creates: /etc/haproxy/controllers/controller123.conf
# Containing:
# - ACL definition: guac_access_controller123 path_beg /console/controller123
# - Backend definition: backend_controller123 with server 35.1.2.100:8080

# 2. Rebuild HAProxy config
docker exec haproxy /usr/local/bin/manage-controller.sh rebuild

# This:
# - Reads all controller configs from /etc/haproxy/controllers/
# - Injects ACLs into frontend section
# - Injects backends into backends section
# - Validates the new config
# - Gracefully reloads HAProxy (no dropped connections)

2. Generated HAProxy Config

For each controller, HAProxy will have:

frontend console_frontend
    # ... other config ...

    acl guac_access_controller123 path_beg /console/controller123
    use_backend backend_controller123 if guac_access_controller123

    acl guac_access_prod01 path_beg /console/prod01
    use_backend backend_prod01 if guac_access_prod01

backend backend_controller123
    balance roundrobin
    option httpchk GET /
    server vm_backend_controller123 35.1.2.100:8080 check

backend backend_prod01
    balance roundrobin
    option httpchk GET /
    server vm_backend_prod01 10.0.1.50:8080 check

Quick Start (GCP)

Prerequisites

  1. GCP account with project created
  2. Docker and docker-compose installed
  3. GCP credentials configured (gcloud auth login)

1. Start HAProxy

cd haproxy

# Create the network first
docker network create haproxy-network

# Start HAProxy
docker-compose up -d

# Verify it's running
docker logs haproxy
curl http://localhost:9999/stats

2. Configure Deployer for GCP

cd deployer

# Copy and configure variables
cp terraform.tfvars.example terraform.tfvars
nano terraform.tfvars

# Set your GCP project
# gcp_project = "my-project-123"
# haproxy_public_url = "http://35.1.2.3"  # Your HAProxy public IP

# Copy provider configuration
cp providers.tf.example providers.tf
# GCP provider is already configured - ready to use!

3. Deploy Your First VM

# Set environment variables for GCP
export GOOGLE_PROJECT="your-gcp-project-id"
export HAPROXY_PUBLIC_URL="http://your-haproxy-ip"

# Start deployer container
DEPLOYER_ID=1 docker-compose up -d

# Enter deployer
docker exec -it deployer_1 sh

# Inside container:
terraform init
terraform plan
terraform apply

Terraform will:

  1. Create a GCP VM named safa4-cont-<random-id>.my.domain.com
  2. Install Guacamole on the VM
  3. Generate controller config snippet
  4. Rebuild HAProxy config with new ACL + backend
  5. Gracefully reload HAProxy
  6. Output console URL

4. Access Guacamole

# Get the console URL from Terraform output
terraform output console_url
# Example: http://35.1.2.3/console/a1b2c3d4/

Default Guacamole credentials: guacadmin / guacadmin

5. Verify HAProxy Configuration

# View the generated HAProxy config
docker exec haproxy cat /usr/local/etc/haproxy/haproxy.cfg

# You should see your controller's ACL and backend

Multiple Deployers (Concurrent Deployments)

Run multiple deployers simultaneously:

cd deployer

# Terminal 1
DEPLOYER_ID=1 GOOGLE_PROJECT=my-project docker-compose up -d
docker exec -it deployer_1 sh
# terraform apply

# Terminal 2
DEPLOYER_ID=2 GOOGLE_PROJECT=my-project docker-compose up -d
docker exec -it deployer_2 sh
# terraform apply

# Terminal 3
DEPLOYER_ID=3 GOOGLE_PROJECT=my-project docker-compose up -d
docker exec -it deployer_3 sh
# terraform apply

All deployers share the same controllers directory and can register backends concurrently.

Manual Controller Management

Use the management script directly:

Add a controller:

# From deployer container:
/scripts/manage-controller.sh add controller123 35.1.2.100 8080

# Rebuild HAProxy config:
docker exec haproxy /usr/local/bin/manage-controller.sh rebuild

Remove a controller:

/scripts/manage-controller.sh remove controller123
docker exec haproxy /usr/local/bin/manage-controller.sh rebuild

List all controllers:

ls -la /etc/haproxy/controllers/

View controller config:

cat /etc/haproxy/controllers/controller123.conf

Configuration

HAProxy Configuration Template

Located in haproxy/haproxy.cfg:

frontend console_frontend
    bind *:80

    ### CONTROLLERS_START ###
    # ACLs and use_backend rules inserted here
    ### CONTROLLERS_END ###

    default_backend no_backend

### BACKENDS_START ###
# Backend definitions inserted here
### BACKENDS_END ###

Key settings:

  • Timeout tunnel: 3600s for WebSocket connections
  • Stats port: 9999
  • Graceful reload: No connection drops when updating config

GCP Variables

Edit deployer/terraform.tfvars:

# GCP settings
gcp_project = "my-gcp-project"
gcp_region  = "us-central1"
gcp_zone    = "us-central1-a"

# VM configuration
vm_machine_type = "e2-medium"
vm_image        = "ubuntu-os-cloud/ubuntu-2204-lts"

# HAProxy public URL
haproxy_public_url = "http://35.1.2.3"

Custom Controller ID

Specify a custom controller ID instead of random:

# In terraform.tfvars
controller_id = "prod-us-central1"

This will create:

  • ACL: guac_access_prod-us-central1
  • Backend: backend_prod-us-central1
  • URL: /console/prod-us-central1/

Monitoring

HAProxy Stats Page

http://your-haproxy:9999/stats

View Current Configuration

docker exec haproxy cat /usr/local/etc/haproxy/haproxy.cfg

List All Controllers

docker exec haproxy ls -la /etc/haproxy/controllers/

Check Controller Config

docker exec haproxy cat /etc/haproxy/controllers/controller123.conf

View HAProxy Logs

docker logs -f haproxy

Troubleshooting

Controller Not Registering

Check controller config was created:

docker exec haproxy ls /etc/haproxy/controllers/

Check if config was rebuilt:

docker exec haproxy cat /usr/local/etc/haproxy/haproxy.cfg | grep controller123

Manually trigger rebuild:

docker exec haproxy /usr/local/bin/manage-controller.sh rebuild

404 Error on Console Access

Verify ACL exists in config:

docker exec haproxy grep "guac_access_controller123" /usr/local/etc/haproxy/haproxy.cfg

Verify backend exists:

docker exec haproxy grep "backend_controller123" /usr/local/etc/haproxy/haproxy.cfg

Check HAProxy logs:

docker logs -f haproxy

VM Not Accessible

Test VM directly:

curl http://<vm-ip>:8080/guacamole

Check GCP firewall:

gcloud compute firewall-rules list --filter="targetTags:guacamole"

SSH to VM and check Guacamole:

gcloud compute ssh <vm-name> --zone=us-central1-a
docker ps
curl localhost:8080/guacamole

Configuration Validation Failed

Check syntax:

docker exec haproxy haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg

View controller config:

cat /etc/haproxy/controllers/controller123.conf

Check for duplicate controllers:

docker exec haproxy ls /etc/haproxy/controllers/ | sort | uniq -d

Directory Structure

.
├── haproxy/
│   ├── docker-compose.yml         # HAProxy container
│   ├── haproxy.cfg                # HAProxy config template
│   └── manage-controller.sh       # Controller management script
│
├── deployer/
│   ├── docker-compose.yml         # Deployer container
│   ├── main.tf                    # Terraform main
│   ├── variables.tf               # Terraform variables (GCP-focused)
│   ├── providers.tf.example       # GCP provider config
│   ├── terraform.tfvars.example   # Example GCP values
│   └── install-guacamole.sh       # Guacamole installation script
│
└── README.md

Advanced Configuration

SSL/TLS Support

Add SSL to haproxy/haproxy.cfg:

frontend console_frontend
    bind *:443 ssl crt /etc/haproxy/ssl/cert.pem
    bind *:80
    redirect scheme https if !{ ssl_fc }

Mount certificate in docker-compose.yml:

volumes:
  - ./ssl/cert.pem:/etc/haproxy/ssl/cert.pem:ro

Custom Health Checks

Edit haproxy/manage-controller.sh to customize health checks:

# In the rebuild_config() function, modify:
echo "    option httpchk GET /guacamole" >> "$TEMP_BACKENDS"
echo "    server vm_${value1} ${value2}:${value3} check inter 5s fall 3 rise 2" >> "$TEMP_BACKENDS"

Path Rewriting

Add path rewriting in backend section:

backend backend_controller123
    http-request set-path %[path,regsub(^/console/controller123,/guacamole)]
    server vm_backend_controller123 35.1.2.100:8080 check

Security Considerations

  1. Config Validation: All configs are validated before reload
  2. GCP Firewall: Configure firewall rules for Guacamole VMs
  3. Guacamole Auth: Change default credentials immediately
  4. HAProxy Stats: Restrict access to stats page in production
  5. SSL/TLS: Use HTTPS for production deployments
  6. Network Isolation: Use VPCs and private networking

Benefits of This Approach

Separate Backend per Controller: Exactly what you wanted! ✅ Dynamic ACLs: Each controller gets its own ACL ✅ Isolated Backends: Each VM has its own dedicated backend ✅ Near-Zero Downtime: Graceful reload keeps connections alive ✅ Simple: No API authentication needed ✅ Validated: Config is checked before reload ✅ GCP-Ready: Optimized for Google Cloud Platform

How Graceful Reload Works

When manage-controller.sh rebuild is called:

  1. Generate new config from all controller snippets
  2. Validate config with haproxy -c
  3. Backup current config
  4. Write new config
  5. Send USR2 signal to HAProxy (graceful reload)
  6. HAProxy:
    • Starts new process with new config
    • New connections go to new process
    • Old connections finish on old process
    • Old process exits when all connections done

Result: No dropped connections!

License

This configuration is provided as-is for educational and operational purposes.

Support

  • Check HAProxy logs: docker logs haproxy
  • View Terraform state: terraform show
  • Validate config: docker exec haproxy haproxy -c -f /usr/local/etc/haproxy/haproxy.cfg
  • GCP documentation: https://cloud.google.com/compute/docs

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors