In HAProxy Data Plane API version 2.6, we continued the effort of expanding support for HAProxy configuration keywords, as this has been the priority with this release cycle, and it will be in the next one too to meet our goal of achieving complete feature parity with both the HAProxy configuration and Runtime API. This will enable you to use HAProxy Data Plane API for configuring HAProxy without any gaps in functionality.
With that in mind, we also implemented quality of life improvements, namely adding a health check endpoint that returns the status of the HAProxy process, and we upgraded to Go 1.18 and updated all dependencies that we are using so users can benefit from bug and security fixes.
Extended Keyword Support
We updated the HAProxy Data Plane API to cover more HAProxy configuration keywords, with the goal of making the API a full-fledged way to configure HAProxy. In this section, you’ll see everything we’ve added.
The ring section
Since HAProxy 2.2, you’ve had the ability to define a section called ring
which creates a FIFO buffer in memory where you can store HAProxy’s logs temporarily before forwarded them to a remote syslog server. The benefit of using a ring buffer is that it allows you to forward log messages to a remote syslog server using TCP. A traditional log line in an HAProxy configuration forwards logs using the UDP protocol. Relaying logs using UDP avoids any slowdowns, since UDP is a connectionless protocol, but the downside is that there is no guarantee that every log message will arrive at the destination. UDP is fire and forget.
global | |
# Uses a UDP port | |
log 192.168.56.30:514 local0 |
However, by defining a ring section you can buffer log messages and then communicate with a syslog server over a TCP port without slowing down HAProxy since the log forwarding happens in the background. The TCP protocol is a connected protocol and guarantees delivery of all messages. In the snippet below, we define a ring section for buffering HAProxy logs.
ring logbuffer | |
description "My log buffer" | |
format rfc3164 | |
maxlen 1200 | |
size 32764 | |
timeout connect 5s | |
timeout server 10s | |
# Uses a TCP port | |
server mysyslogsrv 192.168.56.30:514 log-proto octet-count |
Then in the global
section of your configuration, your log line would specify the ring buffer instead of an IP address and port:
global | |
log ring@logbuffer local0 info |
You can now create a ring
section through the API by using the /services/haproxy/configuration/rings endpoint, as shown below.
$ curl -X POST \ | |
--user admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "logbuffer", | |
"description": "My log buffer", | |
"format": "rfc3164", | |
"maxlen": 1200, | |
"size": 32764, | |
"timeout_connect": 5000, | |
"timeout_server": 1000 | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/rings?version=1" |
Then add a server to it by using the /services/haproxy/configuration/servers endpoint, setting the URL parameter parent_type
to ring and parent_name
to the name of the ring section.
$ curl -X POST \ | |
-–user admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "mysyslogsrv", | |
"address": "192.168.56.30", | |
"port": 514, | |
"log_proto": "octet-count" | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/servers?parent_type=ring&parent_name=logbuffer&version=2" |
To remain backward compatible, the server endpoint will still have the backend query string parameter, but it will be removed in a future version. Going forward please use parenttype and parentname query string parameters to specify the section to which a server resource belongs.
Add the required log line to your global section by invoking the /services/haproxy/configuration/log_targets endpoint.
The log-forward section
An earlier version of this post recommended using the log-forward section for load balancing, but this has been amended to indicate that the use case is primarily log forwarding, since health checking is not yet available.
While the ring
section pertains to forwarding HAProxy’s own logs, another section named log-forward
pertains to forwarding log messages for other applications to a list of syslog servers. This gets its own section in order to support relaying syslog messages over UDP, while in general HAProxy is a TCP-based proxy. The log-forward
section was introduced in HAProxy 2.3 and looks like this:
log-forward sylog | |
# receive log messages on UDP port | |
dgram-bind 192.168.56.20:514 | |
# receive log messages on TCP port | |
bind 192.168.56.20:514 | |
# forward to this syslog server using UDP | |
log 192.168.56.21:514 local0 |
You can create a log-forward
section through the API by using the new /services/haproxy/configuration/log_forwards endpoint.
$ curl -X POST \ | |
-–user admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"name": "sylog", | |
"maxconn": 100 | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/log_forwards?version=3" |
Then add a bind
line for receiving syslog traffic over TCP and a dgram_bind
line for receiving it over UDP by calling the /services/haproxy/configuration/binds and /services/haproxy/configuration/dgram_binds endpoints:
$ curl -X POST \ | |
-–user admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"address": "192.168.56.20", | |
"port": 514 | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/binds?parent_type=log_forward&parent_name=syslog&version=4" | |
$ curl -X POST \ | |
-–user admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"address": "192.168.56.20", | |
"port": 514 | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/dgram_binds?log_forward=syslog&version=5" |
To remain backward compatible, the bind resource will still have the frontend query string parameter, but it will be removed in a future version. Going forward please use parenttype and parentname query string parameters to specify the section to which a bind resource belongs too.
Finally, add the log servers to which you will forward traffic by invoking the /services/haproxy/configuration/log_targets endpoint.
$ curl -X POST \ | |
-–user admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"address": "192.168.56.21:514", | |
"facility": "level0", | |
"sample_range": "1", | |
"sample_size": 2, | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/log_targets?parent_type=log_forward&parent_name=syslog&version=5" |
Global section keywords
With version 2.6, we’re happy to announce that the /services/haproxy/configuration/global endpoint supports all options for the HAProxy global
section.
Process management and security:
default-path
description
expose-experimental-directives
gid
grace
insecure-fork-wanted
insecure-setuid-wanted
issuers-chain-path
h2-workaround-bogus-websocket-clients
log-tag
lua-load-per-thread
mworker-max-reloads
node
numa-cpu-mapping
pp2-never-send-local
presetenv
resetenv
uid
ulimit-n
set-dumpable
set-var
setenv
unix-bind
unsetenv
strict-limits
SSL tuning options:
ssl-default-bind-ciphers
ssl-default-bind-ciphersuites
ssl-default-bind-curves
ssl-default-bind-options
ssl-default-server-ciphers
ssl-default-server-ciphersuites
ssl-default-server-options
ssl-dh-param-file
ssl-server-verify
ssl-skip-self-issued-ca
Performance tuning:
busy-polling
max-spread-checks
maxconnrate
maxcomprate
maxcompcpuusage
maxpipes
maxsessrate
maxsslconn
maxsslrate
maxzlibmem
noepoll
nokqueue
noevports
nopoll
nosplice
nogetaddrinfo
noreuseport
profiling.tasks
spread-checks
ssl-engine
Defaults, frontend and backend keywords
Version 2.6 of the HAProxy Data Plane API also brings support or all option keywords that can be configured in defaults
, backend
, and frontend
sections via the /services/haproxy/configuration/defaults, /services/haproxy/configuration/frontends, and /services/haproxy/configuration/backends API endpoints:
option abortonclose
option checkcache
option http-ignore-probes
option http-no-delay
option http-use-proxy-header
option httpslog
option independent-streams
option nolinger
option originalto
option persist
option prefer-last-server
option socket-stats
option splice-auto
option splice-request
option splice-response
option spop-check
option srvtcpka
option tcp-smart-accept
option tcp-smart-connect
option tcpka
option transparent
In addition, we’ve extended the stats object that you can configure in a frontend or backend section to include the following options:
stats auth
stats http-request
stats realm
For the backend
and the defaults
sections we added support for the server TCP keep-alive options:
srvtcpka-cnt
srvtcpka-idle
Srvtcpka-intvl
For the frontend
and the defaults
sections we added support for the client TCP keep-alive options:
clitcpka-cnt
clitcpka-idle
clitcpka-intvl
The http-after-response directive
HAProxy 2.6 introduced the http-after-response
directive, which applies an action to all responses, even those generated by HAProxy and returned without involving a backend server. People use it to attach HTTP headers to a response when HAProxy returns a redirect, for example. The older http-response
directive applies only when the backend server sends the response.
With HAProxy Data Plane API 2.6, you can configure http-after-response
directives similarly to how you would configure http-response
directives, only using the /services/haproxy/configuration/httpafterresponse_rules endpoint.
$ curl -X POST \ | |
-–user admin:password \ | |
-H "Content-Type: application/json" \ | |
-d '{ | |
"index": 0, | |
"action": "set-header", | |
"hdr_name": "Cache-Control", | |
"hdr_fmt": "no-store,no-cache,private", | |
}' \ | |
"http://127.0.0.1:5555/v2/services/haproxy/configuration/http_after_response_rules?parent_type=frontend&parent_name=test&version=1" |
This will create the following line in your frontend
section in the HAProxy configuration file:
frontend test | |
http-after-response set-header Cache-Control "no-store,no-cache,private" |
Health Endpoint
A new endpoint, /health, returns a value indicating whether HAProxy is up and running.
$ curl -X GET \ | |
-–user admin:password \ | |
-H "Content-Type: application/json" \ | |
"http://127.0.0.1:5555/v2/health" | |
HTTP/1.1 200 OK | |
Content-Type: application/json | |
Vary: Origin | |
Date: Thu, 14 Jul 2022 13:01:17 GMT | |
Content-Length: 22 | |
Connection: close | |
{ | |
"haproxy": "up" | |
} |
To enable this feature, you must configure the status_cmd
field in the HAProxy Data Plane API configuration file (e.g. /etc/haproxy/dataplaneapi.hcl), as shown below.
HCL
haproxy { | |
config_file = "/etc/haproxy/haproxy.cfg" | |
haproxy_bin = "haproxy" | |
reload { | |
reload_delay = 5 | |
reload_cmd = "systemctl reload haproxy" | |
restart_cmd = "systemctl restart haproxy" | |
status_cmd = "systemctl status haproxy" | |
reload_retention = 1 | |
} | |
} |
YAML
haproxy: | |
config_file: "/etc/haproxy/haproxy.cfg" | |
haproxy_bin: "haproxy" | |
reload: | |
reload_delay: 5 | |
reload_cmd: "systemctl reload haproxy" | |
restart_cmd: "systemctl restart haproxy" | |
status_cmd: "systemctl status haproxy" | |
reload_retention: 1 |
Library Updates and Bug Fixes
One of the bigger updates is that the HAProxy Data Plane API project has been migrated to Go 1.18 along with the underlying libraries config-parser and client-native. This 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.
We’ve also updated the go-swagger library we use for code generation to the latest version, which received many bug fixes but introduced some breaking changes for our models package in the client-native project. So, the client-native package has been upgraded to v4. This is important news for all of our contributors, since they will need to update their dev environments for both Go 1.18 and go-swagger 0.29.0.
In addition to that, we did a thorough pass of all the external dependencies used by the HAProxy Data Plane API project and updated those dependencies where needed to benefit from all the bug and security fixes.
Contributors
We’d like to thank the code contributors who helped make this version possible!
Contributor | Area |
Amel Husic | FEATURE |
Andjelko Horvat | BUG FEATURE |
Andjelko Iharos | BUG FEATURE |
Dinko Korunic | BUG |
Connor Edwards | BUG |
Dario Tranchitella | BUG CLEANUP FEATURE TEST |
Goran Galinec | BUG CLEANUP FEATURE |
Mark | CLEANUP |
Marko Juraga | BUG BUILD CLEANUP DOC FEATURE |
Moemen Mhedhbi | FEATURE |
Norwin Schnyder | BUG FEATURE |
Robert Maticevic | BUG BUILD CLEANUP FEATURE REORG |
Seena Fallah | BUG FEATURE |
Zlatko Bratkovic | BUG BUILD CLEANUP FEATURE |