Endurance

Node

An appliance in the cluster, its role, and the state it is in.

Conntrack

Get the appliance’s connection tracking settings: the table size, and how long the kernel keeps an idle flow per connection state. The timeouts are appliance-wide — they govern every flow on the box, not only balanced traffic — and are shared by every Cluster Node. The size is this node’s own.

GET /{applianceId}/system/conntrack

Path parameters
applianceId string Required
curl
curl -X GET "https://appliance.example.com/api/v1/{applianceId}/system/conntrack" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/{applianceId}/system/conntrack';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.get("https://appliance.example.com/api/v1/{applianceId}/system/conntrack", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/{applianceId}/system/conntrack', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Bruno
meta {
  name: Get the connection tracking settings of a node
  type: http
  seq: 1
}

get {
  url: https://{{node-0}}:{{port}}/api/v1/{applianceId}/system/conntrack
  body: none
  auth: bearer
}

auth:bearer {
  token: {{token}}
}
Response
{
  "status": "success",
  "message": "Connection tracking settings",
  "data": {
    "size": 10000,
    "tcpTimeout": "900",
    "tcpFinTimeout": "120",
    "udpTimeout": "300"
  }
}

Update the appliance’s connection tracking settings. A timeout may be given as a whole number of seconds or with a single unit — s, m, h, d, w — such as 900, 15m or 2h. Sub-second units are refused, and so are combinations such as 1h30m: give one unit at a time. What you send is what is stored and returned: 15m comes back as 15m, not as 900. Only size is required, so a timeout you omit keeps its current value. The TCP timeout interacts with Layer 4 persistence. On Source NAT and Destination NAT services a connection can outlive its persistence and keep working on its connection tracking entry alone; if it then idles past this timeout, the next packet is balanced afresh and may reach a different real server. The kernel’s own default is 432000 (5 days), so shortening it narrows that window — the mitigation is a longer persistence. Direct Routing services are unaffected.

PUT /{applianceId}/system/conntrack

This change is staged. Send PUT /services/apply to apply it.

Path parameters
applianceId string Required

.Body parameters

size integer Required

Connection tracking table size. This node only.

tcpTimeout string default: "900"

How long an established TCP connection may idle. 1s–31d. Shared by every Cluster Node.

tcpFinTimeout string default: "120"

How long a connection lingers after entering FIN-WAIT. 1s–31d. Shared by every Cluster Node.

udpTimeout string default: "300"

How long an idle UDP flow is kept, whether or not it has gone bidirectional. 1s–31d. Shared by every Cluster Node.

curl
curl -X PUT "https://appliance.example.com/api/v1/{applianceId}/system/conntrack" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "size": 0,
  "tcpTimeout": "900",
  "tcpFinTimeout": "120",
  "udpTimeout": "300"
}'
PHP
<?php

$url = 'https://appliance.example.com/api/v1/{applianceId}/system/conntrack';
$headers = [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json',
];

$payload = [
    'size' => 0,
    'tcpTimeout' => '900',
    'tcpFinTimeout' => '120',
    'udpTimeout' => '300',
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}
payload = {
    "size": 0,
    "tcpTimeout": "900",
    "tcpFinTimeout": "120",
    "udpTimeout": "300"
}

response = requests.put("https://appliance.example.com/api/v1/{applianceId}/system/conntrack", headers=headers, json=payload)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/{applianceId}/system/conntrack', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "size": 0,
  "tcpTimeout": "900",
  "tcpFinTimeout": "120",
  "udpTimeout": "300"
}),
});

const data = await response.json();
Bruno
meta {
  name: Update the connection tracking settings of a node
  type: http
  seq: 1
}

put {
  url: https://{{node-0}}:{{port}}/api/v1/{applianceId}/system/conntrack
  body: json
  auth: bearer
}

headers {
  Content-Type: application/json
}

auth:bearer {
  token: {{token}}
}

body:json {
  {
    "size": 0,
    "tcpTimeout": "900",
    "tcpFinTimeout": "120",
    "udpTimeout": "300"
  }
}
Response
{
  "status": "success",
  "message": "Set connection tracking settings",
  "data": {
    "size": 10000,
    "tcpTimeout": "15m",
    "tcpFinTimeout": "120",
    "udpTimeout": "300"
  }
}

Proxy

A stored password is never returned: password reads ** when one is stored and an empty string when none is.

GET /{applianceId}/system/proxy

Path parameters
applianceId string Required
curl
curl -X GET "https://appliance.example.com/api/v1/{applianceId}/system/proxy" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/{applianceId}/system/proxy';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.get("https://appliance.example.com/api/v1/{applianceId}/system/proxy", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/{applianceId}/system/proxy', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Bruno
meta {
  name: Get the system proxy settings
  type: http
  seq: 1
}

