dhi.io/haproxy
The Reliable, High Performance TCP/HTTP Load Balancer
All examples in this guide use the public image. If you’ve mirrored the repository for your own use (for example, to your Docker Hub namespace), update your commands to reference the mirrored image instead of the public one.
For example:
dhi.io/<repository>:<tag><your-namespace>/dhi-<repository>:<tag>For the examples, you must first use docker login dhi.io to authenticate to the registry to pull the images.
Refer to the upstream's documentation on the subject of configuring HAProxy for your needs.
Run a basic HAProxy container and output the version with the following command. Replace with the image variant you want to run.
docker run dhi.io/haproxy:<tag> -v
Run a HAProxy container with a mounted configuration directory:
docker run -v /path/to/haproxy:/usr/local/etc/haproxy:ro dhi.io/haproxy:<tag> -f /usr/local/etc/haproxy
Using Docker Compose:
services:
haproxy:
image: dhi.io/haproxy:<tag>
volumes:
- ./haproxy:/usr/local/etc/haproxy:ro
ports:
- "8080:8080"
- "8443:8443"
command: ["-f", "/usr/local/etc/haproxy"]
Create a simple load balancer configuration in haproxy.cfg:
global
maxconn 256
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend http-in
bind *:8080
default_backend servers
backend servers
server server1 192.168.1.10:80 check
server server2 192.168.1.11:80 check
Mount and run with:
docker run -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro \
-p 8080:8080 dhi.io/haproxy:<tag> \
-f /usr/local/etc/haproxy
Configure SSL termination in haproxy.cfg:
global
maxconn 256
defaults
mode http
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend https-in
bind *:8443 ssl crt /usr/local/etc/haproxy/certs/server.pem
default_backend servers
backend servers
server server1 192.168.1.10:80 check
server server2 192.168.1.11:80 check
Mount certificates and configuration:
docker run -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro \
-v $(pwd)/certs:/usr/local/etc/haproxy/certs:ro \
-p 8443:8443 dhi.io/haproxy:<tag> \
-f /usr/local/etc/haproxy
Configure TCP mode for database load balancing:
global
maxconn 256
defaults
mode tcp
timeout connect 5000ms
timeout client 50000ms
timeout server 50000ms
frontend database-in
bind *:5432
default_backend db-servers
backend db-servers
balance roundrobin
server db1 192.168.1.20:5432 check
server db2 192.168.1.21:5432 check
Key differences for HAProxy:
| Feature | Docker Official HAProxy | Docker Hardened HAProxy |
|---|---|---|
| Security | Standard base with common utilities | Minimal, hardened base with security patches |
| Shell access | Full shell (bash/sh) available | No shell in runtime variants |
| Package manager | apt/apk available | No package manager in runtime variants |
| Attack surface | Larger due to additional utilities | Minimal, only essential components |
| Debugging | Traditional shell debugging | Use Docker Debug or Image Mount for troubleshooting |
Docker Hardened Images come in different variants depending on their intended use:
Runtime variants are designed to run HAProxy in production. These images:
Build-time variants typically include dev in the variant name and are intended for building custom HAProxy
configurations or plugins. These images:
FIPS variants include fips in the variant name and tag. They come in both runtime and build-time variants. These
variants use cryptographic modules that have been validated under FIPS 140, a U.S. government standard for secure
cryptographic operations. For example, usage of MD5 fails in FIPS variants.
When migrating from Docker Official Images to Docker Hardened Images for HAProxy, consider the following:
The nonroot user cannot bind to privileged ports (below 1024). Update your HAProxy configuration to use ports 1025 and above inside the container:
# Change from:
bind *:80
bind *:443
# To:
bind *:8080
bind *:8443
Use Docker's port mapping to expose these on privileged ports on the host:
docker run -p 80:8080 -p 443:8443 dhi.io/haproxy:<tag>
Ensure configuration files are readable by the nonroot user. Mount configurations with appropriate permissions:
chmod 644 haproxy.cfg
docker run -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro \
dhi.io/haproxy:<tag>
Verify the entry point behavior matches your expectations. Use docker inspect to check:
docker inspect dhi.io/haproxy:<tag>
If using the stats socket, ensure it's writable by the nonroot user. Consider using a mounted volume:
docker run -v haproxy-socket:/var/run/haproxy \
dhi.io/haproxy:<tag>
The hardened images intended for runtime don't contain a shell nor any tools for debugging. The recommended method for debugging applications built with Docker Hardened Images is to use Docker Debug to attach to these containers. Docker Debug provides a shell, common debugging tools, and lets you install other tools in an ephemeral, writable layer that only exists during the debugging session.
docker debug dhi.io/haproxy:<tag>
Symptom: HAProxy fails to start with a "permission denied" error when binding to ports below 1024.
Solution: Update your HAProxy configuration to use unprivileged ports (1025 and above) and use Docker port mapping to expose privileged ports on the host.
Symptom: HAProxy reports that it cannot read the configuration file.
Solution: Verify that:
Symptom: HAProxy cannot create or write to the stats socket.
Solution: Create a named volume or bind mount with appropriate permissions for the nonroot user to write the socket
file, typically in /var/run/haproxy.
Symptom: Unable to exec into the container because there's no shell.
Solution: Use Docker Debug to attach an ephemeral debugging session to the container with a shell and debugging tools.
To validate your HAProxy configuration before deploying, use a dev variant image:
docker run --rm -v $(pwd)/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro \
dhi.io/haproxy:<tag>-dev \
-c -f /usr/local/etc/haproxy/haproxy.cfg
For detailed HAProxy configuration and tuning guidance, refer to the official HAProxy documentation.