Deploy the HAProxy charm

In this tutorial we’ll deploy the HAProxy charm to provide ingress to a backend application, then configure high-avalability using the hacluster relation. This tutorial is done on LXD and assumes that you have a Juju controller bootstrapped and a machine model to deploy charms.

Requirements

You will need a working station, e.g., a laptop, with AMD64 architecture. Your working station should have at least 4 CPU cores, 8 GB of RAM, and 50 GB of disk space.

Tip

You can use Multipass to create an isolated environment by running:

multipass launch 24.04 --name charm-tutorial-vm --cpus 4 --memory 8G --disk 50G

This tutorial requires the following software to be installed on your working station (either locally or in the Multipass VM):

  • Juju 3.3

  • LXD 5.21.4

Use Concierge to set up Juju and LXD:

sudo snap install --classic concierge
sudo concierge prepare -p machine

This first command installs Concierge, and the second command uses Concierge to install and configure Juju and LXD.

For this tutorial, Juju must be bootstrapped to a LXD controller. Concierge should complete this step for you, and you can verify by checking for msg="Bootstrapped Juju" provider=lxd in the terminal output and by running juju controllers.

If Concierge did not perform the bootstrap, run:

juju bootstrap lxd tutorial-controller

Set up a tutorial model

To manage resources effectively and to separate this tutorial’s workload from your usual work, create a new model using the following command:

juju add-model haproxy-tutorial

Deploy the HAProxy charm

We will deploy charm from Charmhub using the 2.8/stable channel:

juju deploy haproxy --channel=2.8/stable

Configure TLS

HAProxy enforces HTTPS when using the haproxy-route relation. To set up the TLS for the HAProxy charm, deploy the self-signed-certificates charm and integrate with the HAProxy charm:

juju deploy self-signed-certificates
juju integrate haproxy:certificates self-signed-certificates

Once all the application has settled into an “Idle” state, we can verify by sending a request to the HAProxy’s IP address:

HAPROXY_IP=$(juju status --format json | jq -r '.applications.haproxy.units."haproxy/0"."public-address"')
curl $HAPROXY_IP

If successful, the terminal will output: If successful, the terminal will output:

Default page for the haproxy-operator charm

Deploy the backend application

For this tutorial we’ll use the Pollen charm. Start by deploying the Pollen charm:

juju deploy pollen --channel=latest/edge

Configure a hostname for HAProxy and integrate the Pollen charm with HAProxy:

juju config haproxy external-hostname=pollen.internal
juju integrate pollen haproxy:haproxy-route

Let’s check that the request has been properly proxied to the backend service using the pollinate script:

HAPROXY_IP=$(juju status --format json | jq -r '.applications.haproxy.units."haproxy/0"."public-address"')
echo "$HAPROXY_IP pollen.internal" | sudo tee /etc/hosts
sudo pollinate -s https://pollen.internal -r -i

If successful, you should see a success message in the terminal:

<13>Dec 17 20:45:02 pollinate[59078]: system was previously seeded at [2025-12-17 00:08:36.226000000 +0100]
<13>Dec 17 20:45:02 pollinate[59078]: client sent challenge to [https://pollen.internal]
<13>Dec 17 20:45:02 pollinate[59078]: client verified challenge/response with [https://pollen.internal]
<13>Dec 17 20:45:02 pollinate[59078]: client hashed response from [https://pollen.internal]
<13>Dec 17 20:45:02 pollinate[59078]: client successfully seeded [/dev/urandom]

Clean up the environment

Well done! You’ve successfully completed the HAProxy tutorial.

To remove the model environment you created, use the following command:

juju destroy-model haproxy-tutorial

Next steps

Check out these advanced tutorials to learn how to use HAProxy to provide load balancing for different protocols.