get {
  url: https://{{node-0}}:{{port}}/api/v1/{applianceId}/system/proxy
  body: none
  auth: bearer
}

auth:bearer {
  token: {{token}}
}
Response
{
  "status": "success",
  "message": "HTTP Proxy host",
  "data": {
    "enable": true,
    "address": {
      "value": null,
      "port": null
    },
    "username": "",
    "password": "",
    "bypass": [
      "idp.internal",
      "10.0.0.0/8"
    ]
  }
}

Update proxy

PUT /{applianceId}/system/proxy

This change is staged. Send PUT /services/apply to apply it.

Path parameters
applianceId string Required

.Body parameters

enable boolean Required
address object

Omitting this keeps the stored address, and null clears it. An enabled proxy needs one, sent or stored.

Fields
value string

The proxy’s IP address or hostname.

port integer
username string

Omitting this keeps the stored value, so a proxy can be re-enabled without resending it. An empty string or null clears it.

password string

Omitting this keeps the stored value, so a proxy can be re-enabled without resending it. An empty string or null clears it. Sending **, the mask a read returns, also keeps the stored value, and is refused when none is stored.

bypass array of string

Hosts reached directly while the proxy is enabled. An entry is a hostname, a bare domain (which also matches its subdomains), a leading-dot suffix, an IP address or a CIDR range. A port or a wildcard is rejected. Omitting this keeps the stored list, and an empty list or null clears it. A list sent replaces the stored one rather than adding to it.

curl
curl -X PUT "https://appliance.example.com/api/v1/{applianceId}/system/proxy" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "enable": true,
  "address": {
    "value": "<value>",
    "port": 0
  },
  "username": "<username>",
  "password": "<password>",
  "bypass": [
    "<bypass>"
  ]
}'
PHP
<?php

$url = 'https://appliance.example.com/api/v1/{applianceId}/system/proxy';
$headers = [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json',
];

$payload = [
    'enable' => true,
    'address' => [
        'value' => '<value>',
        'port' => 0,
    ],
    'username' => '<username>',
    'password' => '<password>',
    'bypass' => [
        '<bypass>',
    ],
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}
payload = {
    "enable": true,
    "address": {
        "value": "<value>",
        "port": 0
    },
    "username": "<username>",
    "password": "<password>",
    "bypass": [
        "<bypass>"
    ]
}

response = requests.put("https://appliance.example.com/api/v1/{applianceId}/system/proxy", headers=headers, json=payload)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/{applianceId}/system/proxy', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "enable": true,
  "address": {
    "value": "<value>",
    "port": 0
  },
  "username": "<username>",
  "password": "<password>",
  "bypass": [
    "<bypass>"
  ]
}),
});

const data = await response.json();
Bruno
meta {
  name: Update the system proxy settings
  type: http
  seq: 1
}

put {
  url: https://{{node-0}}:{{port}}/api/v1/{applianceId}/system/proxy
  body: json
  auth: bearer
}

headers {
  Content-Type: application/json
}

auth:bearer {
  token: {{token}}
}

body:json {
  {
    "enable": true,
    "address": {
      "value": "<value>",
      "port": 0
    },
    "username": "<username>",
    "password": "<password>",
    "bypass": [
      "<bypass>"
    ]
  }
}
Response
{
  "status": "success",
  "message": "Set HTTP Proxy"
}

User interface

Get the User Interface settings, the SSH settings and whether Console Access (a login shell for the loadbalancer OS user) is on. consoleEnabled is read from the OS each time, and the console password is never returned.

GET /{applianceId}/system/userinterface

Path parameters
applianceId string Required
curl
curl -X GET "https://appliance.example.com/api/v1/{applianceId}/system/userinterface" \
  -H "Authorization: Bearer $TOKEN"
PHP
<?php

$url = 'https://appliance.example.com/api/v1/{applianceId}/system/userinterface';
$headers = [
    'Authorization: Bearer ' . $token,
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'GET',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}

response = requests.get("https://appliance.example.com/api/v1/{applianceId}/system/userinterface", headers=headers)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/{applianceId}/system/userinterface', {
  method: 'GET',
  headers: {
    Authorization: `Bearer ${token}`,
  },
});

const data = await response.json();
Bruno
meta {
  name: Get the WebUI settings
  type: http
  seq: 1
}

get {
  url: https://{{node-0}}:{{port}}/api/v1/{applianceId}/system/userinterface
  body: none
  auth: bearer
}

