- Added detailed `README.md` files with step-by-step instructions for Docker Compose, Kubernetes, Swarm, and static configuration examples. - Included use cases for SSL setup, Let's Encrypt integration, load balancing, and advanced features like plugins and path-based routing. - Documented environment variables, service labels, and troubleshooting tips across all examples. - Enhanced examples with clear testing guidelines, SSL certificate generation steps, and debugging workflows.
9.3 KiB
Static Configuration Example
This directory demonstrates EasyHAProxy using static configuration mode instead of dynamic service discovery.
What is Static Mode?
Static mode uses a YAML configuration file (config.yml) to define HAProxy routing rules instead of discovering services automatically from Docker/Kubernetes/Swarm labels.
Use cases:
- Non-containerized backends
- Mixed environments (containers + VMs + bare metal)
- Fixed infrastructure where services don't change frequently
- Testing HAProxy configurations
Files in This Example
conf/config.yml- Static configuration defining hosts and routingdocker-compose.yml- EasyHAProxy container mounting the config filehost1.local.pem- Example SSL certificate
Configuration Structure
docker-compose.yml
services:
haproxy:
image: byjg/easy-haproxy:4.6.0
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./conf:/etc/haproxy/static # Mount static config
- ./host1.local.pem:/certs/haproxy/host1.local.pem
environment:
EASYHAPROXY_DISCOVER: static # Use static mode
EASYHAPROXY_SSL_MODE: "loose"
ports:
- "80:80"
- "443:443"
- "1936:1936"
conf/config.yml
stats:
username: admin
password: password
port: 1936
customerrors: true
easymapping:
# HTTP Port 80 - Redirects to HTTPS
- port: 80
redirect:
host1.local: https://host1.local
www.host1.local: https://host1.local
# HTTPS Port 443
- port: 443
ssl: true
hosts:
host1.local:
containers:
- container:8080 # Backend container
How It Works
1. Port Definitions
Each item in easymapping defines a listening port:
easymapping:
- port: 80 # Listen on port 80
redirect: {...} # Optional redirects
- port: 443 # Listen on port 443
ssl: true # Enable SSL
hosts: {...} # Virtual hosts
2. Redirect Configuration
Redirect specific domains to different URLs:
- port: 80
redirect:
host1.local: https://host1.local # HTTP → HTTPS
www.host1.local: https://host1.local # www → non-www + HTTPS
old.domain.com: https://new.domain.com # Domain change
3. Virtual Hosts
Define hosts and their backend containers:
- port: 443
ssl: true
hosts:
host1.local: # Virtual host domain
containers:
- container:8080 # Backend: container_name:port
- another_container:3000 # Multiple backends = load balancing
host2.local:
containers:
- webserver:80
Backend formats:
container_name:port- Docker container by nameip_address:port- Direct IP addresshostname:port- Hostname resolution
4. SSL Configuration
- port: 443
ssl: true # Enable SSL on this port
hosts:
secure.example.com:
containers:
- app:8080
SSL certificates must be placed in:
/certs/haproxy/<domain>.peminside container./certs/<domain>.pemon host (if volume mounted)
Certificate format: PEM file containing both certificate and private key.
5. Stats Interface
stats:
username: admin
password: password
port: 1936
Access at: http://localhost:1936
Running the Example
1. Start the Example
cd examples/static
docker compose up -d
2. Create Backend Container
The static config references container:8080. Create a container with this name:
docker run -d --name container \
-p 8080:8080 \
byjg/static-httpserver
Or add to docker-compose.yml:
services:
# ... haproxy service ...
container:
image: byjg/static-httpserver
ports:
- "8080:8080"
3. Test
# Add to /etc/hosts:
# 127.0.0.1 host1.local www.host1.local
# Test HTTP redirect
curl -I http://host1.local
# Should return: HTTP/1.1 301 Moved Permanently
# Location: https://host1.local
# Test HTTPS
curl -k https://host1.local
# Access stats
open http://localhost:1936
# Username: admin
# Password: password
Advanced Configuration
Load Balancing Multiple Backends
hosts:
api.example.com:
containers:
- api_server_1:8080
- api_server_2:8080
- api_server_3:8080
Default algorithm: round-robin
Custom Balance Algorithm
hosts:
api.example.com:
balance: leastconn # Use least connections instead of round-robin
containers:
- api_1:8080
- api_2:8080
Available algorithms:
roundrobin- Distribute evenly (default)leastconn- Send to server with fewest connectionssource- Same client IP always goes to same server
External Backends (Non-Docker)
hosts:
legacy.example.com:
containers:
- 192.168.1.100:8080 # VM
- 192.168.1.101:8080 # Another VM
- database.local:5432 # Database server
Health Checks
hosts:
webapp.example.com:
containers:
- server1:8080
- server2:8080
healthcheck:
path: /health
interval: 5s
Multiple Domains, Same Backend
hosts:
example.com:
containers:
- webapp:8080
www.example.com:
containers:
- webapp:8080 # Same backend
app.example.com:
containers:
- webapp:8080 # Same backend
Path-Based Routing
While static mode focuses on host-based routing, you can achieve path-based routing using redirects:
- port: 80
redirect:
api.example.com/v1: https://api-v1.internal:8080
api.example.com/v2: https://api-v2.internal:8080
Or use HAProxy ACLs via custom templates (advanced).
Plugins with Static Configuration
Enable plugins globally or per-host in static mode:
Global Plugin Configuration
plugins:
enabled: [cleanup]
config:
cleanup:
max_idle_time: 600
Per-Host Plugin Configuration (via env vars)
Since static mode doesn't support per-host plugin configuration directly, use environment variables for domain-specific plugins:
environment:
EASYHAPROXY_PLUGINS_ENABLED: cloudflare,deny_pages
EASYHAPROXY_PLUGIN_CLOUDFLARE_IP_LIST_PATH: /etc/haproxy/cloudflare_ips.lst
EASYHAPROXY_PLUGIN_DENY_PAGES_PATHS: /admin,/private
See Using Plugins for more details.
Comparison: Static vs. Dynamic Discovery
| Feature | Static Mode | Docker/Swarm/K8s Mode |
|---|---|---|
| Configuration | YAML file | Container labels / Ingress annotations |
| Backend types | Any (containers, VMs, IPs) | Containers only |
| Updates | Manual config edit + reload | Automatic discovery |
| Use case | Fixed infrastructure | Dynamic container environments |
| Plugin config | Global via YAML/env | Per-container/ingress via labels/annotations |
Tips
-
Reloading Configuration:
# EasyHAProxy watches config.yml for changes # Edit conf/config.yml, changes auto-reload # Or manually restart: docker compose restart haproxy -
Validate Configuration:
# Check HAProxy config is valid docker compose exec haproxy haproxy -c -f /etc/haproxy/haproxy.cfg -
View Generated Config:
docker compose exec haproxy cat /etc/haproxy/haproxy.cfg -
Debugging:
# Enable debug mode docker compose up # Watch logs in real-time -
SSL Certificate Management:
# Generate self-signed cert openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout host.key -out host.crt \ -subj "/CN=host1.local" # Combine into PEM cat host.crt host.key > host1.local.pem
Troubleshooting
Backend Unreachable
Error: 503 Service Unavailable
Causes:
- Backend container not running
- Wrong container name in config
- Wrong port number
- Network connectivity issues
Debug:
# Check backend container is running
docker ps | grep container_name
# Test backend directly
curl http://container_name:port
# Check HAProxy logs
docker compose logs haproxy
Configuration Not Reloading
Solution:
# Restart HAProxy
docker compose restart haproxy
# Check file is mounted correctly
docker compose exec haproxy cat /etc/haproxy/static/config.yml
SSL Certificate Not Found
Error: Certificate errors in logs
Solution:
# Verify certificate is mounted
docker compose exec haproxy ls -la /certs/haproxy/
# Check certificate format (must be PEM with cert + key)
openssl x509 -in host.pem -text -noout
openssl rsa -in host.pem -check
Migration from Dynamic to Static
If you have Docker labels and want to convert to static config:
Docker label:
labels:
easyhaproxy.http.host: api.example.com
easyhaproxy.http.port: 80
easyhaproxy.http.localport: 8080
easyhaproxy.http.redirect_ssl: true
Static config equivalent:
easymapping:
- port: 80
redirect:
api.example.com: https://api.example.com
- port: 443
ssl: true
hosts:
api.example.com:
containers:
- container_name:8080