Skip to content

Container - HAProxy

HAProxy (High Availability Proxy) is a powerful open-source reverse proxy and load balancer commonly used to improve server reliability and performance. Running HAProxy as a Container on RouterOS provides a secure gateway for directing HTTP/HTTPS traffic to backend services while hiding them from direct external access.

HAProxy supports multiple scheduling algorithms, health checks, SSL termination, and can handle thousands of concurrent connections with minimal resource usage. When combined with RouterOS Containers, it creates a flexible infrastructure for hosting web applications, APIs, and other network services.

HAProxy distributes incoming traffic across multiple backend servers, preventing any single server from becoming overwhelmed. This is essential when running multiple instances of a service for high availability or when different services require different backend configurations.

By terminating SSL/TLS at HAProxy, backend Containers only need to handle unencrypted HTTP traffic. This simplifies certificate management, reduces CPU load on backend services, and centralizes security configuration.

HAProxy can route requests to different backend pools based on URL paths, host headers, or other request attributes. This enables hosting multiple applications on the same IP address with different subdomains or path prefixes.

HAProxy includes built-in rate limiting, connection limits, and IP reputation features that protect backend services from abuse, DDoS attacks, and excessive request rates.

Before deploying HAProxy, ensure you have a Container network configured. HAProxy Containers require network connectivity to receive incoming traffic and connect to backend services.

/interface/veth/print
Flags: X - disabled, A - active, * - default
# NAME MTU ADDRESS GATEWAY
0 veth1 1500 172.17.0.1/24 172.17.0.1

If you need to create a new Container network, refer to the Container networking documentation for detailed instructions.

HAProxy and its configuration require storage space on your RouterOS device. Ensure sufficient disk space is available for:

  • Container image (approximately 50-100MB)
  • Configuration files and certificates
  • Logs (if logging is enabled)

Create a mount point to store the HAProxy configuration file persistently. This allows you to edit the configuration without rebuilding the Container.

/container/mounts/add name=haproxy_etc src=disk1/haproxy-etc dst=/usr/local/etc/haproxy

The mount point maps a directory on your RouterOS storage to the Container’s configuration directory.

Add the HAProxy Container using the official HAProxy image. Specify the interface for network connectivity and the mount point for configuration.

/container/add remote-image=haproxy:latest interface=veth1 root-dir=disk1/haproxy mounts=haproxy_etc user=0:0 name=haproxy

This command:

  • Downloads the latest HAProxy image from Docker Hub
  • Connects the Container to the specified virtual interface
  • Sets the root directory for Container data
  • Mounts the configuration directory
  • Runs the Container as root with specific UID/GID

Connect to your RouterOS device using SFTP (or WinSCP on Windows) and create the configuration file at disk1/haproxy-etc/haproxy.cfg.

global
log stdout format raw local0 info
stats socket :9999 level admin expose-fd listeners
defaults
mode http
timeout client 10s
timeout connect 10s
timeout server 10s
timeout http-request 10s
frontend http_synapse
bind *:80
use_backend synapse
backend synapse
server server1 172.17.0.2:8008 maxconn 32

This basic configuration:

  • Enables logging to stdout for Container logs
  • Exposes the runtime statistics socket on port 9999
  • Listens on port 80 for HTTP traffic
  • Routes requests to a backend server at 172.17.0.2:8008
/container start [find where name=haproxy]

Verify the Container is running:

/container/print
Flags: X - disabled, R - running
0 R name="haproxy" id="abc123..." interface=veth1 ...

Check the logs for startup messages:

/log print follow

You should see HAProxy initialization messages indicating successful startup.

