Replication¶
MySQL primary/replica configuration across multiple panel-managed servers.
All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.
Endpoint count: 10
Endpoints¶
| Method | Path | Handler | Guards |
|---|---|---|---|
DELETE |
/api/replication-servers/:id |
deleteReplicationServer |
RequirePermission(db, "plugins_management") |
PUT |
/api/replication-servers/:id |
updateReplicationServer |
RequirePermission(db, "plugins_management") |
DELETE |
/api/replication-servers/:id/action-log |
clearReplicationActionLog |
RequirePermission(db, "plugins_management") |
GET |
/api/replication-servers/:id/action-log |
getReplicationActionLog |
RequirePermission(db, "plugins_management") |
POST |
/api/replication-servers/:id/action-log/:action_id/retry |
retryReplicationAction |
RequirePermission(db, "plugins_management") |
GET |
/api/replication-servers/:id/categories |
getReplicationCategories |
RequirePermission(db, "plugins_management") |
PUT |
/api/replication-servers/:id/categories |
updateReplicationCategories |
RequirePermission(db, "plugins_management") |
PATCH |
/api/replication-servers/:id/categories/:category |
updateReplicationCategory |
RequirePermission(db, "plugins_management") |
POST |
/api/replication-servers/:id/test |
testReplicationServer |
RequirePermission(db, "plugins_management") |
POST |
/api/replication-servers/:id/toggle |
toggleReplicationServer |
RequirePermission(db, "plugins_management") |
Source¶
Handlers for this section live in api/routes/handlers_*.go in the StarkOne source. Each handler binds its request body with gin.ShouldBindJSON(&req) and responds with the standard envelope:
On error:
Reference¶
DELETE /api/replication-servers/:id¶
Deletes a replication server, but only if no website replications still reference it.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | One or more website replications still use this server (response carries a message like Cannot delete: N replications use this server; no code field). |
Side effects
- Deletes the matching row from the
replication_serverstable.
Example
curl -X DELETE https://panel.example.com:2087/api/replication-servers/3 \
-H "Authorization: Bearer $TOKEN"
PUT /api/replication-servers/:id¶
Updates the editable fields of a replication server; only the non-empty fields supplied in the body are changed.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Request body
{
"name": "string (optional)",
"host": "string (optional)",
"port": "int (optional)",
"api_key": "string (optional)"
}
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | no | New display name. Applied only when non-empty. |
host |
string | no | New hostname/IP. Applied only when non-empty. |
port |
int | no | New port. Applied only when greater than 0. |
api_key |
string | no | New API key for authenticating to the remote panel. Applied only when non-empty. |
No field carries binding:"required". However, at least one effective field must be provided or the request is rejected.
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Request body could not be parsed (message holds the bind error). |
400 |
- | No usable fields supplied (message: No fields to update). |
500 |
- | Database update failed. |
Side effects
- Updates the matching row in
replication_servers, includingupdated_at = datetime('now').
Example
curl -X PUT https://panel.example.com:2087/api/replication-servers/3 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"host": "203.0.113.20", "port": 2087}'
DELETE /api/replication-servers/:id/action-log¶
Clears action-log entries for a server; by default only completed rows (success, or failed with retry_count >= 3), or all rows when ?all=true.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Query parameters
| Name | Type | Optional | Description |
|---|---|---|---|
all |
string | yes | When set to true, deletes every action-log row for the server. Otherwise only success rows and exhausted failures (retry_count >= 3) are removed. |
Response - 200 OK
deleted is the number of rows removed.
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
- | Database delete failed. |
Side effects
- Deletes rows from
replication_action_logfor the given server.
Example
curl -X DELETE "https://panel.example.com:2087/api/replication-servers/3/action-log?all=true" \
-H "Authorization: Bearer $TOKEN"
GET /api/replication-servers/:id/action-log¶
Returns recent forwarded actions for a server, newest first, with optional filtering by category and status.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Query parameters
| Name | Type | Optional | Description |
|---|---|---|---|
limit |
int | yes | Max rows to return. Defaults to 50; only honored when in the range 1-500, otherwise the default applies. |
category |
string | yes | Filter to a single replication category. |
status |
string | yes | Filter by action status (e.g. success, failed, pending). |
Response - 200 OK
{
"data": [
{
"id": 101,
"server_id": 3,
"category": "dns",
"method": "POST",
"endpoint": "/dns/zones",
"request_body": "{...}",
"status": "failed",
"response_code": 500,
"error_message": "connection refused",
"retry_count": 1,
"created_at": "2026-06-17 10:00:00",
"completed_at": ""
}
]
}
On a query error the handler returns 200 OK with an empty data array rather than an error status.
Example
curl "https://panel.example.com:2087/api/replication-servers/3/action-log?status=failed&limit=100" \
-H "Authorization: Bearer $TOKEN"
POST /api/replication-servers/:id/action-log/:action_id/retry¶
Re-attempts a single action-log entry by re-forwarding the stored request to the remote server and updating the log row with the outcome.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
action_id |
string | The action-log entry ID to retry (must belong to this server). |
Response - 200 OK
On success:
On a failed retry (still 200 OK):
Errors
| Status | Code | Meaning |
|---|---|---|
404 |
- | No matching action-log entry for this server (message: Action not found). |
Side effects
- Sends the stored HTTP request (method + endpoint + body) to the remote replication server via
doForwardRequest. - Updates the
replication_action_logrow: on success setsstatus = 'success', clearserror_message, setsresponse_codeandcompleted_at; on failure setsstatus = 'failed', storesresponse_codeanderror_message.retry_countis incremented either way.
Example
curl -X POST https://panel.example.com:2087/api/replication-servers/3/action-log/101/retry \
-H "Authorization: Bearer $TOKEN"
GET /api/replication-servers/:id/categories¶
Returns the full list of known replication categories for a server, each marked enabled or disabled.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Response - 200 OK
Every known category is returned (categories without a stored row default to enabled: false). The known categories are: websites, dns, ssl, aliases, databases, firewall, users, ssh_keys, crontab, php, settings, services, ftp, waf, varnish, rate_limit, plugins, limits, nginx_acl, performance, webapp_backups.
{
"data": [
{ "category": "websites", "enabled": true },
{ "category": "dns", "enabled": false }
]
}
Errors
| Status | Code | Meaning |
|---|---|---|
404 |
- | Server not found (message: Server not found). |
Example
curl https://panel.example.com:2087/api/replication-servers/3/categories \
-H "Authorization: Bearer $TOKEN"
PUT /api/replication-servers/:id/categories¶
Performs a bulk upsert of category enabled/disabled flags for a server; unknown category keys are silently skipped.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
categories |
object (map of string→bool) | no (no binding tag) |
Map of category name to enabled flag. Keys not in the known-category list are ignored. |
Response - 200 OK
updated counts the recognized categories that were upserted.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Request body could not be parsed (message holds the bind error). |
404 |
- | Server not found (message: Server not found). |
500 |
- | Transaction start, upsert, or commit failed. |
Side effects
- Upserts rows in
replication_categoriesinside a transaction. - If the
websiteskey is present, spawns a background request to lock/unlock website creation on the remote server (POST /api/settings/website-creation-lock).
Example
curl -X PUT https://panel.example.com:2087/api/replication-servers/3/categories \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"categories": {"websites": true, "dns": false}}'
PATCH /api/replication-servers/:id/categories/:category¶
Toggles a single replication category on or off for a server.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
category |
string | The category to toggle. Must be one of the known categories. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
bool | no (no binding tag) |
Whether the category should be enabled. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Unknown category (message: Unknown category). |
400 |
- | Request body could not be parsed (message holds the bind error). |
404 |
- | Server not found (message: Server not found). |
500 |
- | Database upsert failed. |
Side effects
- Upserts a single row in
replication_categories. - When the toggled category is
websites, spawns a background request to lock/unlock website creation on the remote server.
Example
curl -X PATCH https://panel.example.com:2087/api/replication-servers/3/categories/websites \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled": true}'
POST /api/replication-servers/:id/test¶
Tests connectivity to a replication server by calling its /api/version endpoint, then stores the result on the server record.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Response - 200 OK
status is active when the remote returns HTTP 200, otherwise error with message describing the failure (transport error or Status <code>).
Errors
| Status | Code | Meaning |
|---|---|---|
404 |
- | Server not found (message: Server not found). |
Side effects
- Makes an outbound HTTPS GET to
https://<host>:<port>/api/version(TLS verification disabled, 10s timeout), sending the stored API key as a bearer token when present. - Updates the server row's
statusandlast_check.
Example
curl -X POST https://panel.example.com:2087/api/replication-servers/3/test \
-H "Authorization: Bearer $TOKEN"
POST /api/replication-servers/:id/toggle¶
Enables or disables a replication server (sets its status) without deleting it.
Guards: RequirePermission(db, "plugins_management")
Path parameters
| Name | Type | Description |
|---|---|---|
id |
string | The replication server ID. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
bool | no (no binding tag) |
true sets status to active; false sets status to disabled. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Request body could not be parsed (message holds the bind error). |
500 |
- | Database update failed. |
Side effects
- Updates the server row's
statusandupdated_at.
Example