The HAProxy load balancer provides a set of APIs for configuring it programmatically.
Although many people enjoy the simplicity of configuring their HAProxy load balancer by directly editing its configuration file, /etc/haproxy/haproxy.cfg, others want a way to do it without logging into the server. Or, they want a way that integrates with bespoke software. For example, they want to add pools of servers to the load balancer programmatically as a part of their CI/CD deployment pipeline.
HAProxy and HAProxy Enterprise provide two APIs for managing your load balancer remotely or programmatically: the HAProxy Runtime API and the HAProxy Data Plane API. Why are there two? What purpose does each serve? In this blog post, you’ll learn about them and find resources for getting started.
The HAProxy Runtime API
The HAProxy Runtime API is the older of the two, introduced in 2016 with HAProxy version 1.7. Since then, it has grown to cover many of the load balancer’s features. You can use it to enable and disable servers, stop and start health check probes, set ACL values, inspect stick tables, view statistics, and more. Built directly into the codebase of HAProxy, its version releases are intertwined into the releases of the load balancer itself.
There are two ways to expose the API: you can either have it listen on a UNIX domain socket like /var/run/haproxy/api.sock, in which case you can access it only while logged into the server, or you can publish it on a TCP/IP address. To use a socket, add a
stats socket line to the
global section of your configuration file:
|stats socket /var/run/haproxy/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners|
To use a TCP/IP address, change the
stats socket line so that it sets an IP address and port instead of a file path:
|stats socket email@example.com:9999 level admin expose-fd listeners|
You send commands by echoing them to the listening socket or address. For example, to see a list of available functions, you would echo the
help command and pipe it to a tool like socat:
|$ echo "help" | sudo socat stdio /var/run/haproxy/api.sock|
If using a TCP/IP address, the command looks like this:
|$ echo "help" | socat stdio tcp4-connect:127.0.0.1:9999|
All of the Runtime API’s commands use this form. For example, to drain traffic from a server you would echo the
set server command:
|$ echo "set server webservers/server1 state drain" |\|
|sudo socat stdio /var/run/haproxy/api.sock|
The defining trait of the Runtime API is that all configuration changes are applied in memory, but do not alter the HAProxy configuration file on disk. The reason for that is simple. For better performance and security, HAProxy never reads from the filesystem after completing its initial startup. During startup, it reads the haproxy.cfg file, along with any other supporting files like SSL certificates and map files, and then keeps a representation of those files in memory. The Runtime API modifies those in-memory representations only. So, after calling an API function, you should not expect to see any change to the files on disk, but HAProxy’s representation of those files will have been updated.
The advantage of making changes in memory only is that you don’t need to reload the load balancer for the changes to take effect. Avoiding a reload helps speed up operations and uses fewer computer resources. The disadvantage is that the changes are not durable. Restarting or reloading the load balancer loses all changes you’ve made with the Runtime API. There is a way to save and restore some of the data by using state files, which are files into which HAProxy dumps the current state of your servers including each server’s IP address, weight and drain status. However, this doesn’t cover the full range of changes that you could have made with the API.
The Runtime API works well for making quick changes on the fly like enabling and disabling servers and changing health check probes; it’s also convenient for viewing statistics and data related to servers, stick tables, maps, and peers. The most recent release of HAProxy adds the ability to add and remove servers via the API. However, to persist your changes, you’ll need to pair it with a mechanism that writes the changes to disk. As you’ll see, the Data Plane API, which is the spiritual successor to the Runtime API, fulfills that role. It writes changes to disk and also calls the Runtime API itself when a given operation is available.
Learn more about the HAProxy Runtime API.
The HAProxy Data Plane API
The HAProxy Data Plane API was released in 2019 at the same time as HAProxy 2.0, but it has its own codebase and follows its own release schedule. Not being dependent on HAProxy’s runtime, the Data Plane API is a self-hosted RESTful HTTP service. A RESTful architecture means that HTTP verbs like GET, PUT, POST and DELETE change the behavior of an API endpoint to either read, update, create or delete a configuration setting.
The Data Plane API is designed to be embedded into other software. It’s built upon the OpenAPI standard, which makes it compatible with a variety of code-generation tools that you can use to generate client-side code in a number of languages. That makes it easier to integrate into your own program.
It ships as a program that you run alongside HAProxy; you can download it from its GitHub page. HAProxy Enterprise ships it as a system package for extra convenience. Being a separate program has some advantages. For one thing, having its versions be independent of HAProxy allows bug fixes and new features to be published without needing to deploy a newer version of the load balancer. The API is written in the Go programming language, which many would argue is a simpler language than C, making it accessible to more developers who want to contribute.
With the Data Plane API, you can build an HAProxy configuration nearly from the ground up. You can add pools of servers, define frontend listeners, update ACLs and maps, manage SSL certificates, and more. Recent releases have added support for powerful features like service discovery with Consul and AWS EC2. API calls update the configuration file on disk so that they persist past a restart. However, the Data Plane API invokes the Runtime API where possible to avoid a reload.
Read the official documentation to learn how to set it up. Basically, you will create the Data Plane API configuration file and then, when starting the program, point to that file with the
|$ sudo dataplaneapi -f /etc/haproxy/dataplaneapi.hcl|
Commands typically return or take JSON objects. For example, the info function returns JSON that describes the API’s version:
|$ curl -X GET --user admin:adminpwd http://localhost:5555/v2/info|
The API supports batching multiple operations together into a transaction and then executing them as an atomic operation. Transactions let you make larger changes at once, such as configuring a frontend and corresponding backend at the same time.
To manage an HAProxy instance, you would just need to run the API next to it.
Learn more about the HAProxy Data Plane API.
By harnessing the Runtime API or the Data Plane API, you can manage your HAProxy configuration without editing its configuration file by hand. The Runtime API is great for changing the state of your servers, SSL certificates, map files, and stick tables without requiring a reload. Use the Data Plane API to build a configuration from the ground up using RESTful HTTP commands. Behind the scenes, the Data Plane API calls the Runtime API whenever it can to avoid a reload. Together, these APIs make it possible to integrate HAProxy into a variety of automation, CI/CD, and observability tools.Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.