Admin API: reverse proxy nodes and Cloudflare
Seven Admin API methods: list, add, check and delete reverse proxy nodes and the Cloudflare accounts the tracker uses to change the A records of domains.
The API offers the same actions as the Reverse proxy nodes section of the panel: add a node, check it, delete it, connect and disconnect a Cloudflare account. All methods require a token with Full access («Полный доступ») (full). Authorization is described on the Admin API: overview and authorization page, and the request and error format on the Request, response and error format page.
General rules
- Records belong to the team: a token sees and changes only the nodes and accounts of its own team.
- Neither nodes nor Cloudflare accounts have an edit method. To change the parameters, delete the record and create a new one.
- The lists have no pagination and no filters.
- The SSH password and the Cloudflare token are accepted only on creation. No method returns them.
- If the address contains a value that is not a UUID in place of
{id}, the response is400with codebad_requestand the messageнекорректный идентификатор или значение(invalid ID or value). - When the license is inactive, the methods respond
402— see Expired license.
Pointing domains to a node is done by separate methods, POST /api/v1/domains/{id}/route and POST /api/v1/domains/route-bulk; they are described on the Admin API: domains page.
Reverse proxy nodes
Node object
| Field | Type | Description |
|---|---|---|
id | string, UUID | Node ID |
workspace_id | string, UUID | Team ID |
label | string | Node name |
ip | string | IPv4 address of the node |
ssh_port | number | SSH port |
ssh_user | string | SSH user |
status | string | State: new, provisioning, ready or error |
last_error | string | Text of the last error. The field is absent if there were no errors or a successful check came after the error |
last_seen | string, RFC 3339 date | Time of the last successful setup or check. The field is absent until the setup is complete |
created_at | string, RFC 3339 date | Time the node was added |
host_key_fingerprint | string | Fingerprint of the node's SSH key, like SHA256:…. Present only in the list and only after a successful setup |
status values:
| Value | In the panel | Meaning |
|---|---|---|
new | “new” («новая») | The node is created, the setup has not started |
provisioning | “setting up…” («настройка…») | The tracker is setting up the node over SSH |
ready | “ready” («готова») | Domains can be pointed to the node |
error | “error” («ошибка») | The setup failed or the node stopped responding. The reason is in last_error |
List nodes
GET /api/v1/proxy-nodesReturns all of the team's nodes.
Token scope: full. There are no parameters.
Response — code 200 and an array of node objects. The newest nodes come first. If there are no nodes, you get an empty array [].
[
{
"id": "5d2f8c14-9a3b-4e7d-b1c6-0f8e7d6c5b4a",
"workspace_id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
"label": "DE-1",
"ip": "203.0.113.10",
"ssh_port": 22,
"ssh_user": "root",
"status": "ready",
"last_seen": "2026-10-04T09:15:42.118204Z",
"created_at": "2026-10-04T09:14:10.552871Z",
"host_key_fingerprint": "SHA256:Zk3v0q1mYb7Qe2xL9aHn4TtR8sWc5uJd6oPfGiK1lMw"
}
]Add a node
POST /api/v1/proxy-nodesCreates a node and starts setting it up over SSH. Server requirements are listed on the Reverse proxy nodes page.
Token scope: full. The body is a JSON object:
| Field | Type | Required | Description |
|---|---|---|---|
ip | string | yes | IPv4 address of the server, for example 203.0.113.10. IPv6 addresses and host names are not accepted |
ssh_password | string | yes | Password of the SSH user. It is used once during the setup and is not stored |
label | string | no | Node name. Spaces at the edges are trimmed. Without it, the IP becomes the name |
ssh_port | integer | no | SSH port. The default is 22; the value 0 also means 22 |
ssh_user | string | no | SSH user. The default is root |
expected_host_key | string | no | Fingerprint of the server's SSH key in SHA256 format, with or without the SHA256: prefix. If the server's fingerprint is different, the password is not sent and the setup ends with an error |
Response — code 201:
| Field | Type | Description |
|---|---|---|
item | object | The created node, status is provisioning |
origin_hint | string | Hint text in Russian that the panel shows after the node is added |
The setup runs in the background, with up to 3 minutes allotted to it. The response comes immediately and does not contain the setup result. Request the node list and wait until status changes to ready or error. After ready, wait about a minute: the tracker server will start accepting requests from this node on its own.
Errors:
| Code | code | message | When |
|---|---|---|---|
400 | bad_request | invalid json | The body is not a JSON object |
422 | validation | ip и ssh_password обязательны (ip and ssh_password are required) | One of the required fields was not passed |
422 | validation | ip должен быть IPv4-адресом ноды (ip must be the IPv4 address of the node) | ip is not an IPv4 address |
422 | validation | expected_host_key: ожидается SHA256-отпечаток host-key ноды… (a SHA256 fingerprint of the node's host key is expected) | The expected_host_key value does not look like a SHA256 fingerprint |
503 | disabled | depends on the reason | Reverse proxy nodes are not configured on the installation — see When the feature is disabled |
Errors of the setup itself — a wrong password, an unreachable server, a fingerprint mismatch — do not get into the response. They are written to the node's last_error, and the node gets the error status. The texts are explained on the Reverse proxy nodes page.
Example request:
curl -X POST https://panel.example.com/api/v1/proxy-nodes \
-H "Api-Key: <token>" \
-H "Content-Type: application/json" \
-d '{"label":"DE-1","ip":"203.0.113.10","ssh_port":22,"ssh_user":"root","ssh_password":"<SSH password>"}'Check a node
POST /api/v1/proxy-nodes/{id}/healthConnects to the node over SSH with the saved key and checks that the web server on it is running. The check takes up to 25 seconds.
Token scope: full. There is no request body. {id} in the address is the node ID from the list.
Response — code 200 in both cases, the result is in the status field:
| Field | Type | Description |
|---|---|---|
status | string | ready — the node responded, error — the check failed |
error | string | Error text. Present only when status = error |
{"status": "ready"}On success, the node's last_seen is updated, its status becomes ready, and last_error is cleared. On failure, the error text with the ручная проверка: (manual check:) prefix is written to last_error, and the status of the node itself does not change. Automatic node monitoring and moving domains are described on the Reverse proxy nodes page.
Errors:
| Code | code | message | When |
|---|---|---|---|
400 | bad_request | некорректный идентификатор или значение (invalid ID or value) | {id} is not a UUID |
404 | not_found | resource not found | There is no node with this ID |
422 | not_provisioned | нода ещё не провижена (the node is not provisioned yet) | The node setup has not finished yet or has failed |
503 | disabled | NODE_ENC_KEY не задан (NODE_ENC_KEY is not set) | Reverse proxy nodes are not configured on the installation |
Example request:
curl -X POST https://panel.example.com/api/v1/proxy-nodes/5d2f8c14-9a3b-4e7d-b1c6-0f8e7d6c5b4a/health \
-H "Api-Key: <token>"Delete a node
DELETE /api/v1/proxy-nodes/{id}Deletes the node from the tracker and unbinds its domains.
Token scope: full. There is no request body. {id} in the address is the node ID from the list.
Response — code 204 with no body.
If there is no node with this ID or it has already been deleted, the response is 404 with code not_found.
DNS records in Cloudflare do not change on deletion. Domains that point to the IP of the deleted node will stop opening. Point them to another node first.
Cloudflare accounts
An account is a saved Cloudflare API token. Through it, the tracker sets a domain's A record to the node's IP. The permissions the token needs and what the tracker does in DNS are described on the Working with Cloudflare page.
Account object
| Field | Type | Description |
|---|---|---|
id | string, UUID | Account ID |
label | string | Name |
created_at | string, RFC 3339 date | Time the account was added |
List accounts
GET /api/v1/cf-accountsReturns the team's connected Cloudflare accounts, without tokens.
Token scope: full. There are no parameters.
Response — code 200 and an array of account objects in the order they were added. If there are no accounts, you get an empty array [].
Connect an account
POST /api/v1/cf-accountsChecks the Cloudflare token by requesting the list of zones and saves it.
Token scope: full. The body is a JSON object:
| Field | Type | Required | Description |
|---|---|---|---|
token | string | yes | Cloudflare API token |
label | string | no | Name. Without it, the name becomes Cloudflare (N зон) (N zones), where N is the number of zones available to the token |
Response — code 201:
| Field | Type | Description |
|---|---|---|
item | object | The created account |
zones | number | How many zones are available to the token |
Errors:
| Code | code | message | When |
|---|---|---|---|
422 | validation | token обязателен (token is required) | The token field is empty or consists of spaces, or the body is not a JSON object |
422 | cf_error | токен не прошёл проверку: … (the token failed the check: …) | Cloudflare did not return the list of zones for this token. The reason follows the colon |
503 | disabled | шифрование не настроено: задайте NODE_ENC_KEY (encryption is not configured: set NODE_ENC_KEY) | Reverse proxy nodes are not configured on the installation |
Example request:
curl -X POST https://panel.example.com/api/v1/cf-accounts \
-H "Api-Key: <token>" \
-H "Content-Type: application/json" \
-d '{"label":"Main account","token":"<Cloudflare API token>"}'Disconnect an account
DELETE /api/v1/cf-accounts/{id}Deletes the saved Cloudflare token.
Token scope: full. There is no request body. {id} in the address is the account ID from the list.
Response — code 204 with no body. DNS records in Cloudflare do not change. The tracker will no longer be able to point the domains of this account to nodes.
If there is no account with this ID or it has already been deleted, the response is 404 with code not_found.
When the feature is disabled
Code 503 with code = disabled means that the reverse proxy node parameters are not set on the tracker server: NODE_ENC_KEY or NODE_ORIGIN_HOST. The installer writes both parameters itself, so this response does not appear on an installation deployed according to the Installation page.
When a node is added, the text in message depends on which parameter is missing:
фича прокси-нод выключена: задайте NODE_ENC_KEY (openssl rand -hex 32)(the proxy node feature is off: set NODE_ENC_KEY);NODE_ORIGIN_HOST не задан (адрес origin для нод)(NODE_ORIGIN_HOST is not set — the origin address for the nodes).
The lists and deletion work without these parameters too: GET and DELETE do not return disabled.