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. 
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.
- Up to date packages from https://haproxy.debian.net/
- Using a linux namespace with podman or a docker container
- Using nix package manager
- Compiling Haproxy from scratch
- Haproxy is the solution
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
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
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.
# Debian 10 echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/ /' > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Debian_10/Release.key | sudo apt-key add - sudo apt-get update sudo apt-get -y install podman
# Raspbian 10 echo 'deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/ /' | sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/Raspbian_10/Release.key | sudo apt-key add - sudo apt-get update -qq sudo apt-get -qq -y install podman
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.cfg podman run -d --name haproxy -p 80:80 -p 443:443 -v /home/activitycosmos/config/haproxy:/usr/local/etc/haproxy:ro haproxy:2.2 Error: /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/slirp4netns chmod +x slirp4netns
podman start haproxy Error: 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.
podman start haproxy haproxy
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.1 Connecting to localhost (localhost)|::1|:80... connected. HTTP request sent, awaiting response... 503 Service Unavailable 2020-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 generate systemd --new --name haproxy > ~/.config/systemd/user/haproxy.service cat ~/.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.service Documentation=man:podman-generate-systemd(1) Wants=network.target After=network-online.target [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=on-failure ExecStartPre=/bin/rm -f %t/container-haproxy.pid %t/container-haproxy.ctr-id ExecStart=/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.2 ExecStop=/usr/bin/podman stop --ignore --cidfile %t/container-haproxy.ctr-id -t 10 ExecStopPost=/usr/bin/podman rm --ignore -f --cidfile %t/container-haproxy.ctr-id PIDFile=%t/container-haproxy.pid KillMode=none Type=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 haproxy systemctl --user start haproxy systemctl --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
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 haproxy systemctl --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/haproxy podman run -d --name haproxy -p 80:80 -p 443:443 -v /etc/haproxy:/usr/local/etc/haproxy:ro haproxy:2.2 podman generate systemd --new --name haproxy --files sudo cp container-haproxy.service /etc/systemd/system/haproxy.service sudo systemctl enable haproxy.service podman stop haproxy sudo 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.
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
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
make TARGET=custom CPU=native USE_PCRE=1 USE_LIBCRYPT=1 USE_LINUX_SPLICE=1 USE_LINUX_TPROXY=1 make 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.
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.
Subscribe to my newsletter