Quickstart HAProxy Community Edition dataplaneAPI

This guide was written after starting up a brand new Ubuntu Server on 22.04 and details the steps taken to quickly get the dataplaneapi up and running.

sudo apt-get update
sudo apt-get install haproxy

Run this to see what version is installed

haproxy -v 

For the sake of this discussion I have HAProxy 2.4.22

Running uname -a or uname -m told me I have x86_64 - That is amd64 architecture

Pick the package that you need from this page:

Note: API just needs to be a newer version than your haproxy version long as you are on HAProxy 1.9 and above.

I’m using this one: dataplaneapi_2.8.3_linux_amd64.deb

Right click on the name and click copy link
https://github.com/haproxytech/dataplaneapi/releases/download/v2.8.3/dataplaneapi_2.8.3_linux_amd64.deb

Curl and download the file into your home directory:

cd ~
curl -JLO https://github.com/haproxytech/dataplaneapi/releases/download/v2.8.3/dataplaneapi_2.8.3_linux_amd64.deb

Install it:

sudo dpkg -i dataplaneapi_2.8.3_linux_amd64.deb

I can see that the dataplane api is now installed:

which dataplaneapi

Returns:

/usr/sbin/dataplaneapi

Make sure that the global configuration has the socket configured:

grep "global\|defaults\|stats socket" /etc/haproxy/haproxy.cfg

It should return this or something similar. If “defaults” shows before the stats line then you need to
make sure you move the stats line under the global section

grep "global\|defaults\|stats socket" /etc/haproxy/haproxy.cfg

Returns:

global
        stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
defaults
        log     global

Create the /etc/haproxy/dataplaneapi.yml file

sudo vi /etc/haproxy/dataplaneapi.yml

Paste the configuration from this page on step 5 - change the password as desired:

If you run this command to start it up it merely runs the API and starts the socket.
It will appear to hang but that’s just because it’s listening. You can open another ssh session to test it.

sudo dataplaneapi -f /etc/haproxy/dataplaneapi.yml

Testing the api:
With the above command running run this:

curl -X GET --user admin:adminpwd http://localhost:5555/v2/info

Result should be similar to this:

{"api":{"build_date":"2023-06-15T09:07:18.000Z","version":"v2.8.0 b77adc7"},"system":{}}

If it’s not then see the green “Tip” sections for help on this page:

Let’s make it load on startup

sudo vi /etc/haproxy/haproxy.cfg

Add these items in (note: the word ‘global’ should already be present, don’t duplicate it):

global
  master-worker
program api
  command dataplaneapi -f /etc/haproxy/dataplaneapi.yml
  no option start-on-reload

Restart haproxy:

sudo systemctl restart haproxy

This is my current frontend and backend configuration:

frontend frontend1
        bind *:80
        mode http
        option httplog
        log global

        default_backend    be_app

backend be_app
        mode http
        option httpchk HEAD /
        log global
        server app1        172.16.1.32:80 cookie a1 check

If I query for the frontend this way:

curl -X GET   --user admin:adminpwd   "http://127.0.0.1:5555/v2/services/haproxy/configuration/frontends"

The response looks like this:

{"_version":2,"data":[{"default_backend":"be_app","from":"unnamed_defaults_1","httplog":true,"mode":"http","name":"frontend1"}]}

Personally that’s hard to read so I want to install jq and pipe the command to that so it reads like this:

sudo apt-get install jq

Now send it:

curl -X GET   --user admin:adminpwd http://127.0.0.1:5555/v2/services/haproxy/configuration/frontends" | jq

Response is this:

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   129  100   129    0     0   262k      0 --:--:-- --:--:-- --:--:--  125k
{
  "_version": 2,
  "data": [
    {
      "default_backend": "be_app",
      "from": "unnamed_defaults_1",
      "httplog": true,
      "mode": "http",
      "name": "frontend1"
    }
  ]
}	
2 Likes

Amazing guide @randomguy
No wonder I was previously unable to make it work on my own, it’s quite involved!

{
   "_version": 4,
   "data": [
      {
         "default_backend": "be_app",
         "from": "RandomGuyRocks",
         "httplog": true,
         "mode": "http",
         "name": "Glorious"
      }
   ]
}

For any future readers there’s some good examples on using it here:

Something to watch for is notice that a frontend configuration and a bind configuration are two different things so make sure you create both as needed.

Hi @randomguy Nate, any chance you could add to the guide these topics?:

  • Creating a server
  • Adding a server to a backend
  • How to get the “version”

Thank you.

Just to be clear are you looking for the dataplane api version or the HAProxy version?

Hi @Yosu_Cadilla the way I commonly work through API stuff is to configure the object by hand and then run a call to the API to get the data and see what it looks like. Once I have a base structure understanding then the manuals and reference become helpful. I am NOT a programmer or the best person for this but this is how I do it.

