In Part 1 of this guide I outlined the relatively simple process of compiling HAProxy and installing it on Ubuntu 18.
Understanding HAProxy and Basic Configuration
When you install HAProxy from source you will need to supply your own configuration file. Thankfully several examples are provided to get you started, and I recommend starting with the simplest one called ‘transparent proxy’. Obviously you’ll need to change the bind and server addresses in the file to match your requirements.
It’s important to note that HAProxy routes requests to hosts using what are effectively conditional statements. You first define an Access Control List (ACL) and then set a parameter to match this ACL, such as an HTTP Host Header or incoming port. You can then specify one or more backends based on the ACLs you have defined, and traffic will be forwarded to that backend as appropriate. Backends themselves can have multiple servers defined, and different load balancing algorithms can be applied per backend definition.
My Configuration for HTTP/HTTPS over NAT
First let me explain my original use case and then I’ll show you a configuration close to what I ended up with. What I needed was a way to route requests on ports 80 and 443 to different servers on my network, and as I mentioned earlier HAProxy accommodates this with Access Control Lists (ACLs) and conditional statements. This is a look at what was my first working configuration:
global
daemon
maxconn 256
tune.ssl.default-dh-param 2048
defaults
timeout connect 300ms
timeout client 1000ms
timeout server 1000ms
mode http
frontend traffic_in
log global
bind *:80
bind *:443 ssl crt /path/to/certs/ no-sslv3
acl server1_in hdr(host) -i server1.kevincottrell.net
acl server2_in hdr(host) -i server2.kevincottrell.net
use_backend server1_backend if server1_in
use_backend server2_backend if server2_in
backend server1_backend
server server1 192.168.1.101:80 check
backend server2_backend
server server2 192.168.1.103:80 check
redirect scheme https code 301 if !{ ssl_fc }
There’s a lot going on in this file so let me explain the basic ideas in this configuration:
-
For some reason HAProxy still defaults to 1024 bit Diffie-Hellman… so we raise this to 2048 with
tune.ssl.default-dh-param 2048
-
This server will bind all interfaces and listen on both ports 80 and 443 (HTTP and HTTPS) with sslv3 disabled. You may want to specify the interface in yours.
-
It will read the host header (
hdr(host)
) of incoming packets and set an ACL flag ofserver1_in
orserver2_in
depending on what it finds. -
The
use_backend
statements will route packets to the appropriate backend server based on the ACL. -
Traffic going to
server2
will be redirected to https if the connection is not already secured. This is dictated by theredirect scheme
statement.
If you need to do something more elaborate there is extensive documentation available but I encourage you to keep it simple and only change one or two things at a time until you are feeling comfortable with the syntax.
SSL Termination
As you might have noticed in my example above, HAProxy can provide encryption to a service that is using port 80 on your local network. This is known as SSL Termination and is a great way to manage a “secure entry” to your backend servers. Just point HAProxy at the directory containing all of your required certificates and keys on the line that binds port 443 as I did in the example above and it will choose the appropriate certificate and key based on the connection being made. Backends can be made to use SSL as well (meaning HAProxy will use encrypted communication with the backend) but it will result in slightly more overhead and likely won’t scale very well.
Checking your configuration file
HAProxy will not start if your configuration is invalid, but thankfully it does provide a means to check this. It’s as simple as haproxy -c -f filename.conf
- where filename.conf
is the file where you have stored your configuration. If there are no problems you’ll get a message Configuration file is valid
or an error message otherwise.
Run HAProxy with your configuration
After all that there’s not much more to do, just type:
sudo haproxy -f filename.conf
And haproxy will be off and running using the parameters you gave it in your file. You’ll need to manually start and stop the process unless you create a systemd service or some other means to start the process.
Add a systemd unit for HAProxy
Thankfully again the community comes through and provides a systemd unit file in the contrib directory of the source you downloaded earlier. You just need to modify it slightly by removing or commenting out the two EnvironmentFile
lines and replacing them with an Environment
value that includes a few key pieces of information for HAProxy, like this:
#EnvironmentFile=-/etc/default/haproxy
#EnvironmentFile=-/etc/sysconfig/haproxy
Environment="CONFIG=/path/to/your/config.conf" "PIDFILE=/run/haproxy.pid" "EXTRAOPTS=-S /run/haproxy-master.sock"
You could alternatively create an environment file with the same values we have on the Environment line, but that’s a matter of preference. Once those changes are made you can copy this file to /etc/systemd/system/haproxy-custom.service
and type in the following commands:
sudo systemctl daemon-reload
sudo systemctl enable haproxy-custom.service
sudo systemctl start haproxy-custom.service
The daemon-reload
command tells the system that you want it to reload the system service files, the enable
command sets the system to start your service on boot, and the start
command triggers this service on boot.
What was it all for?
So with that I hope you’ll be able to understand how useful HAProxy has been for me given the story I gave you in Part 1. This allows me to have a single point of ingress to my home network which can handle all of the SSL termination to the outside world and then route ports 80 and 443 to any internal IP I choose based on various ACLs I define. As far as port forwarding is concerned I just need to send all traffic on ports 80 and 443 to the HAProxy server and then I can manipulate everything from there with the HAProxy configuration file. It’s fantastic!
One thing that was critical to the success of this project was the use of LetsEncrypt and certbot. I highly recommend them and I will make another guide in the future explaining how HAProxy handles all of my certificate renewals using them.
I hope this was helpful or at least interesting to you, and if so check back soon as I’ll be documenting my other projects on a (hopefully) more regular basis.