I had had enough of running Nginx as mostly a reverse proxy for all of my websites.
HAProxy seemed like the next step in powering my public facing websites, with Lighttpd as a backend for static websites.
Why and how?
To sum it up: Because I have so many different backends. I have the standard PHP7 requirements, some static websites and lots of applications that have their own webserver built-in.
Nginx can do all of that fine, but it lacks some advanced TLS features that I want.
Mainly, I want to deny non-SNI requests, because I don’t need that much backwards compatibility, and I don’t want to have anything responding without SNI.
I decided to build HAProxy from source to get the newest features, like OpenSSL 1.1.1, which supports TLS1.3.
I also wanted to port my config from Nginx to HAProxy. This blog post will not be detailing this progress though.
Now if you’re never built anything from source, this can seem like a frightening thing to do. And if you have, you know that there’s nothing to fear.
Whichever camp you’re in, at least the commands below may prove helpfull if you want to quickly build the newest stable version of HAProxy.
sudo apt install build-essential libpcre2-dev zlib1g-dev git wget
Now I’m giving you the commands that use links that are currently up to date, but if you’re reading this later on you’ll need to replace the version numbers with newer ones.
git clone git://git.openssl.org/openssl.git
git branch -a
# Use the latest stable branch from all branches
git checkout OpenSSL_1_1_1-stable
# Rpath is needed for haproxy.
./config -Wl,-rpath=/opt/openssl-1.1.1/lib --prefix=/opt/openssl-1.1.1 --openssldir=/opt/openssl-1.1.1 shared no-ssl3
git clone https://git.haproxy.org/git/haproxy.git
# change v2.0.0 to the latest stable version from git tag.
git checkout v2.0.0
# Read the INSTALL file for what the `make` command parameters do and tailor them to your own needs. Below is what I used.
# Use CPU=native if you're not in a virtualized enviroment. Systemd requires `sudo apt-get install libsystemd-dev`
make TARGET=linux_glibc CPU=generic USE_PCRE2_JIT=1 USE_PCRE2_JIT=1 USE_OPENSSL=1 SSL_LIB=/opt/openssl-1.1.1/lib SSL_INC=/opt/openssl-1.1.1/include USE_ZLIB=1 USE_LIBCRYPT=1 USE_LINUX_TPROXY=1 USE_LINUX_SPLICE=1 USE_SYSTEMD=1 USE_CRYPT_H=1
If ou cannot call
haproxy --help yet, then use the following enviroment variable
LD_LIBRARY_PATH=/opt/openssl-1.1.1/lib/ haproxy --help .
# LD_LIBRARY_PATH might not be needed if it works straight away for you.
Environment="LD_LIBRARY_PATH=/opt/openssl-1.1.1/lib/" "CONFIG=/etc/haproxy" "PIDFILE=/var/run/haproxy.pid"
ExecStartPre=/usr/local/sbin/haproxy -f $CONFIG -c -q
ExecStart=/usr/local/sbin/haproxy -Ws -f $CONFIG -p $PIDFILE
ExecReload=/usr/local/sbin/haproxy -f $CONFIG -c -q
ExecReload=/bin/kill -USR2 $MAINPID
Then to just write the HAProxy config… Easier said that done for me, since I knew pretty much nothing about how HAProxy does things.
I spent hours trying to get it to work the way I wanted: Ignore requests without SNI, and serve multiple domains and multiple subdomains flexibly.
Below is what I finally have as of writing this:
# Now in /etc/haproxy/conf/anyfilename
ssl-default-bind-options no-sslv3 no-tls-tickets
timeout http-request 5s
timeout connect 5s
timeout client 15s
timeout server 30s
redirect scheme https code 301
bind *:443 ssl strict-sni crt /etc/haproxy/certs/
# It matches if the HTTP Host: field mentions any of the hostnames (after the '-i')
acl use_lighttpd hdr(host) -i blog.ljoonal.xyz tos.ljoonal.xyz
use_backend lighttpd if use_lighttpd
errorfile 503 /var/www/html/index.html
server lighttpd localhost:8080
It’s probably not good at all, but hey, it works! I excluded setting up lighttpd, or any other service to work as the backend, because that’s not really relevant to lighttpd.
PS, here’s a protip: run
haproxy -c -V -f /etc/haproxy/conf/ to see if your configuration works before restarting or reloading it!