INSTALL
sudo apt-get update
sudo apt-get install haproxy python3 curl socat openssl
haproxy -vv
python3 --version
curl --version

PREP
mkdir -p "$HOME/avg-haproxy-lab/backend-a" "$HOME/avg-haproxy-lab/backend-b"
printf 'backend-a\n' > "$HOME/avg-haproxy-lab/backend-a/index.html"
printf 'backend-b\n' > "$HOME/avg-haproxy-lab/backend-b/index.html"
printf 'ok\n' > "$HOME/avg-haproxy-lab/backend-a/healthz"
printf 'ok\n' > "$HOME/avg-haproxy-lab/backend-b/healthz"

A
python3 -m http.server 18081 --bind 127.0.0.1 --directory "$HOME/avg-haproxy-lab/backend-a"

B
python3 -m http.server 18082 --bind 127.0.0.1 --directory "$HOME/avg-haproxy-lab/backend-b"

DIRECT
curl --noproxy '*' --max-time 3 http://127.0.0.1:18081/
curl --noproxy '*' --max-time 3 http://127.0.0.1:18082/
curl --noproxy '*' --max-time 3 --include http://127.0.0.1:18081/healthz

CONFIG
cat > "$HOME/avg-haproxy-lab/haproxy.cfg" <<'HAPROXY'
global
    log stdout format raw local0
    maxconn 100
    stats socket ./lab.sock mode 600 level admin

defaults
    mode http
    log global
    option httplog
    timeout connect 2s
    timeout client 15s
    timeout server 15s
    timeout http-request 5s
    timeout queue 3s

frontend lab_http
    bind 127.0.0.1:18080
    acl blocked_path path_beg -i /admin
    http-request deny deny_status 403 if blocked_path
    http-request set-header X-Forwarded-For %[src]
    http-request set-header X-Forwarded-Proto http
    default_backend app_pool

backend app_pool
    balance roundrobin
    option httpchk
    http-check send meth GET uri /healthz ver HTTP/1.1 hdr Host lab.local
    http-check expect status 200
    default-server inter 2s fall 3 rise 2
    server app_a 127.0.0.1:18081 check
    server app_b 127.0.0.1:18082 check

frontend lab_stats
    bind 127.0.0.1:18404
    stats enable
    stats uri /stats
    stats refresh 5s
HAPROXY

VALIDATE
cd "$HOME/avg-haproxy-lab"
haproxy -c -f haproxy.cfg

START
cd "$HOME/avg-haproxy-lab"
haproxy -db -f haproxy.cfg

REQUESTS
for request_no in $(seq 1 10); do
    curl --noproxy '*' --silent --show-error --max-time 3 http://127.0.0.1:18080/
done

STATS
curl --noproxy '*' --max-time 3 --output /dev/null --write-out 'HTTP %{http_code}\n' http://127.0.0.1:18404/stats

DRAIN
cd "$HOME/avg-haproxy-lab"
printf 'set server app_pool/app_a state drain\n' | socat - UNIX-CONNECT:./lab.sock
printf 'show stat\n' | socat - UNIX-CONNECT:./lab.sock

READY
cd "$HOME/avg-haproxy-lab"
printf 'set server app_pool/app_a state ready\n' | socat - UNIX-CONNECT:./lab.sock

ACL
curl --noproxy '*' --max-time 3 --include http://127.0.0.1:18080/admin

CERT
cd "$HOME/avg-haproxy-lab"
umask 077
openssl req -x509 -newkey rsa:2048 -sha256 -nodes -days 7 -keyout lab-key.pem -out lab-cert.pem -subj "/CN=lab.example.test" -addext "subjectAltName=DNS:lab.example.test"
cat lab-cert.pem lab-key.pem > lab.pem
chmod 600 lab-key.pem lab.pem

TLS_CONFIG
cd "$HOME/avg-haproxy-lab"
cp haproxy.cfg haproxy-tls.cfg
cat >> haproxy-tls.cfg <<'HAPROXY_TLS'

frontend lab_https
    bind 127.0.0.1:18443 ssl crt ./lab.pem
    acl blocked_path path_beg -i /admin
    http-request deny deny_status 403 if blocked_path
    http-request set-header X-Forwarded-For %[src]
    http-request set-header X-Forwarded-Proto https
    default_backend app_pool
HAPROXY_TLS

TLS_VALIDATE
cd "$HOME/avg-haproxy-lab"
haproxy -c -f haproxy-tls.cfg

TLS_CURL
cd "$HOME/avg-haproxy-lab"
curl --noproxy '*' --resolve lab.example.test:18443:127.0.0.1 --cacert lab-cert.pem --max-time 5 https://lab.example.test:18443/