Settings¶
Server-wide settings: PHP versions, mail relay, timezone, MySQL remote access, backups, Cloudflare, web server choice.
All endpoints below are mounted under /api. Authentication: Authorization: Bearer <token> unless noted as public.
Endpoint count: 37
Endpoints¶
| Method | Path | Handler | Guards |
|---|---|---|---|
POST |
/api/settings/backup/disable-encryption |
disableBackupEncryption |
RequireSuperuser() |
POST |
/api/settings/backup/generate-key |
generateBackupKey |
RequireSuperuser() |
POST |
/api/settings/backup/get-key |
getBackupKey |
RequireSuperuser() |
POST |
/api/settings/backup/test-s3 |
testBackupS3 |
RequireSuperuser() |
POST |
/api/settings/backup/webapp-restore |
restoreWebappBackup |
RequireSuperuser() |
POST |
/api/settings/backup/webapp-restore-all |
restoreAllWebappBackups |
RequireSuperuser() |
GET |
/api/settings/backup/webapp-restore-progress |
getWebappRestoreProgress |
RequireSuperuser() |
GET |
/api/settings/backup/webapp-scan |
scanWebappBackups |
RequireSuperuser() |
GET |
/api/settings/mail |
getMailSettings |
RequireSuperuser() |
POST |
/api/settings/mail |
setMailSettings |
RequireSuperuser() |
GET |
/api/settings/mysql |
getMySQLSettings |
RequireSuperuser() |
POST |
/api/settings/mysql/max-connections |
setMySQLMaxConnections |
RequireSuperuser() |
POST |
/api/settings/mysql/port |
setMySQLPort |
RequireSuperuser() |
POST |
/api/settings/mysql/read-only |
setMySQLReadOnly |
RequireSuperuser() |
POST |
/api/settings/mysql/remote |
setMySQLRemote |
RequireSuperuser() |
POST |
/api/settings/mysql/replication/restart |
restartReplication |
RequireSuperuser() |
POST |
/api/settings/mysql/replication/skip-error |
skipReplicationError |
RequireSuperuser() |
POST |
/api/settings/mysql/slave-skip-errors |
setSlaveSkipErrors |
RequireSuperuser() |
GET |
/api/settings/php-security |
getPHPSecuritySettings |
RequireSuperuser() |
POST |
/api/settings/php-security |
setPHPSecuritySettings |
RequireSuperuser() |
GET |
/api/settings/php/:version/config |
getPHPConfig |
RequireSuperuser() |
POST |
/api/settings/php/:version/config |
setPHPConfig |
RequireSuperuser() |
GET |
/api/settings/php/available |
getAvailablePHPVersions |
RequireSuperuser() |
POST |
/api/settings/php/install |
installPHPVersion |
RequireSuperuser() |
POST |
/api/settings/php/remove |
removePHPVersion |
RequireSuperuser() |
POST |
/api/settings/remote-logging |
saveRemoteLogging |
RequireSuperuser() |
GET |
/api/settings/server-name |
getServerName |
AuthWithDB(cfg.JWTSecret, db) |
POST |
/api/settings/server-name |
middleware |
AuthWithDB(cfg.JWTSecret, db) |
GET |
/api/settings/server-timezone |
getServerTimezone |
RequireSuperuser() |
POST |
/api/settings/server-timezone |
setServerTimezone |
RequireSuperuser() |
POST |
/api/settings/ssh-audit/forward |
setSSHAuditForward |
RequireSuperuser() |
GET |
/api/settings/ssh-audit/logs |
getSSHAuditLogs |
RequireSuperuser() |
POST |
/api/settings/ssh-audit/rewrite |
rewriteSSHAudit |
RequireSuperuser() |
GET |
/api/settings/ssh-audit/status |
getSSHAuditStatus |
RequireSuperuser() |
POST |
/api/settings/ssh-audit/toggle |
toggleSSHAudit |
RequireSuperuser() |
POST |
/api/settings/webserver/switch |
switchWebServer |
RequireSuperuser() |
POST |
/api/settings/website-creation-lock |
setWebsiteCreationLock |
RequireSuperuser() |
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¶
POST /api/settings/backup/disable-encryption¶
Clears the stored backup encryption passphrase and disables encryption for both local and remote backups.
Guards: RequireSuperuser()
Response - 200 OK
Side effects
- Sets the
backup_encryption_passphrase,backup_encryption_key_set,backup_encrypt_local, andbackup_encrypt_remotesettings to empty/0in the settings store.
Example
curl -X POST https://panel.example.com:2087/api/settings/backup/disable-encryption \
-H "Authorization: Bearer $TOKEN"
POST /api/settings/backup/generate-key¶
Generates a new 32-character random backup encryption passphrase, stores it encrypted, and returns the plaintext passphrase once.
Guards: RequireSuperuser()
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
server_error |
Random generation, encryption, or settings write failed. |
Side effects
- Stores the encrypted passphrase under setting
backup_encryption_passphraseand setsbackup_encryption_key_setto1.
Example
curl -X POST https://panel.example.com:2087/api/settings/backup/generate-key \
-H "Authorization: Bearer $TOKEN"
POST /api/settings/backup/get-key¶
Returns the currently stored backup encryption passphrase in plaintext (decrypted from the settings store).
Guards: RequireSuperuser()
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
404 |
not_found |
No encryption key is set. |
500 |
server_error |
Decryption of the stored passphrase failed. |
Example
curl -X POST https://panel.example.com:2087/api/settings/backup/get-key \
-H "Authorization: Bearer $TOKEN"
POST /api/settings/backup/test-s3¶
Tests S3 backup connectivity by calling head_bucket with the supplied credentials, then measures latency to the endpoint host with ping.
Guards: RequireSuperuser()
Request body
{
"s3_endpoint": "string (required)",
"s3_bucket": "string (required)",
"s3_access_key": "string (required)",
"s3_secret_key": "string (required)",
"s3_region": "string (optional)",
"s3_prefix": "string (optional)"
}
| Field | Type | Required | Description |
|---|---|---|---|
s3_endpoint |
string | yes | S3 endpoint URL. |
s3_bucket |
string | yes | Bucket name. |
s3_access_key |
string | yes | Access key ID. |
s3_secret_key |
string | yes | Secret access key. |
s3_region |
string | no | Region; defaults to us-east-1 if empty. |
s3_prefix |
string | no | Key prefix. |
All five string fields are validated to reject shell metacharacters (;|&$`\"'(){}[]!<> and newlines).
Response - 200 OK
{ "data": { "success": true, "message": "Connection successful", "ping_ms": 12.3, "ping_host": "s3.example.com" } }
ping_ms is -1 when the ping probe fails or could not be parsed.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body did not bind, a required field was empty, or input contained invalid characters. |
400 |
s3_error |
The boto3 head_bucket call failed (bad credentials, wrong bucket, unreachable endpoint). |
Side effects
- Runs
python3 -c <boto3 script>to callhead_bucket, andping -c 3against the endpoint host. No persistent changes.
Example
curl -X POST https://panel.example.com:2087/api/settings/backup/test-s3 \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"s3_endpoint":"https://s3.example.com","s3_bucket":"backups","s3_access_key":"AKIAEXAMPLE","s3_secret_key":"secret","s3_region":"us-east-1"}'
POST /api/settings/backup/webapp-restore¶
Restores a single webapp's backup (files and/or database), pulling from S3 first if requested; the actual restore runs in a background goroutine.
Guards: RequireSuperuser()
Request body
{
"username": "string (required)",
"domain": "string (required)",
"set": "string (optional)",
"time_mark": "string (optional)",
"source": "string (optional)",
"restore_files": "bool (optional)",
"restore_database": "bool (optional)",
"passphrase": "string (optional)"
}
| Field | Type | Required | Description |
|---|---|---|---|
username |
string | yes | System user owning the webapp. |
domain |
string | yes | Webapp domain to restore. |
set |
string | no | Backup set name; defaults to default. |
time_mark |
string | no | Duplicity time mark to restore to (empty = latest). |
source |
string | no | local or s3; defaults to local. |
restore_files |
bool | no | Restore site files. If both file/db flags are false, both are restored. |
restore_database |
bool | no | Restore the database. |
passphrase |
string | no | Required when the backup is GPG-encrypted. |
Response - 202 Accepted
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind (e.g. missing username/domain). |
400 |
s3_error |
Pulling the backup from S3 failed. |
400 |
passphrase_required |
Backup is encrypted but no passphrase was supplied. |
Side effects
- For
source: s3, downloads backup files into/mnt/starkone-backups/<user>/<domain>/<set>before restoring. - Background restore may create the website (
websites.Create) if missing and runs therestore_websiteCLI command, restoring files under/home/<username>and/or the database.
Example
curl -X POST https://panel.example.com:2087/api/settings/backup/webapp-restore \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"username":"user1","domain":"example.com","source":"local","restore_files":true,"restore_database":true}'
POST /api/settings/backup/webapp-restore-all¶
Scans all local webapp backups and starts a background bulk restore (one set per site, files + database), tracking progress globally.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
source |
string | no | local or s3; defaults to local. |
passphrase |
string | no | Passphrase applied to every encrypted backup. |
Response - 202 Accepted
When no backups are found the handler returns 200 OK with an error envelope (code: no_backups).
Errors
| Status | Code | Meaning |
|---|---|---|
409 |
already_running |
A bulk restore is already in progress. |
200 |
no_backups |
No webapp backups were found under /mnt/starkone-backups (returned with HTTP 200). |
Side effects
- Scans
/mnt/starkone-backupsfor duplicity files and restores each unique user/domain in the background via therestore_websiteCLI command (may create missing websites). Updates the shared restore-progress state.
Example
curl -X POST https://panel.example.com:2087/api/settings/backup/webapp-restore-all \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"source":"local"}'
GET /api/settings/backup/webapp-restore-progress¶
Returns the current state of the in-progress (or last) bulk webapp restore.
Guards: RequireSuperuser()
Response - 200 OK
Note: this endpoint returns the fields at the top level, not wrapped in a data envelope.
Example
curl https://panel.example.com:2087/api/settings/backup/webapp-restore-progress \
-H "Authorization: Bearer $TOKEN"
GET /api/settings/backup/webapp-scan¶
Scans local /mnt/starkone-backups and (if remote backups are enabled) S3 for webapp backup sets, merging the two sources and flagging which sites still exist on the server.
Guards: RequireSuperuser()
Response - 200 OK
{
"backups": [
{
"username": "user1",
"domain": "example.com",
"sets": [
{ "name": "default", "latest_date": "2026-06-01 03:00", "size_mb": "12.4 MB", "chains": 1, "source": "local", "encrypted": false }
],
"exists_on_server": true,
"source": "local"
}
]
}
Note: results are returned at the top level under backups, not in a data envelope. source per entry can be local, s3, or both. Results are sorted with sites missing from the server first.
Side effects
- Read-only on disk; when remote backups are enabled, runs a
python3boto3 script to list S3 objects. No writes.
Example
curl https://panel.example.com:2087/api/settings/backup/webapp-scan \
-H "Authorization: Bearer $TOKEN"
GET /api/settings/mail¶
Returns the outbound mail relay state by inspecting the exim4 service and config files.
Guards: RequireSuperuser()
Response - 200 OK
{ "data": { "smart_route": "", "config_type": "internet", "running": true, "default_from": "[email protected]" } }
| Field | Type | Description |
|---|---|---|
smart_route |
string | Configured smarthost (dc_smarthost) or empty. |
config_type |
string | Exim config type (dc_eximconfig_configtype), e.g. internet or smarthost. |
running |
bool | Whether the exim4 service is active. |
default_from |
string | Default From address from /etc/starkone/mail.conf. |
Side effects
- Read-only; runs
systemctl is-active exim4and reads exim/panel config files.
Example
POST /api/settings/mail¶
Configures the outbound mail smarthost and default From address, then rebuilds the exim config and restarts exim4.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
smart_route |
string | no | Smarthost host::port. Non-empty switches config type to smarthost; empty switches to internet. |
default_from |
string | no | Default From address, saved to /etc/starkone/mail.conf. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
500 |
server_error |
Could not read or write the exim config file. |
Side effects
- Writes
/etc/starkone/mail.confand rewrites/etc/exim4/update-exim4.conf.conf(config type,dc_local_interfaces,dc_smarthost). - Runs
update-exim4.confandsystemctl restart exim4.
Example
curl -X POST https://panel.example.com:2087/api/settings/mail \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"smart_route":"smtp.example.com::587","default_from":"[email protected]"}'
GET /api/settings/mysql¶
Returns MySQL/MariaDB server settings parsed from the active config file plus runtime values (max connections, firewall port state).
Guards: RequireSuperuser()
Response - 200 OK
{
"data": {
"remote_enabled": false,
"port_open": false,
"bind_address": "127.0.0.1",
"config_file": "/etc/mysql/mysql.conf.d/mysqld.cnf",
"slave_skip_errors": false,
"read_only": false,
"max_connections": 151
}
}
| Field | Type | Description |
|---|---|---|
remote_enabled |
bool | True when bind-address is 0.0.0.0, ::, or *. |
port_open |
bool | Whether port 3306 appears open in firewalld/csf/iptables. |
bind_address |
string | Parsed bind-address. |
config_file |
string | Detected config file path. |
slave_skip_errors |
bool | Whether slave-skip-errors is set (uncommented). |
read_only |
bool | Whether read_only is set to on. |
max_connections |
int | Runtime @@max_connections. |
Side effects
- Read-only; runs
mysql,firewall-cmd,csf, and/oriptablesto read state.
Example
POST /api/settings/mysql/max-connections¶
Sets the MySQL max_connections value both in the config file and at runtime.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
value |
int | yes | New max connections; must be between 10 and 10000 (binding:"required,min=10,max=10000"). |
Response - 200 OK
Note: this response is not wrapped in a data envelope.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Body failed to bind / value out of range (error.message only, no code). |
500 |
- | Config file not found, or read/write failed (error.message only). |
Side effects
- Rewrites
max_connectionsin the detected MySQL config file under[mysqld]. - Runs
mysql ... -e "SET GLOBAL max_connections = <value>"to apply immediately.
Example
curl -X POST https://panel.example.com:2087/api/settings/mysql/max-connections \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"value":500}'
POST /api/settings/mysql/port¶
Opens or closes TCP port 3306 in the active firewall (firewalld, csf, or ufw).
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
open |
bool | no | true to open port 3306, false to close it. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
Side effects
- Runs firewall commands:
firewall-cmd --add-port/--remove-port=3306/tcp --permanent+ reload, orcsf -a/-d 3306, orufw allow/deny 3306/tcp, depending on which is installed.
Example
curl -X POST https://panel.example.com:2087/api/settings/mysql/port \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"open":true}'
POST /api/settings/mysql/read-only¶
Toggles the MySQL read_only global, persisting it in config and applying it live.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
enable |
bool | no | true sets read_only = ON, false sets read_only = OFF. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Body failed to bind (error.message only). |
500 |
- | Config file not found or read/write failed (error.message only). |
Side effects
- Writes
read_only = ON/OFFinto the[mysqld]section of the detected config file. - Runs
mysql ... -e "SET GLOBAL read_only = ON/OFF".
Example
curl -X POST https://panel.example.com:2087/api/settings/mysql/read-only \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enable":true}'
POST /api/settings/mysql/remote¶
Enables or disables remote MySQL access by setting bind-address and restarting the database service.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
bool | no | true sets bind-address = 0.0.0.0, false sets 127.0.0.1. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
500 |
server_error |
Config file not found or read/write failed. |
Side effects
- Rewrites
bind-addressin the detected MySQL config file. - Restarts the DB service via
systemctl restart mysql,mysqld, andmariadb.
Example
curl -X POST https://panel.example.com:2087/api/settings/mysql/remote \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'
POST /api/settings/mysql/replication/restart¶
Restarts MySQL replication by stopping and starting the slave, then reports IO/SQL thread status.
Guards: RequireSuperuser()
Response - 200 OK
Side effects
- Runs
mysql ... -e "STOP SLAVE", thenSTART SLAVE, then readsSHOW SLAVE STATUS.
Example
curl -X POST https://panel.example.com:2087/api/settings/mysql/replication/restart \
-H "Authorization: Bearer $TOKEN"
POST /api/settings/mysql/replication/skip-error¶
Skips a number of replication errors via SQL_SLAVE_SKIP_COUNTER, then reports whether the SQL thread is running.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
count |
int | no | Number of events to skip. Defaults to 1 if absent/invalid; clamped to 1-100. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
- | The SET GLOBAL SQL_SLAVE_SKIP_COUNTER query failed (error.message only). |
Side effects
- Runs
mysql ... -e "STOP SLAVE",SET GLOBAL SQL_SLAVE_SKIP_COUNTER = <count>,START SLAVE, thenSHOW SLAVE STATUS.
Example
curl -X POST https://panel.example.com:2087/api/settings/mysql/replication/skip-error \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"count":1}'
POST /api/settings/mysql/slave-skip-errors¶
Persists the slave-skip-errors = 1032,1062,1452 directive in the MySQL config (or removes it) and restarts the database to apply.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
enable |
bool | no | true adds the slave-skip-errors directive; false removes it. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Body failed to bind (error.message only). |
500 |
- | Config file not found or read/write failed (error.message only). |
Side effects
- Edits the
[mysqld]section of the detected config file. - Restarts the DB via
systemctl restart mariadb(falling back tomysql).
Example
curl -X POST https://panel.example.com:2087/api/settings/mysql/slave-skip-errors \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enable":true}'
GET /api/settings/php-security¶
Returns, per detected PHP version, whether StarkOne's hardened disable_functions list is applied in 99-starkone.ini.
Guards: RequireSuperuser()
Response - 200 OK
Note: keys are PHP versions (checked across 7.4, 8.0-8.4); value is true when the FPM 99-starkone.ini contains a disable_functions line including exec and shell_exec. Not wrapped in a data envelope.
Side effects
- Read-only; reads
/etc/php/<ver>/fpm/conf.d/99-starkone.inifor each version.
Example
POST /api/settings/php-security¶
Enables or disables the hardened PHP disable_functions list for one PHP version (FPM and CLI) and restarts PHP-FPM.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
version |
string | yes | PHP version, e.g. 8.2. |
secure |
bool | no | true writes the full hardened disable_functions list; false clears it. |
Response - 200 OK
Note: not wrapped in a data envelope.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
404 |
not_found |
The PHP version's FPM conf.d directory does not exist. |
500 |
server_error |
Writing the FPM ini file failed. |
Side effects
- Writes
disable_functionsinto/etc/php/<ver>/fpm/conf.d/99-starkone.iniand the matching CLI99-starkone.ini, preserving other existing lines. - Runs
systemctl restart php<ver>-fpm.
Example
curl -X POST https://panel.example.com:2087/api/settings/php-security \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"version":"8.2","secure":true}'
GET /api/settings/php/:version/config¶
Returns the StarkOne-managed PHP INI settings for a version, read only from its 99-starkone.ini file.
Guards: RequireSuperuser()
Path parameters
| Name | Type | Description |
|---|---|---|
version |
string | PHP version, e.g. 8.2. |
Response - 200 OK
Note: returns a flat map of INI keys (dots replaced with underscores) plus a custom field ("true"/"false") indicating whether the file exists. Not wrapped in a data envelope.
Side effects
- Read-only; reads
/etc/php/<version>/fpm/conf.d/99-starkone.ini.
Example
POST /api/settings/php/:version/config¶
Writes a StarkOne-managed PHP INI file (99-starkone.ini) for the version, for both FPM and CLI.
Guards: RequireSuperuser()
Path parameters
| Name | Type | Description |
|---|---|---|
version |
string | PHP version, e.g. 8.2. |
Request body
JSON object of setting keys. Only the following keys are recognized; non-empty values are written:
{
"memory_limit": "256M",
"upload_max_filesize": "64M",
"post_max_size": "64M",
"max_execution_time": "120",
"max_input_time": "60",
"max_input_vars": "3000",
"display_errors": "Off",
"error_reporting": "E_ALL",
"log_errors": "On",
"date_timezone": "UTC",
"session_gc_maxlifetime": "1440",
"opcache_enable": "1",
"opcache_memory_consumption": "128",
"realpath_cache_size": "4096k",
"allow_url_fopen": "On"
}
| Field | Type | Required | Description |
|---|---|---|---|
| (any of the keys above) | string/number | no | Mapped to the corresponding INI directive (e.g. date_timezone -> date.timezone). Unknown keys are ignored. |
Response - 200 OK
Note: not wrapped in a data envelope.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind as JSON. |
500 |
write_error |
Writing the FPM ini file failed. |
Side effects
- Writes
/etc/php/<version>/fpm/conf.d/99-starkone.iniand the CLI99-starkone.ini. Does not restart PHP-FPM.
Example
curl -X POST https://panel.example.com:2087/api/settings/php/8.2/config \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"memory_limit":"256M","upload_max_filesize":"64M"}'
GET /api/settings/php/available¶
Lists PHP versions installable on the host, querying the package manager and adding the ondrej PPA / remi repo if too few versions are found.
Guards: RequireSuperuser()
Response - 200 OK
Versions are sorted descending.
Side effects
- Runs
apt-cache search(Debian) ordnf search(RHEL). If 0-1 versions are found, may runadd-apt-repository ppa:ondrej/php+apt-get update, or install the remi-release RPM, then re-search.
Example
POST /api/settings/php/install¶
Installs a PHP version via the install_php CLI command.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
version |
string | yes | PHP version in X.Y format (validated by regex). |
Response - 200 OK
Note: not wrapped in a data envelope.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
400 |
invalid_version |
Version is not in X.Y format. |
500 |
install_failed |
The install_php <ver> add CLI command failed (includes output). |
Side effects
- Runs the
install_php <version> addCLI command, which installs PHP packages.
Example
curl -X POST https://panel.example.com:2087/api/settings/php/install \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"version":"8.3"}'
POST /api/settings/php/remove¶
Removes a PHP version via the install_php CLI command.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
version |
string | yes | PHP version to remove. |
Response - 200 OK
Note: not wrapped in a data envelope.
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
500 |
remove_failed |
The install_php <ver> remove CLI command failed (includes output). |
Side effects
- Runs the
install_php <version> removeCLI command, which uninstalls PHP packages.
Example
curl -X POST https://panel.example.com:2087/api/settings/php/remove \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"version":"8.3"}'
POST /api/settings/remote-logging¶
Configures remote log forwarding via rsyslog and journald, persisting the settings to the database.
Guards: RequireSuperuser()
Request body
{
"server": "string (optional)",
"port": "int (optional)",
"protocol": "string (optional)",
"syslog": "bool (optional)",
"journald": "bool (optional)",
"http": "bool (optional)"
}
| Field | Type | Required | Description |
|---|---|---|---|
server |
string | no | Remote log server address. Rejected if it contains shell metacharacters/spaces or is a loopback address. |
port |
int | no | Defaults to 514 if <= 0; clamped to <= 65535. |
protocol |
string | no | tcp or udp; anything else becomes udp. |
syslog |
bool | no | Enable rsyslog forwarding. |
journald |
bool | no | Set journald ForwardToSyslog. |
http |
bool | no | Stored as remote_log_http; no rsyslog effect in this handler. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind, server had invalid characters, or server was a loopback address. |
500 |
server_error |
Writing the rsyslog config file failed. |
Side effects
- Persists
remote_log_*settings togeneral_settings. - Writes or removes
/etc/rsyslog.d/starkone-remote.confand restartsrsyslog. - Edits
/etc/systemd/journald.confForwardToSyslogand restartssystemd-journaldwhen changed.
Example
curl -X POST https://panel.example.com:2087/api/settings/remote-logging \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"server":"203.0.113.10","port":514,"protocol":"udp","syslog":true,"journald":true}'
GET /api/settings/server-name¶
Returns the configured server name, falling back to the system hostname when unset.
Guards: AuthWithDB(cfg.JWTSecret, db)
Response - 200 OK
Side effects
- Read-only; runs
hostnameonly when noserver_namesetting exists.
Example
POST /api/settings/server-name¶
Sets the panel's server name (handler setServerName; the route also applies RequireSuperuser()).
Guards: AuthWithDB(cfg.JWTSecret, db)
Request body
| Field | Type | Required | Description |
|---|---|---|---|
server_name |
string | no | New server name to persist. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
500 |
db_error |
Upserting the server_name setting failed. |
Side effects
- Upserts
server_nameintogeneral_settings.
Example
curl -X POST https://panel.example.com:2087/api/settings/server-name \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"server_name":"panel.example.com"}'
GET /api/settings/server-timezone¶
Returns the server's timezone via timedatectl, falling back to /etc/timezone then UTC.
Guards: RequireSuperuser()
Response - 200 OK
When detection fails entirely, returns { "data": { "timezone": "UTC", "error": "Could not detect server timezone" } }.
Side effects
- Read-only; runs
timedatectl show -p Timezone.
Example
curl https://panel.example.com:2087/api/settings/server-timezone \
-H "Authorization: Bearer $TOKEN"
POST /api/settings/server-timezone¶
Sets the server timezone using timedatectl set-timezone.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
timezone |
string | yes | IANA timezone name, e.g. UTC or America/New_York. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
invalid_request |
Body failed to bind (missing timezone). |
500 |
set_timezone_failed |
timedatectl set-timezone failed. |
Side effects
- Runs
timedatectl set-timezone <timezone>.
Example
curl -X POST https://panel.example.com:2087/api/settings/server-timezone \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"timezone":"America/New_York"}'
POST /api/settings/ssh-audit/forward¶
Enables or disables forwarding of SSH command-audit log entries to the configured remote log server via rsyslog.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
bool | no | true writes the rsyslog forward rule; false removes it. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
400 |
no_server |
Enabling requested but no remote log server is configured. |
Side effects
- Persists
ssh_audit_forwardtogeneral_settings. - Writes or removes
/etc/rsyslog.d/starkone-audit-forward.confand restartsrsyslog.
Example
curl -X POST https://panel.example.com:2087/api/settings/ssh-audit/forward \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'
GET /api/settings/ssh-audit/logs¶
Returns parsed SSH command-audit log entries from /var/log/starkone/ssh-audit.log, with optional filtering and pagination (newest first).
Guards: RequireSuperuser()
Query parameters
| Name | Type | Optional | Description |
|---|---|---|---|
user |
string | yes | Filter entries to this user (exact match). |
search |
string | yes | Case-insensitive substring filter on the command. |
limit |
int | yes | Page size; defaults to 100, clamped to 1-1000. |
offset |
int | yes | Pagination offset; defaults to 0. |
Response - 200 OK
{
"data": {
"logs": [
{ "timestamp": "2026-06-17T10:00:00Z", "user": "user1", "command": "ls -la", "exit_code": 0, "tty": "pts/0", "ip": "203.0.113.5" }
],
"total": 1
}
}
total reflects the count after filtering but before pagination. If the log file is missing, returns empty logs with total: 0.
Example
curl "https://panel.example.com:2087/api/settings/ssh-audit/logs?user=user1&limit=50" \
-H "Authorization: Bearer $TOKEN"
POST /api/settings/ssh-audit/rewrite¶
Re-applies the SSH audit hooks across users by running the audit_rewrite CLI command.
Guards: RequireSuperuser()
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
500 |
server_error |
The audit_rewrite CLI command failed. |
Side effects
- Runs the
audit_rewriteCLI command, which rewrites the audit hooks in user shell profiles.
Example
curl -X POST https://panel.example.com:2087/api/settings/ssh-audit/rewrite \
-H "Authorization: Bearer $TOKEN"
GET /api/settings/ssh-audit/status¶
Returns SSH command-audit status: whether auditing is enabled, log size/entry count, monitored user count, and remote-forward state.
Guards: RequireSuperuser()
Response - 200 OK
{ "data": { "enabled": true, "log_size": 10240, "entry_count": 42, "users_count": 3, "forward_remote": false } }
Side effects
- Read-only; reads the audit log file and scans
/root/.bashrcand/home/*/.bashrcfor the audit marker.
Example
curl https://panel.example.com:2087/api/settings/ssh-audit/status \
-H "Authorization: Bearer $TOKEN"
POST /api/settings/ssh-audit/toggle¶
Enables or disables SSH command auditing via the audit_enable / audit_disable CLI commands.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
enabled |
bool | no | true runs audit_enable; false runs audit_disable. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind. |
500 |
server_error |
The audit_enable/audit_disable CLI command failed. |
Side effects
- Runs the
audit_enableoraudit_disableCLI command, which installs/removes audit hooks in user shell profiles.
Example
curl -X POST https://panel.example.com:2087/api/settings/ssh-audit/toggle \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'
POST /api/settings/webserver/switch¶
Switches the active web server between nginx and apache: stops/disables all web servers, installs and enables the target, rewrites all site configs, and starts the target.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
target |
string | yes | nginx or apache (case-insensitive). |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
bad_request |
Body failed to bind, or target is not nginx/apache. |
Side effects
- Stops and disables nginx, apache2, and httpd via
systemctl. - Installs the target web server (
apt-get/dnf) if missing, enables it, and starts it. - Updates the
webserversetting ingeneral_settings. - Runs the
rewrite_allCLI command to regenerate all website configs.
Example
curl -X POST https://panel.example.com:2087/api/settings/webserver/switch \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"target":"nginx"}'
POST /api/settings/website-creation-lock¶
Locks or unlocks website creation panel-wide by toggling the website_creation_locked setting.
Guards: RequireSuperuser()
Request body
| Field | Type | Required | Description |
|---|---|---|---|
locked |
bool | no | true locks website creation; false unlocks it. |
Response - 200 OK
Errors
| Status | Code | Meaning |
|---|---|---|
400 |
- | Body failed to bind (error.message only). |
Side effects
- Upserts
website_creation_locked(1/0) intogeneral_settings.
Example