1
0
Fork 0
docker-easy-haproxy/examples/static
Joao Gilberto Magalhaes d3637e737a Refactor plugin configuration examples and improve formatting in documentation
- Replaced `config.yml` with modular configuration examples: `config-basic.yml`, `config-certbot.yml`, `config-deny-pages.yml`, and `config-jwt-validator.yml`.
- Improved examples with detailed usage instructions, prerequisites, and testing steps for each configuration.
- Fixed indentation and formatting inconsistencies across plugin files and HAProxy configuration generation.
- Streamlined README comparison table for static vs. dynamic discovery.
- Updated `docker-compose-jwt-validator.yml` to correct audience key formatting.
2025-11-27 19:49:32 -05:00
..
conf Refactor plugin configuration examples and improve formatting in documentation 2025-11-27 19:49:32 -05:00
docker-compose.yml [skip ci] Update from 4.5.0 to 4.6.0 2025-08-24 23:14:07 +00:00
host1.local.pem Upgrade HAProxy to 2.4.2; Added examples 2021-08-10 15:17:00 -05:00
README.md Refactor plugin configuration examples and improve formatting in documentation 2025-11-27 19:49:32 -05:00

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 routing
  • docker-compose.yml - EasyHAProxy container mounting the config file
  • host1.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 name
  • ip_address:port - Direct IP address
  • hostname: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>.pem inside container
  • ./certs/<domain>.pem on 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 connections
  • source - 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

  1. Reloading Configuration:

    # EasyHAProxy watches config.yml for changes
    # Edit conf/config.yml, changes auto-reload
    
    # Or manually restart:
    docker compose restart haproxy
    
  2. Validate Configuration:

    # Check HAProxy config is valid
    docker compose exec haproxy haproxy -c -f /etc/haproxy/haproxy.cfg
    
  3. View Generated Config:

    docker compose exec haproxy cat /etc/haproxy/haproxy.cfg
    
  4. Debugging:

    # Enable debug mode
    docker compose up
    # Watch logs in real-time
    
  5. 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

Further Reading