Installing and Configuring Haproxy 2.2 on a Raspberry Pi with Debian 10 - Rootless Podman and Systemd usage

Installing and Configuring Haproxy 2.2 on a Raspberry Pi with Debian 10 - Rootless Podman and Systemd usage

Show table of contents

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.

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 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
Install Podman for Raspberry PI OS armhf (ex Raspbian)
# 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
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.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
Let’s start haproxy again
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.

This time it should work, let’s try it out
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 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.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

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 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. 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=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.

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.

Subscribe to my newsletter

NOTE:You will need to confirm your e-mail address in order to fully complete the subscription process.

The comments section is closed.

You might enjoy these similar articles: