# Ansible Role: HAProxy Install and configure HAProxy load balancer with flexible frontends, backends, and stats. ## Variables ### Global Settings | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `haproxy_global.log` | No | List with `/dev/log local2` | Log target (string or list) | | `haproxy_global.stats_socket` | No | See defaults | Stats socket configuration | | `haproxy_global.stats_timeout` | No | Empty | Stats timeout (optional, e.g., "30s") | | `haproxy_global.chroot` | No | `/var/lib/haproxy` | Chroot directory | | `haproxy_global.user` | No | `haproxy` | User to run as | | `haproxy_global.group` | No | `haproxy` | Group to run as | | `haproxy_global.daemon` | No | `true` | Run as daemon | | `haproxy_global.pidfile` | No | `/var/run/haproxy.pid` | PID file location (optional) | | `haproxy_global.maxconn` | No | `35000` | Maximum connections (optional) | ### Default Settings | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `haproxy_defaults.log` | No | `global` | Log setting | | `haproxy_defaults.mode` | No | `tcp` | Default mode (tcp/http) | | `haproxy_defaults.options` | No | List with `tcplog` | Options list (or use `option` for single) | | `haproxy_defaults.timeout_check` | No | `5s` | Health check timeout (optional) | | `haproxy_defaults.timeout_connect` | No | `10s` | Connection timeout | | `haproxy_defaults.timeout_client` | No | `600s` | Client timeout | | `haproxy_defaults.timeout_server` | No | `600s` | Server timeout | | `haproxy_defaults.timeout_tunnel` | No | Empty | Tunnel timeout (optional) | ### Stats Listener | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `haproxy_stats.enabled` | No | `false` | Enable stats interface | | `haproxy_stats.bind` | No | `192.168.32.10:9000` | Bind address for stats | | `haproxy_stats.mode` | No | `http` | Stats mode | | `haproxy_stats.uri` | No | `/` | Stats URI path | | `haproxy_stats.show_node` | No | `true` | Show node name | | `haproxy_stats.refresh` | No | `10s` | Refresh interval | | `haproxy_stats.auth` | No | `admin:password` | Basic auth credentials | ### Frontends | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `haproxy_frontends` | No | `[]` | List of frontends | | `haproxy_frontends[].name` | Yes | - | Frontend name | | `haproxy_frontends[].bind` | Yes | - | Bind address and port | | `haproxy_frontends[].default_backend` | Yes | - | Default backend name | | `haproxy_frontends[].mode` | No | - | Override default mode | | `haproxy_frontends[].options` | No | `[]` | Additional options | ### Backends | Variable | Required | Default | Description | |----------|----------|---------|-------------| | `haproxy_backends` | No | `[]` | List of backends | | `haproxy_backends[].name` | Yes | - | Backend name | | `haproxy_backends[].balance` | No | - | Load balancing algorithm | | `haproxy_backends[].hash_type` | No | - | Hash type for balancing | | `haproxy_backends[].mode` | No | - | Override default mode | | `haproxy_backends[].stick_table` | No | - | Stick table configuration | | `haproxy_backends[].acls` | No | `[]` | List of ACL rules | | `haproxy_backends[].tcp_request` | No | `[]` | TCP request rules | | `haproxy_backends[].tcp_response` | No | `[]` | TCP response rules | | `haproxy_backends[].stick` | No | `[]` | Stick rules | | `haproxy_backends[].options` | No | `[]` | Additional options | | `haproxy_backends[].http_check` | No | `[]` | HTTP health check directives | | `haproxy_backends[].tcp_check` | No | `[]` | TCP health check directives | | `haproxy_backends[].servers` | Yes | - | List of backend servers | | `haproxy_backends[].servers[].name` | Yes | - | Server name | | `haproxy_backends[].servers[].address` | Yes | - | Server address:port | | `haproxy_backends[].servers[].check` | No | `false` | Enable health checks | | `haproxy_backends[].servers[].check_port` | No | - | Health check port (if different) | | `haproxy_backends[].servers[].send_proxy` | No | `false` | Enable send-proxy | | `haproxy_backends[].servers[].extra_params` | No | - | Additional server parameters | ## Examples ### Teleport Example Configuration for Teleport with SSL session persistence and advanced health checks: ```yaml --- - name: "Deploy HAProxy for Teleport" hosts: "haproxy_servers" become: true vars: # global settings with multiple log targets haproxy_global: log: - "/dev/log local0" - "/dev/log local1 notice" stats_socket: "/var/lib/haproxy/stats level admin" chroot: "/var/lib/haproxy" user: "haproxy" group: "haproxy" daemon: true # defaults with multiple options haproxy_defaults: log: "global" mode: "tcp" options: - "httplog" - "dontlognull" timeout_connect: "5000" timeout_client: "10m" timeout_server: "10m" timeout_tunnel: "10m" # frontends haproxy_frontends: - name: "hafrontend" bind: "*:443" mode: "tcp" default_backend: "teleport" # backends with http-check and tcp-check haproxy_backends: - name: "teleport" mode: "tcp" balance: "roundrobin" stick_table: "type binary len 2048 size 300k expire 30m" acls: - "clienthello req.ssl_hello_type 1" - "serverhello res.ssl_hello_type 2" tcp_request: - "inspect-delay 10s" - "content accept if clienthello" tcp_response: - "content accept if serverhello" stick: - "on req.payload_lv(43,1) if clienthello" - "store-response res.payload_lv(43,1) if serverhello" options: - "option httpchk GET /healthz" - "option tcp-check" http_check: - "expect status 200" tcp_check: - "connect" servers: # teleport node 1 - name: "teleport-prod-01" address: "192.168.10.120:443" check: true check_port: "3000" send_proxy: true extra_params: "check-ssl verify none" # teleport node 2 - name: "teleport-prod-02" address: "192.168.10.121:443" check: true check_port: "3000" send_proxy: true extra_params: "check-ssl verify none" roles: - "role-haproxy" ``` ### K3s Cluster Example Configuration for K3s cluster with IP-based session persistence: ```yaml --- - name: "Deploy HAProxy for K3s Cluster" hosts: "haproxy_servers" become: true vars: # global settings haproxy_global: log: - "/dev/log local0" - "/dev/log local1 notice" chroot: "/var/lib/haproxy" stats_socket: "/run/haproxy-admin.sock mode 660 level admin" stats_timeout: "30s" user: "haproxy" group: "haproxy" daemon: true # defaults settings haproxy_defaults: log: "global" mode: "tcp" options: - "tcplog" - "dontlognull" timeout_connect: "5000" timeout_client: "50000" timeout_server: "50000" # frontends haproxy_frontends: - name: "fe-k3s-http" bind: "192.168.10.17:80" default_backend: "be-k3s-http" - name: "fe-k3s-https" bind: "192.168.10.17:443" default_backend: "be-k3s-https" - name: "fe-k3s-api" bind: "192.168.10.17:6443" default_backend: "be-k3s-nodes" # backends with IP-based sticky sessions haproxy_backends: - name: "be-k3s-http" balance: "roundrobin" stick_table: "type ip size 200k expire 30m" stick: - "on src" options: - "option tcp-check" servers: - name: "k3s-node01" address: "192.168.10.21:80" check: true - name: "k3s-node02" address: "192.168.10.22:80" check: true - name: "k3s-node03" address: "192.168.10.23:80" check: true - name: "be-k3s-https" balance: "roundrobin" stick_table: "type ip size 200k expire 30m" stick: - "on src" options: - "option tcp-check" servers: - name: "k3s-node01" address: "192.168.10.21:443" check: true - name: "k3s-node02" address: "192.168.10.22:443" check: true - name: "k3s-node03" address: "192.168.10.23:443" check: true - name: "be-k3s-nodes" balance: "roundrobin" options: - "option tcp-check" servers: - name: "k3s-node01" address: "192.168.10.21:6443" check: true - name: "k3s-node02" address: "192.168.10.22:6443" check: true - name: "k3s-node03" address: "192.168.10.23:6443" check: true roles: - "role-haproxy" ``` ### WAF Example with SSL Persistence ```yaml --- - name: "Deploy HAProxy Load Balancer" hosts: "haproxy_servers" become: true vars: # enable stats interface haproxy_stats: enabled: true bind: "192.168.32.10:9000" mode: "http" uri: "/" show_node: true refresh: "10s" auth: "admin:password" # frontends haproxy_frontends: # http frontend - name: "http-in" bind: "192.168.32.15:80" default_backend: "waf_siempie_tools_http" # https frontend - name: "https-in" bind: "192.168.32.15:443" default_backend: "waf_siempie_tools_https" # backends haproxy_backends: # http backend with simple load balancing - name: "waf_siempie_tools_http" balance: "source" hash_type: "consistent" options: - "option httpchk GET /health" servers: # waf0.siempie.tools - name: "waf0.siempie.tools" address: "192.168.32.20:80" check: true send_proxy: true # waf1.siempie.tools - name: "waf1.siempie.tools" address: "192.168.32.21:80" check: true send_proxy: true # https backend with SSL session persistence - name: "waf_siempie_tools_https" balance: "roundrobin" stick_table: "type binary len 2048 size 300k expire 30m" acls: - "clienthello req.ssl_hello_type 1" - "serverhello res.ssl_hello_type 2" tcp_request: - "inspect-delay 10s" - "content accept if clienthello" tcp_response: - "content accept if serverhello" stick: - "on req.payload_lv(43,1) if clienthello" - "store-response res.payload_lv(43,1) if serverhello" options: - "option httpchk GET /health" servers: # waf0.siempie.tools - name: "waf0.siempie.tools" address: "192.168.32.20:443" send_proxy: true check: true extra_params: "check-ssl verify none" # waf0.siempie.tools - name: "waf1.siempie.tools" address: "192.168.32.21:443" send_proxy: true check: true extra_params: "check-ssl verify none" roles: - "role-haproxy" ```