Haproxy is the leading high availability proxy system for TCP and HTTP load balancing. Using it on a raspberry pi makes sense. The only problem is that the version on Debian 10 Buster is 1.8.19 which is pretty old. Knowing that we have cool new features in 2.2 (and 2.3).
We’ll explore some of the alternatives on how to install a working version of Haproxy 2.2 on Debian 10 AND which options you have when you’re on an ARM system like a Raspberry Pi. [1]
This article’s main focus is on how to run any container (haproxy is our prime application) in a rootless environment using podman and having systemd managing our pod/container. As a bonus, we will be fixing the errors we might encounter along the way for our raspberry pi setup.
Table of Contents
Up to date packages from https://haproxy.debian.net/
If you’re just running Debian 10 on a VPS which is based on a x86 system then you can use haproxy.debian.net All you need to do is run the following commands
You need to enable a the dedicated repository for the haproxy packages:
curl https://haproxy.debian.net/bernat.debian.org.gpg | \\ apt-key add - echo deb http://haproxy.debian.net buster-backports-2.2 main | \\ tee /etc/apt/sources.list.d/haproxy.list
Then, use the following commands to install haproxy:
apt-get update apt-get install haproxy=2.2.\\*
The downside is that you can’t really use it on an ARM system since there are no prebuilt packages. This means we need to go out and seek another solution.
Using a linux namespace with podman or a docker container
I’d rather have haproxy run on bare linux, however, using it in a linux namespace or as a docker container is a good alternative when no package is available.
I’ll asume using podman, since the commands map to the docker commands. The added benefits of using podman is that you can use it under non root users as we’ll see in the examples to follow.
Podman Installation
Install Podman under Debian 10 (x86 systems)
# Debian 10echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.listcurl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/Release.key | sudo apt-key add -sudo apt-get updatesudo apt-get -y install podman
Install Podman for Raspberry PI OS armhf (ex Raspbian)
# Raspbian 10echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/ /' | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.listcurl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/Release.key | sudo apt-key add -sudo apt-get update -qqsudo apt-get -qq -y install podman
Get haproxy:2.2 container
podman pull haproxy:2.2
Make sure you have your haproxy configuration in ~/config/haproxy/haproxy.cfg Afterwards, run and create the podman container. I presume you’re under a normal non root user without using sudo. Yes, podman works on rootless environments and is perfect for allowing non root users to run containers.
mkdir ~/config/haproxy# Copy your configuration to ~/config/haproxy/haproxy.cfgpodman run -d --name haproxy -p 80:80 -p 443:443 -v /home/activitycosmos/config/haproxy:/usr/local/etc/haproxy:ro haproxy:2.2Error: /usr/bin/slirp4netns failed: "/usr/bin/slirp4netns: unrecognized option '--netns-type=path'\\nUsage: /usr/bin/slirp4netns [OPTION]... PID TAPNAME\\nUser-mode networking for unprivileged network namespaces.\\n\\n-c, --configure bring up the interface\\n-e, --exit-fd=FD specify the FD for terminating slirp4netns\\n-r, --ready-fd=FD specify the FD to write to when the network is configured\\n-m, --mtu=MTU specify MTU (default=1500, max=65521)\\n-6, --enable-ipv6 enable IPv6 (experimental)\\n-h, --help show this help and exit\\n-v, --version show version and exit\\n"
Fixing slirp4netns issue
It will fail on a Raspberry PI due to the fact that slirp4netns is old.. so we’ll need to manually compile the newest version.
We could also get the latest binary release version and simply use that.
curl -o slirp4netns --fail -L https://github.com/rootless-containers/slirp4netns/releases/download/v1.1.6/slirp4netns-$(uname -m)sudo cp slirp4netns /usr/bin/slirp4netnschmod +x slirp4netns
Let’s start haproxy again
podman start haproxyError: unable to start container "68304e7838c64a24248f8f58ce7be7e2a0ea333db09b222dcb12a181a03430af": failed to expose ports via rootlessport: "cannot expose privileged port 80, you might need to add \\"net.ipv4.ip_unprivileged_port_start=0\\" (currently 443) to /etc/sysctl.conf, or choose a larger port number (>= 443): listen tcp 0.0.0.0:80: bind: permission denied\\n"
And it will fail due to the fact that you can’t run anything on ports
under 1024 as non root. The solution is to allow the 80+ ports to be
used by non root. This is an example I use on my development machine all
the time, in production i’d advise you run haproxy as a rootfull
container, I’ll show you how later.
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
You can make it permament by editing /etc/sysctl.conf and pasting that there. NOTE: This is NOT as secure at it seems as ALL users will be able to run anything on those ports. An alternative would be to use setcap for an executable.
This time it should work, let’s try it out
podman start haproxyhaproxy
Test it locally, if your configuration is not yet setup or you don’t have any backends it will take some time/
wget localhost--2020-11-23 10:33:26-- http://localhost/Resolving localhost (localhost)... ::1, 127.0.0.1Connecting to localhost (localhost)|::1|:80... connected.HTTP request sent, awaiting response... 503 Service Unavailable2020-11-23 10:33:46 ERROR 503: Service Unavailable.
The 503 error is normal, I haven’t set up any default backend server. If you setup a default backend server you should get a HTTP code of 200.
Using systemd to run podman pods
We’ll now use systemd to run user controlled pods. NOTE: For haproxy it might be a better choice to run it system wide, however we’ll use it as an example of how you can run anything from a non root user.
Generate the folder structure for where we’ll be storing the service
files mkdir -p ~/.config/systemd/user
.
Podman comes with built in kubectl and systemd generators. Let’s use them to generate our new systemd service.
podman generate systemd --new --name haproxy > ~/.config/systemd/user/haproxy.servicecat ~/.config/systemd/user/haproxy.service# container-haproxy.service# autogenerated by Podman 2.1.1# Mon Nov 23 10:44:23 GMT 2020[Unit]Description=Podman container-haproxy.serviceDocumentation=man:podman-generate-systemd(1)Wants=network.targetAfter=network-online.target[Service]Environment=PODMAN_SYSTEMD_UNIT=%nRestart=on-failureExecStartPre=/bin/rm -f %t/container-haproxy.pid %t/container-haproxy.ctr-idExecStart=/usr/bin/podman run --conmon-pidfile %t/container-haproxy.pid --cidfile %t/container-haproxy.ctr-id --cgroups=no-conmon --replace -d --name haproxy -p 80:80 -p 443:443 -v /home/activitycosmos/config/haproxy:/usr/local/etc/haproxy:ro haproxy:2.2ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-haproxy.ctr-id -t 10ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-haproxy.ctr-idPIDFile=%t/container-haproxy.pidKillMode=noneType=forking[Install]WantedBy=multi-user.target default.target
It’s extremely easy to get up and running by using podman and systemd without anyother external software.
To make systemd recognize our changes we need to reload it’s settings
systemctl --user daemon-reload
All commands like start,stop, status, reload need to be run with the
systemctl --user status workser-service
command.
Let’s stop the podman haproxy version and start it via systemctl. Plus let’s enable it when the user logs in.
podman stop haproxysystemctl --user start haproxysystemctl --user enable haproxy
However, that won’t start any user apps on boot/ ONly when the user logs
in. There is a solution to enable lingering or starting user services at
boot. All you have to do is run this command
loginctl enable-linger user
Reboot the system and see the wonders of systemd.
Podman + systemd can allow you to do a variety of cool things without overcomplicating things. You can create new users and just run the services under those users
Reloading
We still need to allow reloads. As we’ll probably want to reload our haproxy.cfg without restarting everything. Add this to the [Service] ExecReload=/usr/bin/podman kill -s HUP haproxy
systemctl --user disable haproxysystemctl --user enable haproxy
Everything Together for a Rootfull Podman
Rootless containers are awesome, however it’s advised to actually run haproxy as a system service instead. This allows you to make usage bridged adapters for networking.
sudo mkdir -p /etc/haproxypodman run -d --name haproxy -p 80:80 -p 443:443 -v /etc/haproxy:/usr/local/etc/haproxy:ro haproxy:2.2podman generate systemd --new --name haproxy --filessudo cp container-haproxy.service /etc/systemd/system/haproxy.servicesudo systemctl enable haproxy.servicepodman stop haproxysudo systemctl start haproxy
Now your haproxy service should be system wide Plus, you should now have
a few virtual interfaces which you can use to communicate between your
pods. ip addr
Using nix package manager
Another nice alternative is using the nix package manager. Which has some benefits of being able to allow non root users to install their own software.
There is some setup to be done and you can follow the nix manual should you want to take this route.
I haven’t tested it on ARM, yet might give it a try in the future.
Compiling Haproxy from scratch
This option should be used as a last resort since it complicates everything, especially on a raspberry pi.
Compiling requires us to download and install all of the build essentials and development libraries which use precious memory. If you’re
`sudo apt-get install build-essential libssl-dev libpcre++-dev`
You’ll also need to download it yourself
`wget https://www.haproxy.org/download/2.2/src/haproxy-2.2.5.tar.gz`
I’m not going to details all configuration and installation steps, you can find them on the website itself and experiment as per your needs. Why? BEcause you’ll need to configure a variety of C variables which depend on your needs
Such as:
make TARGET=custom CPU=native USE_PCRE=1 USE_LIBCRYPT=1 USE_LINUX_SPLICE=1 USE_LINUX_TPROXY=1make install
Haproxy is the solution
Depending on your needs, your installation method might differ. However, if you need reverse proxy, high availability and plain old load balancing then Haproxy is the best solution. The first choice is to be preferred whenever running on a X86 vps. The container one is also great whenever you just need a version of haproxy or any software to run under any underlying system.
Take care!
Leave me a message on the contact page if you found this usefull:).
Join my Newsletter as I’m working on a specific DevOps course for Developers in which I’ll showcase many more awesome things you can do with free software.
Cover Photo by Benjamin Voros on Unsplash>
1. Debian 11 will have haproxy 2.2 and is due to be released somewhere in 2021.