auth:bearer {
  token: {{token}}
}
Response
{
  "status": "success",
  "message": "User Interface details",
  "data": {
    "apiPort": 9443,
    "ipId": "5e1db550eb4f2",
    "SSLCertificate": "5e1db550eb565",
    "sshPort": 22,
    "sshEnabled": true,
    "consoleEnabled": true
  }
}

Update the User Interface settings, the SSH settings and Console Access (a login shell for the loadbalancer OS user). Fields other than apiPort keep their current value when omitted. Console Access changes apply immediately; the other fields wait for the pending changes to be applied. Switching Console Access on needs a consolePassword. While it is on, a consolePassword changes the password and leaving it out changes nothing. Switching it off removes the shell and replaces the password with a random one. A password must be 8 to 128 characters long and contain an upper-case letter, a lower-case letter, a digit and a symbol. This update works without a valid licence, so that an administrator can still reach the shell of an unlicensed appliance. While PUT /{applianceId}/system/console is deprecated, sending consoleEnabled or consolePassword also needs permission for that route, and is refused with a 403 without it. Refused while a transaction is open. Commit or roll back the transaction first.

PUT /{applianceId}/system/userinterface

This change is staged. Send PUT /services/apply to apply it.

Path parameters
applianceId string Required

.Body parameters

ipId string

The id of the Service IP the WebUI and API listen on

apiPort integer Required
SSLCertificate string

The id of the certificate the WebUI and API serve

sshEnabled boolean
sshPort integer
consoleEnabled boolean

Whether the loadbalancer OS user has a login shell. Omit it to leave Console Access as it is. Absent from a response when the appliance could not read it.

consolePassword string

The loadbalancer OS user’s password. Required when switching Console Access on, and refused while it stays off. Sent without consoleEnabled, it changes the password of a console that is on. Never stored or returned.

curl
curl -X PUT "https://appliance.example.com/api/v1/{applianceId}/system/userinterface" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "ipId": "<ipId>",
  "apiPort": 0,
  "SSLCertificate": "<SSLCertificate>",
  "sshEnabled": true,
  "sshPort": 0,
  "consoleEnabled": true,
  "consolePassword": "<consolePassword>"
}'
PHP
<?php

$url = 'https://appliance.example.com/api/v1/{applianceId}/system/userinterface';
$headers = [
    'Authorization: Bearer ' . $token,
    'Content-Type: application/json',
];

$payload = [
    'ipId' => '<ipId>',
    'apiPort' => 0,
    'SSLCertificate' => '<SSLCertificate>',
    'sshEnabled' => true,
    'sshPort' => 0,
    'consoleEnabled' => true,
    'consolePassword' => '<consolePassword>',
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
]);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);
Python
import requests

headers = {"Authorization": f"Bearer {token}"}
payload = {
    "ipId": "<ipId>",
    "apiPort": 0,
    "SSLCertificate": "<SSLCertificate>",
    "sshEnabled": true,
    "sshPort": 0,
    "consoleEnabled": true,
    "consolePassword": "<consolePassword>"
}

response = requests.put("https://appliance.example.com/api/v1/{applianceId}/system/userinterface", headers=headers, json=payload)
response.raise_for_status()
print(response.json())
JavaScript
const response = await fetch('https://appliance.example.com/api/v1/{applianceId}/system/userinterface', {
  method: 'PUT',
  headers: {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "ipId": "<ipId>",
  "apiPort": 0,
  "SSLCertificate": "<SSLCertificate>",
  "sshEnabled": true,
  "sshPort": 0,
  "consoleEnabled": true,
  "consolePassword": "<consolePassword>"
}),
});

const data = await response.json();
Bruno
meta {
  name: Update the WebUI settings
  type: http
  seq: 1
}

put {
  url: https://{{node-0}}:{{port}}/api/v1/{applianceId}/system/userinterface
  body: json
  auth: bearer
}

headers {
  Content-Type: application/json
}

auth:bearer {
  token: {{token}}
}

body:json {
  {
    "ipId": "<ipId>",
    "apiPort": 0,
    "SSLCertificate": "<SSLCertificate>",
    "sshEnabled": true,
    "sshPort": 0,
    "consoleEnabled": true,
    "consolePassword": "<consolePassword>"
  }
}
Response
{
  "status": "success",
  "message": "Set User Interface",
  "data": {
    "apiPort": 9443,
    "ipId": "5e1db550eb4f2",
    "SSLCertificate": "5e1db550eb565",
    "sshPort": 22,
    "sshEnabled": true,
    "consoleEnabled": true
  }
}