HAProxy’s configuration can be dynamically updated without restarting the service, a feat often achieved by targeting specific backend server entries.

Let’s see this in action. Imagine we have a HAProxy configuration like this:

frontend http_in
    bind *:80
    default_backend webservers

backend webservers
    balance roundrobin
    server srv1 192.168.1.10:80 check
    server srv2 192.168.1.11:80 check

We want to add a new backend server, srv3 at 192.168.1.12:80. To do this, we’ll use HAProxy’s Runtime API, typically exposed over a TCP socket.

First, ensure your HAProxy configuration has the stats socket directive:

global
    stats socket /var/run/haproxy.sock mode 660 level admin

Now, we can use socat or echo to send commands to this socket.

To add srv3:

echo "add server webservers/srv3 192.168.1.12:80 check" | sudo socat stdio /var/run/haproxy.sock

If you check your HAProxy stats (usually via http://<haproxy_ip>:8404/ if you’ve configured a stats frontend), you’ll see srv3 listed and participating in load balancing. The check option means HAProxy will immediately start health-checking this new server.

To remove srv1:

echo "del server webservers/srv1" | sudo socat stdio /var/run/haproxy.sock

This removes srv1 from active rotation. HAProxy will drain existing connections gracefully before fully removing it.

The problem HAProxy’s runtime API solves is the ability to scale your application’s backend capacity up or down, or perform maintenance on individual servers, without any interruption to service. This is crucial for high-availability systems where downtime is unacceptable. Internally, when you add a server, HAProxy allocates the necessary structures to track its state, health checks, and statistics, and then inserts it into the appropriate backend’s server list. When you remove a server, it marks it for draining, stops sending new connections, and once existing connections are finished, it deallocates those resources.

The show servers state <backend> command is invaluable here. It will show you the current state of all servers within a given backend, including whether they are UP, DOWN, MAINT, or DRAIN. This allows you to verify the impact of your runtime commands. For instance, after running del server webservers/srv1, show servers state webservers will eventually show srv1 in a DRAIN or DOWN state before it disappears entirely.

Many administrators are unaware that you can directly manipulate server weights and other parameters at runtime as well. For example, to temporarily reduce the load on srv2, you could issue:

echo "set server webservers/srv2 weight 50" | sudo socat stdio /var/run/haproxy.sock

This command changes the weight of srv2 to 50, meaning it will receive half the traffic of a server with weight 100. This is incredibly useful for canary deployments or when a server is experiencing high load but is still healthy enough to serve some traffic.

The next logical step after managing individual servers is to consider how HAProxy handles changes to the backend itself, such as adding or removing entire backend definitions.

Want structured learning?

Take the full Haproxy course →