The [global](#global-section) section configures process-wide settings:

PropertyDescription
logConfigures logging destination and format
stats socketEnables the runtime statistics socket for dynamic configuration
nbthreadNumber of worker threads (match to CPU cores)
tune.bufsizeBuffer size (adjust for large headers)
tune.ssl.cachesizeSSL session cache size

The [defaults](#defaults-section) section sets default values for all subsequent frontend and backend sections:

defaults
mode http
timeout client 10s
timeout connect 10s
timeout server 10s
timeout http-request 10s
PropertyDescription
modeConnection mode: http for layer 7, tcp for layer 4
timeout clientMaximum inactivity time for client connections
timeout connectMaximum time to wait for a backend connection
timeout serverMaximum inactivity time for backend connections
timeout http-requestMaximum time to receive a complete HTTP request

The [frontend](#frontend-section) section defines how HAProxy accepts incoming connections:

frontend frontend_webapp
mode http
option httplog
bind *:80
bind *:443 ssl crt /usr/local/etc/haproxy/certs/
http-request redirect scheme https unless { ssl_fc }
use_backend backend_webapp
PropertyDescription
bindSocket binding specification (address:port)
ssl crtSSL certificate path for HTTPS
http-requestManipulate incoming HTTP requests
use_backendDirect traffic to specified backend

The [backend](#backend-section) section defines backend servers and load balancing:

backend backend_webapp
mode http
balance roundrobin
option http-server-close
option forwardfor
server server1 172.17.0.2:8080
PropertyDescription
balanceLoad balancing algorithm: roundrobin, leastconn, source
option http-server-closeClose connections to backend after response
option forwardforAdd X-Forwarded-For header with client IP
serverBackend server definition with address and options

This section describes how to configure HAProxy with HTTPS support using Certbot for automatic certificate management with RFC2136 DNS validation.

Step 1: Create Container with Advanced Configuration

Section titled “Step 1: Create Container with Advanced Configuration”
/container/mounts/add name=MOUNT_HAPROXY src=disk1/volumes/haproxy/config dst=/usr/local/etc/haproxy
/container/add remote-image=haproxy:latest interface=veth1 root-dir=disk1/images/haproxy mounts=MOUNT_HAPROXY name=haproxy start-on-boot=yes user=0:0 logging=yes

Key additions:

  • start-on-boot=yes ensures HAProxy starts automatically after reboot
  • logging=yes enables Container logging to RouterOS logs
  • Separate configuration directory for easier management

Step 2: Create HAProxy Configuration with SSL

Section titled “Step 2: Create HAProxy Configuration with SSL”

Create haproxy.cfg on your local system and upload to disk1/volumes/haproxy/config/:

global
log stdout format raw local0 info
stats socket :9999 level admin expose-fd listeners
ssl-default-bind-ciphers EECDH+AESGCM:EDH+AESGCM
ssl-default-server-ciphers EECDH+AESGCM:EDH+AESGCM
ssl-default-bind-options ssl-min-ver TLSv1.2
ssl-default-server-options ssl-min-ver TLSv1.2
tune.ssl.default-dh-param 2048
tune.bufsize 43768
tune.ssl.cachesize 1000000
nbthread 8
defaults
log global
timeout client 10s
timeout connect 10s
timeout server 10s
timeout http-request 10s
frontend frontend_webapp
mode http
option httplog
option http-server-close
option forwardfor except 127.0.0.0/8
stick-table type ipv6 size 100k expire 30s store http_req_rate(10s)
http-request track-sc0 src
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 10000 }
bind *:80
bind *:443 ssl crt /usr/local/etc/haproxy/certs/
http-request redirect scheme https unless { ssl_fc }
http-request set-header X-Forwarded-Host %[req.hdr(host)]
http-request set-header X-Forwarded-For %[src]
use_backend backend_webapp
backend backend_webapp
mode http
balance roundrobin
option http-server-close
option forwardfor
server server1 172.17.0.2:8080

This configuration includes:

  • Strong SSL cipher configuration
  • Rate limiting (10000 requests per 10 seconds per IP)
  • HTTP to HTTPS redirection
  • X-Forwarded headers for backend server logging
  • High-performance SSL settings with large caches

Create the Certbot Container for Let’s Encrypt certificate management:

/container/mounts/add name=MOUNT_CERTBOT_CONFIG src=disk1/volumes/certbot/config dst=/etc/letsencrypt
/container/mounts/add name=MOUNT_CERTBOT_DATA src=disk1/volumes/certbot/data dst=/var/lib/letsencrypt
/container/mounts/add name=MOUNT_CERTBOT_LOG src=disk1/volumes/certbot/log dst=/var/log/letsencrypt
/container/mounts/add name=MOUNT_CERTBOT_HAPROXY src=disk1/volumes/haproxy/config dst=/etc/haproxy
/container/add remote-image=certbot/dns-rfc2136 cmd="certonly -n --agree-tos --dns-rfc2136 --dns-rfc2136-credentials /etc/letsencrypt/rfc2136.ini -m admin@<FQDN> --deploy-hook 'cat /etc/letsencrypt/live/<FQDN>/fullchain.pem /etc/letsencrypt/live/<FQDN>/privkey.pem | tee /etc/haproxy/certs/<FQDN>.pem > /dev/null; echo -e \"set ssl cert /usr/local/etc/haproxy/certs/<FQDN>.pem <<\n$(cat /etc/haproxy/certs/<FQDN>.pem)\n\n\" | nc 127.0.0.1:9999; echo \"commit ssl cert /usr/local/etc/haproxy/certs/<FQDN>.pem\" | nc 127.0.0.1:9999' -d <FQDN> --cert-name <FQDN>" interface=veth1 logging=yes mounts=MOUNT_CERTBOT_CONFIG,MOUNT_CERTBOT_DATA,MOUNT_CERTBOT_LOG,MOUNT_CERTBOT_HAPROXY name=certbot root-dir=disk1/images/certbot start-on-boot=yes workdir=/opt/certbot

Replace all <FQDN> placeholders with your fully qualified domain name before running this command.

This configuration:

  • Uses Certbot with RFC2136 DNS validation (for networks where HTTP validation is not possible)
  • Automatically copies new certificates to HAProxy via the statistics socket
  • Reloads HAProxy certificates without restart
  • Runs with start-on-boot for automatic certificate renewal
/container start [find where name=certbot]

Monitor the logs for certificate generation:

/log print follow

Look for messages indicating successful certificate issuance. The certificate will be automatically deployed to HAProxy.

/container start [find where name=haproxy]

Create a scheduler to run certificate renewal automatically:

/system scheduler
add interval=1d name=SCHEDULE_RenewCertbot on-event=SCRIPT_RenewCertbot policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon start-date=2025-03-10 start-time=06:30:00
/system script
add dont-require-permissions=no name=SCRIPT_RenewCertbot owner=admin policy=ftp,reboot,read,write,policy,test,password,sniff,sensitive,romon source="/container/start [find where name=\"certbot\"]"

This schedule runs daily at 6:30 AM to check for and obtain new certificates if needed.

HAProxy includes powerful features for protecting backend services from abuse:

frontend frontend_webapp
stick-table type ipv6 size 100k expire 30s store http_req_rate(10s)
http-request track-sc0 src
http-request deny deny_status 429 if { sc_http_req_rate(0) gt 10000 }

This configuration:

  • Tracks request rates per source IP
  • Allows 10,000 requests per 10-second window
  • Returns HTTP 429 (Too Many Requests) when limit exceeded

HAProxy can integrate with IP reputation services or maintain local blacklists:

frontend frontend_webapp
http-request deny if { src,netmask(24) -f /etc/haproxy/blacklist.txt }
defaults
timeout http-request 10s
timeout client 10s
timeout server 10s

Short timeouts prevent slowloris-style attacks that hold connections open indefinitely.

  1. Verify sufficient storage space: /system/resource/print
  2. Check interface exists: /interface/veth/print
  3. Review mount point paths exist on storage
  4. Check logs for specific errors: /log print
/container/print detail
  1. Verify backend server is running: /container/print
  2. Check backend IP and port are correct in configuration
  3. Test connectivity from RouterOS: /tool ping 172.17.0.2
  4. Verify no firewall rules block traffic
/ip/firewall/filter/print
/interface/veth/print detail
  1. Verify certificate file exists: /file print
  2. Check certificate format is PEM with both certificate and private key
  3. Ensure certificate is not expired
  4. Verify HAProxy has read access to certificate files
  1. Check HAProxy statistics: Connect to the statistics socket
  2. Review connection limits and backend server capacity
  3. Monitor system resources: /system resource/print
  4. Consider increasing thread count for multi-core systems
  1. Verify logging=yes was set on Container creation
  2. Check RouterOS log settings: /system/logging/print
  3. Ensure log topics are enabled