Table of contents
- Creating a cluster
- Creating an agent
- Creating a node
- Easy ZoneCloud configuration for agents/nodes
- Creating a user
- Excluding a zone
- Removing a zone exclusion
- Changing timezone
- Webhook notifications
- External API Access
Creating a cluster #
Navigate to Clusters and press the “Create cluster” button.
Give your new cluster a name press the “Create” button.
Creating an agent #
Navigate to “Servers” and press the “Create Server” button.
Fill in the required fields and press “Save”.
Server name: could be the hostname of the server, unique for each agent
Server token: will be used in the agent’s configuration file, press the “GENERATE” button to create a random one
IP: The server’s IP
Agent selection active
Cluster: Select the appropriate cluster from the list
Navigating back to the Servers page, you should see the newly created server/agent.
Creating a node #
Navigate to “Servers” and press the “Create Server” button.
Fill in the required fields and press “Save”.
Server name: could be the hostname of the server, unique for each agent
Server token: will be used in the nodes’s configuration file, press the “GENERATE” button to create a random one
IP: The server’s IP
Node selection active
Cluster: Select the appropriate cluster from the list
Navigating back to the Servers page, you should see the newly created server/node.
Easy ZoneCloud configuration for agents/nodes #
Navigate to “Servers” and press the “Configuration” button for the agent/node you want to setup.
You can copy-paste the configurations on your agent/node.
e.g.:
Creating a user #
Navigate to Users and press the “CREATE USER” button.
Fill in the appropriate fields and press “Create”.
Excluding a zone #
If for some reason you want a zone to not be served by an agent, all you have to do is navigate to Zones page and press the “Exclude” button.
Removing a zone exclusion #
Navigate to Zones page and locate the zone on the “Excluded zones” table.
Press the “Remove exclusion” button.
Changing timezone #
The time zone can be set on the .env
file:
APP_TIMEZONE='Europe/Athens'
Webhook notifications support #
Under the Settings page you can find “Webhook notifications settings”.
From there you can set a URL and enable webhook notifications for:
- Zone action logs (insert, delete, exclude, remove exclude)
- Agents or Nodes going offline
The controller sends a JSON payload for these notifications.
The payloads have the following format:
For zone action logs:
{ "report": { "message": "Zone: test.zonecloud.io Action: remove exclude Server: server1 Timestamp: 2025-09-17 11:51:37\r\nZone: test.zonecloud.io Action: exclude Server: server2 Timestamp: 2025-09-17 11:51:39\r\n", "logs": [ { "timestamp": "2025-09-17 11:51:37", "action": "remove exclude", "zone": "test.zonecloud.io", "server_name": "server1" }, { "timestamp": "2025-09-17 11:51:39", "action": "exclude", "zone": "test.zonecloud.io", "server_name": "server2" } ] } }
For servers going offline:
{ "report": { "message": "Server server1 (X.X.X.X) from cluster dev is offline since 2025-09-17 09:50:59.\r\nServer server2 (Y.Y.Y.Y) from cluster dev is offline since 2025-09-17 09:50:59.\r\n", "errors": { "offline_servers": [ { "name": "server1", "last_login": "2025-09-17 09:50:59", "IP": "X.X.X.X", "zones_count": 5, "version": "2.9.5" }, { "name": "server2", "last_login": "2025-09-17 09:50:59", "IP": "Y.Y.Y.Y", "zones_count": 2, "version": "2.9.0" } ] } } }
Verifying signature #
You’ll notice that each of these webhook notifications appends an HTTP header with the name ‘signature’ and a string value.
The value is the hash of the payload and a predefined secret string using the sha256 algorithm.
You can verify that the notification is really coming from you by simply running the same hash algorithm against the payload.
The default secret is the string “zcloud”. You can customize it in your .env file by adding a WEBHOOK_SECRET=MYSECRET line.
In PHP’s terms this would be:
hash_hmac('sha256', $payload, 'MYSECRET');
External API Access #
Token authorization #
To allow an external application to interact with ZoneCloud Controller’s API, you need to create an access token.
You can do this from the App API Access page.
From this page you can create new tokens or revoke existing ones.
Endpoints #
POST /api/check_zone_active #
Parameter name | Value |
zone | Required The zone name to be checked if it is active |
cluster | Optional The cluster name to search for the zone |
extra_info | Optional Value = 1 Appends “active_in” and “excluded_in” info for the zone where applicable. |
Result | Output (JSON) |
Zone is active | {"active":true} |
Zone is active (with extra_info=1) | {"active":true,"active_in":["server1"]} |
Zone is not active | {"active":false} |
Authorization header missing/invalid | {"message":"Authorization token missing\/invalid."} |
Wrong cluster name | {"active":false,"message":"No such cluster"} |
Missing zone parameter | {"message":"No zone given as parameter."} |
curl examples:
curl https://<controller_hostname>/api/check_zone_active -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=test1.com" {"active":true} curl https://<controller_hostname>/api/check_zone_active -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=test-inactive1.com" {"active":false} curl https://<controller_hostname>/api/check_zone_active -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=test1.com&extra_info=1" {"active":true,"active_in":["server1"]}
POST /api/exclude-zone #
Exclude a zone from an agent.
Parameter name | Value |
zone | Required The zone name to exclude |
server_name | Required The agent’s name to exclude the zone from |
Result | Output (JSON) |
Zone is excluded | {"result":true,"message":"Zone excluded from server."} |
Server not found | {"result":false,"message":"Can't find an agent with such name."} |
Zone not found in agent | {"result":false,"message":"Can't find a zone with such name\/agent name."} |
Authorization header missing/invalid | {"message":"Authorization token missing\/invalid."} |
Missing zone/server_name parameter | {"result":false,"message":"Missing \"zone\" and\/or \"server_name\" parameter."}
|
curl examples:
curl https://<controller_hostname>/api/exclude-zone -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=test1.com&server_name=demo1" {"result":true,"message":"Zone excluded from server."} curl https://<controller_hostname>/api/exclude-zone -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=test1.com&server_name=non_existing" {"result":false,"message":"Can't find an agent with such name."} curl https://<controller_hostname>/api/exclude-zone -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=not-existing-zone.com&server_name=demo1" {"result":false,"message":"Can't find a zone with such name\/agent name."}
POST /api/remove-exclude-zone #
Remove a zone exclusion from an agent.
Parameter name | Value |
zone | Required The zone name to remove exclusion |
server_name | Required The agent’s name to remove exclusion of zone from |
Result | Output (JSON) |
Zone exclusion removed | {"result":true,"message":"Zone exclusion removed from server."} |
Server not found | {"result":false,"message":"Can't find an agent with such name."} |
Zone not found in agent | {"result":false,"message":"Can't find a zone with such name\/agent name."} |
Authorization header missing/invalid | {"message":"Authorization token missing\/invalid."} |
Missing zone/server_name parameter | {"result":false,"message":"Missing \"zone\" and\/or \"server_name\" parameter."}
|
curl examples:
curl https://<controller_hostname>/api/remove-exclude-zone -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=test1.com&server_name=demo1" {"result":true,"message":"Zone exclusion removed from server."} curl https://<controller_hostname>/api/remove-exclude-zone -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=test1.com&server_name=non_existing" {"result":false,"message":"Can't find an agent with such name."} curl https://<controller_hostname>/api/remove-exclude-zone -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" -X POST --data "zone=not-existing-zone.com&server_name=demo1" {"result":false,"message":"Can't find a zone with such name\/agent name."}
GET /api/get-duplicate-zones #
Responds with duplicate zones along with a list of the servers that the zone is active in.
Takes no parameters.
curl exapmles:
curl -s https://<controller_hostname>/api/get-duplicate-zones -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" | jq [ { "zone": "test0.com", "server_id": 30, "cluster_id": 6, "count": 2, "server_name": "demo1", "duplicate_servers": [ { "name": "demo1", "id": 30 }, { "name": "demo3", "id": 32 } ], "excluded_in": 0, "excluded_server_count": 0, "not_excluded_server_count": 2 } ]
GET /api/zones{/group?} #
Responds with a list of zones along with some info for each zone.
You can group the zones by server if you append /by-server in the url
curl exapmles:
curl -s https://<controller_hostname>/api/zones -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" | jq [ { "zone": "domain1.com", "owner": "user1", "insert_date": "2022-03-30 10:24:20", "excluded": null, "server_name": "server1" }, { "zone": "domain2.com", "owner": "user2", "insert_date": "2022-03-30 10:24:20", "excluded": null, "server_name": "server2" }, ]
curl -s https://<controller_hostname>/api/zones/by-server -H "Authorization: dEYmHvuoSiwQJATTF2y8fiAfZ9N887b" | jq { "server1": [ { "zone": "domain1.com", "owner": "user1", "insert_date": "2022-03-30 10:24:20", "excluded": null } ], "server2": [ { "zone": "domain2.com", "owner": "user2", "insert_date": "2022-03-30 10:24:20", "excluded": null } ] }