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.
Building
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.
1
| 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.
1
2
3
4
5
6
7
8
9
10
11
12
| su
cd /usr/local/src/
git clone git://git.openssl.org/openssl.git
cd openssl
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
make
make test
make install
|
1
2
3
4
5
6
7
8
9
10
11
| su
cd /usr/local/src/
git clone https://git.haproxy.org/git/haproxy.git
cd haproxy
git tag
# 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
make install
|
If ou cannot call haproxy --help
yet, then use the following enviroment variable LD_LIBRARY_PATH=/opt/openssl-1.1.1/lib/ haproxy --help
.
Configuration
Systemd service:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # /etc/systemd/system/haproxy.service
[Unit]
Description=HAProxy
After=network.target
[Service]
# 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
KillMode=mixed
Restart=always
Type=notify
[Install]
WantedBy=multi-user.target
|
1
2
3
4
| mkdir /etc/haproxy
mkdir /etc/haproxy/conf
mkdir /etc/haproxy/certs
vim /etc/haproxy/conf/default.cfg
|
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:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
| # Now in /etc/haproxy/conf/anyfilename
global
maxconn 4096
tune.ssl.default-dh-param 2048
ssl-dh-param-file /etc/haproxy/dhparams.pem
ssl-default-bind-options no-sslv3 no-tls-tickets
ssl-default-bind-ciphers DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-AES256-SHA:ECDHE-RSA-AES256-SHA
#debug
defaults
mode http
timeout http-request 5s
timeout connect 5s
timeout client 15s
timeout server 30s
option http-server-close
frontend http-redirect
bind *:80
redirect scheme https code 301
frontend https-in
bind *:443 ssl strict-sni crt /etc/haproxy/certs/
option forwardfor
# 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
backend lighttpd
option forwardfor
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!