For example

admin@HAProxy:~$ curl -k -X GET   --user admin:adminpwd "https://172.16.1.2:5555/v2/services/haproxy/configuration" | jq -M . | grep -i server
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  8257    0  8257    0     0   719k      0 --:--:-- --:--:-- --:--:--  733k
    "description": "Returns an array of all servers that are configured in specified backend.",
    "title": "Return an array of servers",
    "url": "/services/haproxy/configuration/servers"
    "description": "Returns an array of all configured nameservers.",
    "title": "Return an array of nameservers",
    "url": "/services/haproxy/configuration/nameservers"
    "description": "Returns an array of all server templates that are configured in specified backend.",
    "title": "Return an array of server templates",
    "url": "/services/haproxy/configuration/server_templates"
    "title": "Return an array of all Server Switching Rules",
    "url": "/services/haproxy/configuration/server_switching_rules"

From this I can see that I want servers

admin@HAProxy:~$ curl -k -X GET   --user admin:adminpwd "https://172.16.1.2:5555/v2/services/haproxy/configuration/servers?parent_type=backend&parent_name=be_http" | jq -M .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    79  100    79    0     0  11570      0 --:--:-- --:--:-- --:--:-- 13166
{
  "_version": 16,
  "data": [
    {
      "address": "172.16.1.32",
      "name": "server_1",
      "port": 80
    }
  ]
}

To reverse the process I just pull up the docs - HAProxy Data Plane API

There’s an “example” tab so I can just take that and send it (or use my data from above).

admin@HAProxy:~$ curl -k -X POST \
  --user admin:adminpwd \
  -H "Content-Type: application/json" \
  -d '{
      "address": "172.16.1.33",
      "name": "server_2",
      "port": 80
    }' \
  "https://172.16.1.2:5555/v2/services/haproxy/configuration/servers?backend=be_http"
{"code":400,"message":"13: version or transaction not specified, specify only one"}

Notice that I changed from using ?parent_type=backend&parent_name=be_http to just ?backend=be_http. That’s just to illustrate the differences. That post should do the trick of creating a server and assigning it.

Oh but look I got an error! So check the reference doc and you’ll see “QUERY-STRING PARAMETERS” at the top. Notice that version is an option:

admin@HAProxy:~$ curl -k -X POST   --user admin:adminpwd   -H "Content-Type: application/json"   -d '{
      "address": "172.16.1.33",
      "name": "server_2",
      "port": 80
    }'   "https://172.16.1.2:5555/v2/services/haproxy/configuration/servers?backend=be_http&version=1"
{"code":409,"message":"15: version in configuration file is 16, given version is 1"}

I just tagged that variable “version” on the end and dang another error but fairly clear. A quick adjustment to the version string and I’m all set.

admin@HAProxy:~$ curl -k -X POST   --user admin:adminpwd   -H "Content-Type: application/json"   -d '{
      "address": "172.16.1.33",
      "name": "server_2",
      "port": 80
    }'   "https://172.16.1.2:5555/v2/services/haproxy/configuration/servers?backend=be_http&version=16"
{"address":"172.16.1.33","name":"server_2","port":80}

My config file now has this (I cut a few lines just to make it easier to read). So it created the server and assigned it.

backend be_http from unnamed_defaults_1
  server server_1 172.16.1.32:80
  server server_2 172.16.1.33:80

That’s how you can walk through the API and also use the reference to find what you need. I did a search for “version” and nothing showed up in the docs so I just jump on down to the root and start working through it:

admin@HAProxy:~$ curl -k -X GET   --user admin:adminpwd "https://172.16.1.2:5555/v2/"  | jq -M .
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  1259  100  1259    0     0   110k      0 --:--:-- --:--:-- --:--:--  111k
[
  {
    "description": "Return API, hardware and OS information",
    "title": "Return API, hardware and OS information",
    "url": "/info"
  },
  ...snip...

Ah that looks promising

admin@HAProxy:~$ curl -k -X GET   --user admin:adminpwd "https://172.16.1.2:5555/v2/info"  | jq -M
.
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    94  100    94    0     0  13599      0 --:--:-- --:--:-- --:--:-- 15666
{
  "api": {
    "build_date": "2024-01-02T12:00:36.000Z",
    "version": "v2.8.4-ee3 8182e868"
  },
  "system": {}
}

There’s a ton more to explore and play with but hopefully this gives you some insight into how you can leverage the docs and the API.

1 Like

Reverse engineering the HAPDPAPI!
It’s a good way to “build” the json indeed.
Thanks !

@Yosu_Cadilla Why not use one of the available Terraform providers to configure HAProxy, works like a charm fairly well-documented and simple to use Terraform Registry