HAProxy Data Plane API 2.8 is now the latest version. Learn more
HAProxy Technologies is proud to unveil the 2.7 release of HAProxy Data Plane API. This release was a huge undertaking, and as with the Data Plane API 2.6, we focused on extending support for configuration keywords. We are happy to announce that with this release we support all HAProxy configuration keywords in the Data Plane API. Along with enhanced keyword coverage, we’ve added the ability to specify multiple named default sections through the API.
In addition, we’re excited to announce some quality of life improvements. You can now add and delete servers dynamically using the Runtime API without the need to reload, and we’ve added reload strategies to simplify the configuration of the Data Plane API.
Extended HAProxy configuration keywords support
Added support for sections: program, fcgi-app, mailers and http-errors
To complete the goal of covering the entire configuration in the Data Plane API, we needed to add support for sections that were missing. Although not used as often as other sections like backend, frontend, and others, they can be very useful in some use cases.
program section
The program
section defines external binaries. When running HAProxy in master-worker mode, which you do by adding the -W flag when starting HAProxy, it is possible to launch external binaries with the master process. These external binaries are called programs. They are launched and managed the same way as the HAProxy worker processes, but could perform other long-running tasks like hosting the HAProxy traffic mirroring program, as shown in the example below.
To create a new program
section through the API, use the /v2/services/haproxy/configuration/programs
resource:
$ curl -X POST \ | |
-âuser admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "mirror", | |
"command": "spoa-mirror --runtime 0 --mirror-url http://test.local", | |
"user": "myusername", | |
"group": "mygroupname", | |
"start-on-reload": "enabled" | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/programs?version=1" |
This request creates the following program
section in the HAProxy configuration file:
program mirror | |
command spoa-mirror --runtime 0 --mirror-url http://test.local | |
user myusername | |
group mygroupname | |
option start-on-reload |
fcgi-app section
A fcgi-app
section defines how HAProxy should connect to a web application using the FastCGI protocol. Once you’ve defined the section, you can use it in backend sections with the use-fcgi-app
keyword. We covered HAProxy’s support for FastCGI in our blog post Load Balancing PHP-FPM with HAProxy and FastCGI.
You can create a new fcgi-app
section through the API using the newly added resource /v2/services/haproxy/configuration/fcgi_apps
:
$ curl -X POST \ | |
-âuser admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "php_fpm", | |
"docroot": "/var/www/myapp", | |
"index": "index.php", | |
"path-info": "^(/.+\\.php)(/.*)?$", | |
"log-stderr": [ | |
{ | |
"global": true | |
} | |
] | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/fcgi_apps?version=2" |
This request creates an fcgi-app
section in your HAProxy configuration file that looks like this:
fcgi-app php_fpm | |
docroot /var/www/myapp | |
index index.php | |
path-info ^(/.+\.php)(/.*)?$ | |
log-stderr global |
To activate FastCGI, you must then reference this fcgi-app
section in a backend, which you can do by making a PUT request to the /services/haproxy/configuration/backends/{name}
resource with the use-fcgi-app
parameter in the body of the request.
mailers section
A mailers
section lists mail servers to which HAProxy will send notification emails via the SMTP protocol. To create a mailers
section, use /v2/services/haproxy/configuration/mailers_section
:
$ curl -X POST \ | |
-âuser admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "mymailers", | |
"timeout": 20000 | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/mailers_sections?version=4" |
Then to define the servers, add mailer
lines to the mailers
section using the /v2/services/haproxy/configuration/mailer_entry
resource:
$ curl -X POST \ | |
-âuser admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "mymailers", | |
"timeout": 20000 | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/mailers_sections?version=4" |
These requests create an HAProxy configuration like this:
mailers mymailers | |
timeout mail 20000 |
http-errors section
By adding an http-errors
section to your configuration, you can define branded error pages to display to users rather than the basic, stock error pages. We cover this feature in our blog post Serve Dynamic Custom Error Pages with HAProxy. It is possible to globally declare several groups of HTTP error pages, which can be imported afterwards into any proxy section. The same group may be referenced at multiple places and can be fully or partially imported.
To create a new http-errors
section using the API you can use the /v2/services/haproxy/configuration/http_errors_sections
resource:
$ curl -X POST \ | |
-âuser admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "website-1", | |
"error_files": [ | |
{ | |
"code": 400, | |
"name": "/etc/haproxy/errorfiles/site1/400.http" | |
}, | |
{ | |
"code": 404, | |
"name": "/etc/haproxy/errorfiles/site1/404.http" | |
} | |
] | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/http_errors_sections?version=3" |
This request creates an HAProxy configuration like this:
http-errors website-1 | |
errorfile 400 /etc/haproxy/errorfiles/site1/400.http | |
errorfile 404 /etc/haproxy/errorfiles/site1/404.http | |
mailer smtp1 192.168.0.1:587 |
New resource http_error_rules
In addition to those new sections, there is a new resource, /services/haproxy/configuration/http_error_rules
, which represents http-error
in the HAProxy configuration. This directive imports a custom error page to use for an error that originates from HAProxy, such as 503 Service Unavailable and 504 Gateway Timeout. It has the ability to render a static HTML file from an http-errors
section when given the errorfiles
parameter. Here is an example of how to add this new resource to an already existing backend section named test:
$ curl -X POST \ | |
-âuser admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"index": 0, | |
"status": 503, | |
"errorfiles": "website-1" | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/http_error_rules?parent_type=backend&parent_name=test&version=6" |
This will create the following line in your backend section in the HAProxy configuration file:
http-error status 503 errorfiles website-1 |
This line means that for 503 statuses, HAProxy will return whatever file is defined for status 503 in the website-1 errorfiles
section.
Support for all options in defaults, frontend, and backend sections
With release 2.7 of the Data Plane API we are happy to announce that the frontend
, backend
, and defaults
resources now support all options in the respective HAProxy sections. Here’s an extensive list of added options for the sections:
/services/haproxy/configuration/backends
:
persist_rule
http_restrict_req_hdr_names
tarpit_timeout
server_fin_timeout
email_alert
load_server_state_from_file
server_state_file_name
description
id
enabled
disabled
use_fcgi_app
error_files
errorfiles_from_http_errors
errorloc302
errorloc303
fullconn
force_persist
ignore_persist
http_send_name_header
max_keep_alive_queue
retry_on
source
/services/haproxy/configuration/frontends
:
client_fin_timeout
tarpit_timeout
http_restrict_req_hdr_names
email_alert
description
id
enabled
disabled
error_files
errorfiles_from_http_errors
errorloc302
errorloc303
error_log_format
/services/haproxy/configuration/defaults
:
hash_type
persist_rule
http_restrict_req_hdr_names
tarpit_timeout
email_alert
enabled
disabled
errorfiles_from_http_errors
errorloc302
errorloc303
error_log_format
fullconn
http_send_name_header
max_keep_alive_queue
retry_on
source
Named Defaults
As of HAProxy 2.4, inheriting settings from a specific defaults section is possible with the use of the from
keyword on the line where you define your section and its name, e.g.:
defaults http | |
mode http | |
timeout connect 10000 | |
timeout client 30000 | |
timeout server 30000 | |
defaults tcp | |
mode tcp | |
frontend fe_1 from http | |
bind 0.0.0.0:80 | |
frontend fe_2 from tcp | |
bind 0.0.0.0:3000 | |
timeout connect 20000 |
This way you can specify that the frontend fe_1
frontend section inherits all the settings specified in the defaults http
defaults section, while frontend fe_2
inherits only the settings from the defaults tcp
section. This way you don’t have to rely on ordering of your sections to inherit the proper settings. If no from
is defined that section will implicitly inherit the settings from the last defaults
section specified before that section. So to avoid ambiguity official HAProxy docs suggest naming your defaults settings and specifying from
in your sections’ definitions.
To fully support HAProxy configurations, we added support for this in the API, but we still wanted this version to support older versions of HAProxy, namely all versions from HAProxy 2.1 to 2.7 so some compromises in the API were made. Also we didn’t want to break backward compatibility so we created a new resource in the API /services/haproxy/configuration/named_defaults
where you can now GET multiple defaults, create new defaults, and delete existing ones to support having multiple defaults sections instead of just one like it was before HAProxy Data Plane API 2.7.
Also defaults resources now have additional name
and from
fields, while frontend and backend resources now have the from
field.
In the HAProxy configuration some settings depend on the ordering, and that creates some implicitness in the configuration. When you are using the HAProxy Data Plane API to configure HAProxy we want to remove as many implicit settings as possible, so in that case, you will see some changes in your HAProxy configurations. No matter which version of HAProxy you are running, you will see that all your defaults sections that don’t have a name will get a name unnamed_defaults_<n>
, where n is an automatically incrementing number starting with 1.
If you are running HAProxy 2.4 or newer, it means that HAProxy supports the from
keyword, and Data Plane API will enforce usage of that functionality. This means that when first parsing the HAProxy configuration file, Data Plane API will go through all the sections, and if your section does not have the from
keyword, it will automatically assign it to the last defaults section it parsed. This way implicit settings become explicit, and it’s easier to parse and debug. To better explain it with an example, this might be a configuration that you already have and want to use the Data Plane API:
defaults | |
mode http | |
timeout connect 10000 | |
timeout client 30000 | |
timeout server 30000 | |
frontend fe_1 | |
bind 0.0.0.0:80 | |
defaults | |
mode tcp | |
frontend fe_2 | |
bind 0.0.0.0:3000 | |
timeout connect 20000 |
After first parsing it for the first time, your configuration will be transformed to look like this if you are running HAProxy version 2.4 or newer:
defaults unnamed_defaults_1 | |
mode http | |
timeout connect 10000 | |
timeout client 30000 | |
timeout server 30000 | |
defaults unnamed_defaults_2 | |
mode tcp | |
frontend fe_1 from unnamed_defaults_1 | |
bind 0.0.0.0:80 | |
frontend fe_2 from unnamed_defaults_2 | |
bind 0.0.0.0:3000 | |
timeout connect 20000 |
This way, your configuration is a bit changed, but the original functionality is unchanged and it’s easily representable and changeable via the Data Plane API.
To remain backward compatible, the defaults resource will still stay the same: on GET you will always get the last defaults section in the HAProxy configuration, and on PUT you will be changing the same section in the API. This way when you upgrade, you will only have one defaults section and this will be discoverable by both the old defaults resource and the new named_defaults resource. Please note that in the future versions we will be removing the defaults resource so we suggest you migrate to using named_defaults moving forward.
Dynamic Server Configuration
In addition to all the HAProxy configuration changes that version 2.7 brings to the Data Plane API, we have implemented support for add server
and del server
commands from the HAProxy Runtime API. Those commands were added in HAProxy 2.4 so they won’t work if you try to run them in older versions of HAProxy.
To use the new add
and del
commands, use the existing /services/haproxy/runtime/servers
API resource. We’ve added POST and DELETE methods to support add
and del
server commands respectively.
When using any runtime/
resources, changes are only applied through the HAProxy Runtime API and are not persisted in the configuration file. This means that those changes are strictly transient and will not survive a reload or a restart.
With the ability to use these commands through the Runtime API, we’ve added some changes to how the /services/haproxy/configuration/servers
resource behaves. So if you are running HAProxy 2.4 or newer and you are adding a server, this change will be done automatically through the Runtime API and no reload will be issued. There are a couple of caveats to this though, as mentioned in the official documentation for the Runtime API add server command: the Runtime API supports only a subset of server
fields, so if your server has any non-supported fields, the Data Plane API will issue a reload on the HAProxy process. Also given that the server you are adding in through the Runtime API doesn’t take into account any default settings specified in the default-server
configuration line, if there is a default-server
line set in your backend or the relevant defaults section, the Data Plane API will again issue a reload.
We’ve opted not to do the same for the deletion of servers, as that may hinder your running servers and cause them to forcefully drop connections. In the future we are looking to improve this in the Runtime API, so that the server first drains its connections before it’s deleted, which it doesn’t do now, so upon deletion of /services/haproxy/configuration/servers
, the Data Plane API will still issue a reload to avoid any unwanted dropped connections for the mentioned server.
Reload Strategies
One quality of life improvement that the Data Plane API 2.7 brings is something we call reload strategies. In previous versions, to set the HAProxy reload commands you would have configured something like this:
YAML:
haproxy: | |
config_file: "/etc/haproxy/haproxy.cfg" | |
haproxy_bin: "haproxy" | |
reload: | |
reload_cmd: "systemctl reload haproxy" | |
restart_cmd: "systemctl restart haproxy" | |
status_cmd: "systemctl status haproxy" |
Now we’ve implemented reload strategies. In the reload
section of the Data Plane API configuration, you can set the new reload_strategy
option to either systemd, s6, or custom. To remain backward compatible, the upper snippet will still work as a custom reload strategy. If you set any of the other supported values, HAProxy will by default use the following commands:
For systemd:
reload_cmd: "sudo -n systemctl reload haproxy.service" | |
restart_cmd: "sudo -n systemctl restart haproxy.service" | |
status_cmd: "systemctl --quiet is-active haproxy.service" |
For s6:
reload_cmd: "s6-svc -2 /etc/service.d/haproxy" | |
restart_cmd: "s6-svc -r /etc/service.d/haproxy" | |
status_cmd: "s6-svstat -u /etc/service.d/haproxy" |
In addition, you can customize the service name using the service_name option. For example, now if you use systemd to manage an HAProxy process called haproxy, you can set this in the configuration:
YAML:
haproxy: | |
config_file: "/etc/haproxy/haproxy.cfg" | |
haproxy_bin: "haproxy" | |
reload: | |
reload_strategy: "systemd" | |
service_name: "haproxy-2.4" |
The same is true if you are using the s6 init system. Note that service_name
is optional, and the default values are as mentioned before.
Another thing that changed in HAProxy 2.7 is improved reload handling in the master Runtime API. So if you are running HAProxy 2.7 in master-worker mode with a master socket configured in the Data Plane API, the Data Plane API will use it for reloads no matter what you configured, as it is the most reliable method. Before HAProxy 2.7 the reload command would just kill the socket connection, leaving you with no information about the outcome of the reload. In 2.7, by contrast, reload behaves synchronously, so when you issue a reload command, you can wait for the response and see whether the reload succeeded or failed, and you get the output of the reload command which enables you to more consistently revert configuration in case the reload failed.
Library Updates & Bug Fixes
In addition to the many enhancements described above, HAProxy Data Plane API 2.7 introduces some stability and infrastructure improvements as well as bug fixes.
One of the bigger updates is that the Data Plane API project has been migrated to Go 1.19 along with the underlying libraries, config-parser, and client-native. This migration allows us to get all the new features of the Go language to improve our codebase, along with some optimizations and, of course, security fixes.
In addition, we performed a thorough scan of all external dependencies and performed updates as needed for bug and security fixes.
There have been 58 commits of bug fixes in the Data Plane API project and its underlying libraries since the v2.6.0 release.
Version Note
With Data Plane API release 2.7 we have caught up the HAProxy versioning numbers, and with this, we’ll be moving from our quarterly release schedule to the same release schedule as HAProxy, meaning a bi-yearly release cadence with one LTS version.
Data Plane API 2.7 supports all HAProxy versions from 2.1 to 2.7. The plan, moving forward with the same versioning numbers, is to keep it one-to-one with HAProxy versions, so that each HAProxy gets its matching version of Data Plane API. This will be implemented and announced in one of the future versions of the Data Plane API.
Read more:
Conclusion and Contributors
With this release, we’re proud to say we’ve achieved our goal of full HAProxy configuration support!
We’d like to thank the code contributors who helped achieve this important milestone:
Contributor | Area |
Alexander Duryagin | BUG |
Andjelko Iharos | BUG FEATURE |
Dario Tranchitella | FEATURE OPTIMIZATION REORG TEST |
Dinko Korunic | BUG FEATURE OPTIMIZATION |
George Vine | BUG FEATURE |
Goran Galinec | BUG CLEANUP FEATURE |
Karan Sharma | BUG FEATURE |
Marko Juraga | BUG BUILD CLEANUP DOC FEATURE TEST |
Olivier Duclos | BUG DOC FEATURE TEST |
Robert Maticevic | BUG FEATURE |
Tim Brabant | BUG |
Zlatko Bratkovic | BUG BUILD CLEANUP FEATURE TEST |
To check the latest release, visit our GitHub releases page.
Subscribe to our blog. Get the latest release updates, tutorials, and deep-dives from HAProxy experts.