Skip to content
Back to skills

Haproxy

ASecurity

Expert coverage of HAProxy across all versions: frontend/backend architecture, ACL-based routing, stick tables for rate limiting and session tracking, health checks, SSL offload, L4/L7 modes, runtime API for dynamic configuration, multi-threading, and Kubernetes Ingress Controller. Use for \"HAProxy\", \"haproxy.cfg\", \"frontend\", \"backend\", \"stick table\", \"ACL\", \"HAProxy runtime API\", \"HAProxy Ingress\". Do NOT use for cross-vendor comparison, platform selection, or category-wide ...

  • 4 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
devopsgobashsqlkubernetesapidatabasefrontendbackendperformance

Works with

  • cli
  • api

Security analysis

A100/100

Pro scans all 6 files and shows the line behind each finding

Scanned September 24, 2026

npx -y skills add chrishuffman5/domain-expert --skill haproxy --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Haproxy?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Haproxy
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/chrishuffman5-haproxy/badge)](https://www.skillsdirectory.com/skills/chrishuffman5-haproxy)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: haproxy
description: "Expert coverage of HAProxy across all versions: frontend/backend architecture, ACL-based routing, stick tables for rate limiting and session tracking, health checks, SSL offload, L4/L7 modes, runtime API for dynamic configuration, multi-threading, and Kubernetes Ingress Controller. Use for \"HAProxy\", \"haproxy.cfg\", \"frontend\", \"backend\", \"stick table\", \"ACL\", \"HAProxy runtime API\", \"HAProxy Ingress\". Do NOT use for cross-vendor comparison, platform selection, or category-wide architecture -- use the `load-balancing` skill."
license: MIT
---

# HAProxy

This skill covers HAProxy across all supported versions (2.8 LTS through 3.2 LTS and 3.3 current). Areas of expertise include:

- Frontend/backend/listen architecture with global and defaults sections
- ACL (Access Control List) system for complex routing and filtering
- Stick tables for stateful rate limiting, session tracking, and abuse detection
- Health checks (TCP, HTTP, external script-based)
- SSL/TLS offload and cipher management
- L4 (TCP mode) and L7 (HTTP mode) proxying
- Runtime API for dynamic configuration without reload
- Multi-threaded architecture (nbthread)
- Zero-downtime reloads (listener socket passing)
- Kubernetes Ingress Controller
- Logging architecture (async, no file I/O in data path)

When a question is version-specific, consult the matching `references/versions/` file. When the version is unknown, provide general guidance and note where behavior differs across versions.

## How to Approach Tasks

1. **Classify** the request:
   - **Troubleshooting** -- Check stats page, runtime API, logs, health check status
   - **Configuration** -- Load `references/best-practices.md` for SSL, health checks, rate limiting, tuning
   - **Architecture** -- Load `references/architecture.md` for frontend/backend model, ACLs, stick tables, runtime API
   - **Rate limiting** -- Apply stick table patterns below
   - **Kubernetes** -- Apply Ingress Controller guidance below

2. **Identify version** -- Determine HAProxy version (2.x or 3.x). If unclear, ask. Version matters for stick table features (3.0 sharding, 3.2 arrays), multi-threading behavior, and LTS status.

3. **Load context** -- Read the relevant reference file for deep knowledge.

4. **Analyze** -- Apply HAProxy-specific reasoning, not generic load balancer advice.

5. **Recommend** -- Provide actionable configuration snippets with explanations.

6. **Verify** -- Suggest validation steps (stats page, runtime API commands, log analysis).

## Core Architecture

### Process Model
- Single-process, multi-threaded (since 2.x)
- `nbthread` directive scales across CPU cores
- Event-driven: uses epoll (Linux) / kqueue (BSD) for non-blocking I/O
- No file I/O in data path: all logging is async (syslog UDP/TCP)
- Zero-downtime reload: new process inherits listener sockets from old process

### Configuration Structure
```
global          # Process-level: threading, SSL, logging, resource limits
defaults        # Default settings inherited by all frontends/backends
frontend        # Listener: accepts client connections
backend         # Server pool: forwards traffic to servers
listen          # Combined frontend + backend (shorthand)
```

### Frontend
Defines how HAProxy accepts incoming connections:
```haproxy
frontend http_front
    bind *:80
    bind *:443 ssl crt /etc/ssl/example.pem alpn h2,http/1.1
    
    http-request redirect scheme https unless { ssl_fc }
    
    # ACL-based routing
    acl is_api path_beg /api/
    use_backend api_backend if is_api
    default_backend web_backend
```

### Backend
Defines the server pool and load balancing behavior:
```haproxy
backend web_backend
    balance leastconn
    option httpchk GET /health HTTP/1.1\r\nHost:\ app.internal
    http-check expect status 200
    
    server web1 192.168.10.11:8080 check weight 10
    server web2 192.168.10.12:8080 check weight 10
    server web3 192.168.10.13:8080 check weight 5 backup
```

### Listen
Combined frontend+backend for simple deployments:
```haproxy
listen stats
    bind *:8404
    stats enable
    stats uri /stats
    stats refresh 10s
    stats auth admin:password
```

## ACL System

ACLs are named conditions used for routing, blocking, and traffic control:
```haproxy
frontend http_front
    # Define ACLs
    acl is_api          path_beg /api/
    acl is_admin        path_beg /admin/
    acl is_mobile       hdr_sub(User-Agent) -i Mobile
    acl internal_src    src 10.0.0.0/8 192.168.0.0/16
    acl has_auth        req.hdr(Authorization) -m found
    acl is_post         method POST
    acl is_large_body   req.body_len gt 1048576
    
    # Route based on ACLs
    use_backend api_backend     if is_api
    use_backend admin_backend   if is_admin internal_src
    http-request deny           if is_admin !internal_src
    use_backend upload_backend  if is_post is_large_body
    default_backend web_backend
```

**ACL matching methods**:
- `path_beg`, `path_end`, `path_reg`: URL path matching
- `hdr()`, `hdr_beg()`, `hdr_sub()`, `hdr_reg()`: Header matching
- `src`: Source IP matching
- `ssl_fc`: SSL/TLS connection (boolean)
- `method`: HTTP method matching
- `-m found`: Check if header/value exists
- `-i`: Case-insensitive matching

## Stick Tables

Stick tables are in-memory data stores for stateful tracking and rate limiting.

### Rate Limiting with Stick Tables
```haproxy
frontend http_front
    # Define stick table: track per-IP request rate
    stick-table type ip size 100k expire 30s store http_req_rate(10s)
    
    # Track client IP
    http-request track-sc0 src
    
    # Deny if more than 100 requests in 10 seconds
    http-request deny deny_status 429 if { sc_http_req_rate(0) gt 100 }
```

### Session Tracking
```haproxy
backend app_backend
    stick-table type ip size 100k expire 10m store conn_cur,http_req_rate(1m),http_err_rate(1m)
    
    stick on src          # persist client IP to same server
    
    server app1 192.168.10.11:8080 check
    server app2 192.168.10.12:8080 check
```

### Stick Table Data Types
- `conn_cur`: Current concurrent connections
- `conn_rate(period)`: Connection rate
- `http_req_rate(period)`: HTTP request rate
- `http_err_rate(period)`: HTTP error rate (4xx/5xx)
- `gpc0`, `gpc1`: General Purpose Counters
- `gpt0`: General Purpose Tag
- `bytes_in_rate`, `bytes_out_rate`: Bandwidth tracking

## Health Checks

### HTTP Health Check
```haproxy
backend app_backend
    option httpchk GET /health HTTP/1.1\r\nHost:\ app.internal
    http-check expect status 200
    http-check expect string "healthy"
    
    server app1 192.168.10.11:8080 check inter 2s rise 2 fall 3
```

**Parameters**:
- `inter`: Check interval (default 2s)
- `rise`: Consecutive successes to mark UP (default 2)
- `fall`: Consecutive failures to mark DOWN (default 3)
- `fastinter`: Interval during transition (faster detection)
- `downinter`: Interval when server is down (slower to reduce load)

### TCP Health Check
```haproxy
backend db_backend
    mode tcp
    option tcp-check
    
    server db1 192.168.10.20:5432 check inter 5s
```

### External Script Health Check
```haproxy
backend custom_backend
    option external-check
    external-check command /usr/local/bin/check_app.sh
    
    server app1 192.168.10.11:8080 check inter 10s
```

## SSL/TLS Offload

```haproxy
global
    ssl-default-bind-ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
    ssl-default-bind-ciphersuites TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384
    ssl-default-bind-options ssl-min-ver TLSv1.2
    tune.ssl.default-dh-param 2048

frontend https_front
    bind *:443 ssl crt /etc/ssl/certs/bundle.pem alpn h2,http/1.1
    
    # Forward proto and client cert info
    http-request set-header X-Forwarded-Proto https
    http-request set-header X-SSL-Client-CN %{+Q}[ssl_c_s_dn(cn)]
    
    default_backend app_backend
```

### SNI-Based Routing
```haproxy
frontend https_front
    bind *:443 ssl crt /etc/ssl/certs/ strict-sni
    
    # Route based on SNI (TLS hostname)
    use_backend api_backend if { ssl_fc_sni api.example.com }
    use_backend web_backend if { ssl_fc_sni www.example.com }
    default_backend default_web
```

## L4 (TCP) vs L7 (HTTP) Mode

### TCP Mode (L4)
```haproxy
frontend db_front
    mode tcp
    bind *:5432
    default_backend db_backend

backend db_backend
    mode tcp
    balance roundrobin
    option tcp-check
    server db1 192.168.10.20:5432 check
    server db2 192.168.10.21:5432 check
```

Use for: databases (PostgreSQL, MySQL, Redis), SMTP, custom TCP protocols, any non-HTTP traffic.

### HTTP Mode (L7)
```haproxy
frontend web_front
    mode http
    bind *:80
    default_backend web_backend

backend web_backend
    mode http
    balance leastconn
    option httpchk
    server web1 192.168.10.11:8080 check
```

Use for: web applications, APIs, any HTTP/HTTPS traffic requiring content-based decisions.

## Runtime API

The Runtime API allows dynamic reconfiguration without reload:

### Enable Runtime API
```haproxy
global
    stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
    stats timeout 30s
```

### Common Runtime Commands
```bash
# System information
echo "show info" | socat stdio /run/haproxy/admin.sock

# Show all server/backend statistics
echo "show stat" | socat stdio /run/haproxy/admin.sock

# Disable server (drain connections)
echo "disable server app_backend/app1" | socat stdio /run/haproxy/admin.sock

# Enable server
echo "enable server app_backend/app1" | socat stdio /run/haproxy/admin.sock

# Set server weight dynamically
echo "set weight app_backend/app1 50" | socat stdio /run/haproxy/admin.sock

# Show stick table contents
echo "show table STICK_TABLE_NAME" | socat stdio /run/haproxy/admin.sock

# Clear stick table
echo "clear table STICK_TABLE_NAME" | socat stdio /run/haproxy/admin.sock

# Show backend state
echo "show backend" | socat stdio /run/haproxy/admin.sock

# Show errors
echo "show errors" | socat stdio /run/haproxy/admin.sock
```

## Load Balancing Algorithms

| Algorithm | Directive | Description |
|---|---|---|
| Round Robin | `balance roundrobin` | Sequential distribution with weights |
| Static Round Robin | `balance static-rr` | No dynamic weight changes; faster |
| Least Connections | `balance leastconn` | Fewest active connections |
| Source | `balance source` | Client IP hash (session affinity) |
| URI | `balance uri` | Hash of URI (cache optimization) |
| Header | `balance hdr(name)` | Hash of HTTP header value |
| Random | `balance random` | Random; `random(2)` for P2C |
| First | `balance first` | Fill first server before moving to next |
| rdp-cookie | `balance rdp-cookie(name)` | RDP session persistence |

## Kubernetes Ingress Controller

HAProxy Technologies provides an official Kubernetes Ingress Controller:

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    haproxy.org/load-balance: "leastconn"
    haproxy.org/timeout-connect: "5s"
    haproxy.org/rate-limit-requests: "100"
    haproxy.org/rate-limit-period: "1m"
spec:
  rules:
  - host: app.example.com
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: app-service
            port:
              number: 80
```

Features:
- Standard Ingress resources with HAProxy-specific annotations
- Native stick table support for session persistence
- Dynamic reconfiguration via ConfigMap + CRD
- Load balancing algorithms: roundrobin, leastconn, source, uri, hdr

## Common Pitfalls

1. **Mode mismatch** -- Setting `mode tcp` on a frontend but `mode http` on the backend (or vice versa) causes silent failures. Always match modes between frontend and backend.

2. **Forgetting `check` on server lines** -- Without the `check` keyword, no health checking is performed for that server. Always add `check` to enable health monitoring.

3. **Stick table memory sizing** -- `stick-table type ip size 100k` allocates space for 100,000 entries. If the table fills up, new entries are rejected. Size based on expected unique client count.

4. **ACL evaluation order** -- `use_backend` rules are evaluated top-down. If a broad ACL is listed before a specific one, the specific rule never matches. Order from most specific to least specific.

5. **Runtime API changes not persistent** -- Changes made via the runtime API (disable server, set weight) are lost on reload. For permanent changes, update haproxy.cfg.

6. **SSL certificate ordering in bundle** -- HAProxy requires the certificate bundle in order: server cert, intermediate(s), root. Incorrect ordering causes validation failures.

7. **Not using `option httplog`** -- Without `option httplog`, HAProxy uses `tcplog` format which lacks HTTP-specific fields (URL, status code, response time). Always enable `option httplog` for HTTP mode.

8. **Zero-downtime reload failure** -- `expose-fd listeners` must be set on the stats socket for seamless listener socket transfer during reload. Without it, reload causes brief connection drops.

## Version-Specific Guidance

| Version | Reference | What's version-specific |
|---|---|---|
| 3.2 | `references/versions/3.2.md` | HAProxy 3.2 LTS, stick table peer sync thread, array data types, enhanced show events |

## Reference Files

Load these when you need deep knowledge:

- `references/architecture.md` -- Frontend/backend model, ACL system, stick table internals, runtime API mechanics, multi-threading. Read for "how does X work" questions.
- `references/best-practices.md` -- SSL offload patterns, health check design, rate limiting strategies, K8s integration, performance tuning. Read for design and configuration questions.

## Diagnostic Scripts

Ready-made stats-socket and config-check scripts (read-only) in `scripts/`.

- `scripts/01-runtime-stats.sh` -- Down servers with check reasons, queueing, error rates
- `scripts/02-config-check.sh` -- Config validation gate before reload (and the reload-vs-restart rule)

Files in this skill

  • SKILL.md13.7 KB
  • references/architecture.md10.2 KB
  • references/best-practices.md11.5 KB
  • references/versions/3.2.md8.1 KB
  • scripts/01-runtime-stats.sh1.5 KB
  • scripts/02-config-check.sh1.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…