HAProxy
Install
sudo apt update
sudo apt install -y haproxy
sudo systemctl enable --now haproxy
Ubuntu packages include a systemd unit.
Basic reverse proxy (HTTP only first)
Edit /etc/haproxy/haproxy.cfg
:
global
log /dev/log local0
log /dev/log local1 notice
maxconn 4096
daemon
defaults
mode http
log global
option httplog
option forwardfor
timeout connect 5s
timeout client 30s
timeout server 30s
frontend http-in
bind :80
# ACME HTTP-01 challenge goes to certbot (see HTTPS section)
acl acme_http path_beg /.well-known/acme-challenge/
use_backend acme if acme_http
default_backend app
backend app
server app1 127.0.0.1:3000 check
mode http
lets HAProxy parse/modify HTTP and add X-Forwarded-For
.
Reload:
sudo haproxy -c -f /etc/haproxy/haproxy.cfg
sudo systemctl reload haproxy
HTTPS with Let’s Encrypt (no downtime approach)
Run Certbot in standalone mode on an alternate port and route only ACME paths to it:
- Start/renew certificates via Certbot on port 8888:
sudo snap install --classic certbot
sudo certbot certonly --standalone --preferred-challenges http \
--http-01-port 8888 -d example.com
- Add an ACME backend to HAProxy:
backend acme
server certbot 127.0.0.1:8888
- Concatenate cert + key for HAProxy:
sudo mkdir -p /etc/haproxy/certs
sudo bash -c 'cat /etc/letsencrypt/live/example.com/fullchain.pem \
/etc/letsencrypt/live/example.com/privkey.pem \
> /etc/haproxy/certs/example.com.pem'
sudo chmod 600 /etc/haproxy/certs/example.com.pem
- Add HTTPS frontend and redirect HTTP→HTTPS:
frontend https-in
bind :443 ssl crt /etc/haproxy/certs/example.com.pem
default_backend app
# Optional: redirect all plain HTTP to HTTPS when not ACME
frontend http-in
bind :80
acl acme_http path_beg /.well-known/acme-challenge/
use_backend acme if acme_http
http-request redirect scheme https code 301 if !acme_http
default_backend app
Renewals: schedule certbot renew
(snap sets systemd timers) and re-concat the PEM via a deploy hook:
sudo bash -c 'printf "%s\n" "#!/bin/sh" \
"cat /etc/letsencrypt/live/example.com/fullchain.pem /etc/letsencrypt/live/example.com/privkey.pem > /etc/haproxy/certs/example.com.pem" \
"systemctl reload haproxy" > /etc/letsencrypt/renewal-hooks/deploy/haproxy.sh'
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/haprory.sh
Notes
- HAProxy config/manual references for HTTP mode & examples: docs.haproxy.org
- Let’s Encrypt challenge types context (HTTP-01): Let's Encrypt
- HAProxy + ACME approaches (overview with
acme.sh
option): blog post.