HAProxy is available on the Raspbian platform! HAProxy is a high availability, load balancing, and proxying server application. It sits between the Internet and your webservers. HAProxy sends the traffic to each of your servers, round-robin style. Since I’m serving this website on a couple of Raspberries, I thought HAProxy would be a welcome solution to my Raspberry environment.
This, a WordPress website, has a couple of parts. Traffic comes in from the Internet through my fiber modem/firewall. The router port forwards port 80 traffic (web) to my proxy server on port 8000. The proxy server is running HAProxy, which listens on port 8000, and sends the traffic to the proper set of servers, based on the URL that is being requested. Better Done Yourself gets a little more traffic than How to Raspberry so there are 3 Raspberries set up to serve Better Done Yourself. Currently, How to Raspberry only gets two. This describes the “front end”.
The “back-end” is not directly reachable from the Internet. WordPress is a CMS, or “Content Management System”. A CMS relies on a database to store the content of the pages, posts, and comments. The CMS draws the content from the database, formats it into HTML, and hands it off to the web server for perusal by the person browsing the site.
Installing haproxy is simple! Just run “sudo apt install haproxy” and it will install the software and any necessary dependencies.
So, now let’s take a look at how HAProxy is configured to be the mediator of web-traffic destined for my web-serving Raspberries. HAProxy also operates on the front-end/back-end principle. From HAProxy’s point of view, the “front-end” is incoming traffic. The “back-end” is the webservers that are going to answer the web requests.
Now, let’s tackle configuring HAProxy. First, we define the frontend and name it www. (By the way, HAProxy is more than capable of serving up more than just web traffic!) For this frontend, we’re going to listen on port 8000 for incoming requests. If it sees a request, it checks a lookup table for the name of the web server to send the page request to:
frontend www bind *:8000 use_backend %[req.hdr(host),lower,map_dom(/etc/haproxy/domain2backend.map,bk_default)]
Here’s a look at that table. Pretty simple. Just a list on my domains and the backend that serves them. (In this case, we’re talking about the servers that backend HAProxy, not the database that backends WordPress.)
root@proxy:/etc/haproxy# cat domain2backend.map #domain-name backend-name betterdoneyourself.com betterdy macdowalls.com stone howtoraspberry.com howto
So, HAProxy has three potential domains for which to route traffic. Each has its own backend. Note that I have chosen a “round-robin” load balancing strategy. This means that HAProxy will attempt to use each server one after the other in order. The first request goes to webs1, the second request to webs2, third request to webs3, fourth request to webs1, fifth request to webs2, and so on.
Also note that I have set up each of the 5 raspberry pi web servers, and added their full IP addresses (including port 80, where all the servers are listening for connections). “stone” is the odd man out. stone is actually an x86_64 LINUX server so it’s not load balanced.
backend stone mode http server stone 10.0.0.6:80 check backend betterdy mode http balance roundrobin server webs1 10.0.0.204:80 check server webs2 10.0.0.205:80 check server webs3 10.0.0.206:80 check backend howto mode http balance roundrobin server wordp1 10.0.0.207:80 check server wordp2 10.0.0.208:80 check
Finally, the statistics page. I’ve bound THAT to port 80 so I don’t have to browse to a nonstandard port to check on my HAProxy server with my web browser. Here’s the config snippet for that
listen stats bind :80 mode http stats enable stats uri / stats hide-version
Here’s a shot of my current stats page:
Finally, here’s the entirety of my running config, for your convenience:
global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon defaults log global mode http option tcplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http frontend www bind *:8000 use_backend %[req.hdr(host),lower,map_dom(/etc/haproxy/domain2backend.map,bk_default)] backend stone mode http server stone 10.0.0.6:80 check backend betterdy mode http balance roundrobin server webs1 10.0.0.204:80 check server webs2 10.0.0.205:80 check server webs3 10.0.0.206:80 check backend howto mode http balance roundrobin server wordp1 10.0.0.207:80 check server wordp2 10.0.0.208:80 check listen stats bind :80 mode http stats enable stats uri / stats hide-version
I haven’t gone over every bit of the config. I’ll leave that as homework. I will however give you some troubleshooting tips:
Check your configuration with:
haproxy -c -f /etc/haproxy/haproxy.cfg
Then try to start it manually with:
haproxy -db -f /etc/haproxy/haproxy.cfg
Here’s the parts list: https://www.howtoraspberry.com/index.php/2020/04/24/parts-to-build-the-raspberry-webserver/
Here’s a good book about HAProxy, for further study!
Was thinking about using a pi as a HAProxy and came across your post. Have you considered the idea of using another pi as a memcached server for your setup to improve performance? Not that your site speed is all that bad (I ran a test – forgive me lol) but there’s places I see that you could make improvements.
Interesting. Nice article on configuring haproxy however, the article is titled “How to Install HAProxy on a Raspberry” yet there isn’t a single mention of how to install haproxy on a pi.
Oops! Sorry. I added the follow paragraph:
Installing haproxy is simple! Just run “sudo apt install haproxy” and it will install the software and any necessary dependencies.