HAProxy

haproxy(1) is a TCP load balancing and reverse proxy server.


Installation

Most Linux and BSD distributions offer a haproxy package.

Containers

A Docker container image is available for most releases. These are available from DockerHub as docker.io/library/haproxy (or simply haproxy when using docker(1) specifically).

The image runs as the non-root user haproxy, so it cannot bind to a privileged port. There are workarounds, but the upstream recommendation is to properly configure bridge networks and DNS and then to configure haproxy(1) to resolve names at runtime.


Configuration

BSD distributions will look for configuration files in /usr/local/etc.

Basic Configuration

A minimal configuration file looks like:

global
  user haproxy
  group haproxy
  daemon

backend www_backend
  server www1 127.0.0.1:80

frontend http_in
  bind *:80
  mode http
  default_backend www_backend

A backend instructs haproxy(1) where traffic for a particular service should be routed to. Multiple servers can be defined in a backend and an algorithm for load balancing (i.e. roundrobin, leastconn, etc.) can be specified.

A frontend instructs haproxy(1) to listen on an address and/or port. In the above, http_in binds to any name on port 80 and handles HTTP traffic. A frontend also provides logic for routing traffic to the correct backend.

Encryption

See here for details.

Authentication

See here for details.

Web Sockets

When a connection is upgraded to the websocket protocol, haproxy(1) implicitly drops to tunnel mode. Generally no other configuration is necessary.

If you are redirecting HTTP traffic to HTTPS in the frontend, you will need to make that redirect further conditional on not being a websocket connection.

acl is_websocket hdr(Upgrade) -i WebSocket
http-request redirect scheme https if !{ ssl_fc } !is_websocket

Conditional Routing

HTTP headers can be inspected to logically route traffic using access control lists (ACLs). Consider the below frontend:

frontend http_frontend
  bind *:80
  bind *:443 ssl crt /path/to/the/pem/certificate alpn h2, http1.1
  mode http

  default_backend www_backend

  #route ACME challenge from Let's Encrypt to the certbot temporary server
  acl acme path_beg /.well-known/acme-challenge
  use_backend letsencrypt_backend if acme

  #route API requests
  acl api hdr(host) -i api.example.com

  #for webgit, split CGI requests from file requests
  acl webgit hdr(host) -i git.example.com
  acl cdn path_beg /js
  acl cdn path_beg /css
  use_backend www_backend if webgit ! cdn
  use_backend cdn_backend if cdn

This demonstrates:

Name Resolution

haproxy(1) can be configured to resolve server addresses at runtime.

First, configure a resolvers:

resolvers docker_dns
  nameserver docker1 127.0.0.11:53

Second, configure servers to defer name resolution and provide instructions on how to resolve names.

backend www_backend
  server www1 nginx:80 check resolvers docker_dns

Third, configure haproxy(1) to run regardless of name resolution errors. (The default behavior is to exit if any servers are unreachable.)

defaults
  default-server init-addr none

Stick Tables

See here for details.


See also

HAProxy project documentation


CategoryRicottone

HAProxy (last edited 2023-10-24 19:42:44 by DominicRicottone)