Skip to content

Admin API ​

Sweety ships with a full-featured REST Admin API that matches all Caddy Admin API capabilities and extends beyond them. The API runs as an independent TCP listener and has zero impact on main server performance.

Enabling ​

toml
[global]
admin_listen = "127.0.0.1:9099"   # Listen address (empty = disabled)
admin_token  = "your-secret-token" # Bearer Token (empty = no auth)

⚠️ Security: Only bind to 127.0.0.1. Never expose to the public internet.

Authentication ​

When admin_token is set, all requests require Authorization: Bearer <token> except:

  • GET /api/health
  • GET /health
  • GET /api/version
  • GET /api/doc
  • GET /metrics

Core Concepts ​

Runtime Config vs Disk Config ​

  • All changes only affect runtime memory by default — they are lost on restart
  • GET /config always returns the currently running config, not the disk file
  • Append ?save=true to also persist changes to the config file (TOML format)
  • POST /config/save explicitly saves the current runtime config to disk at any time
bash
# Runtime-only change (lost on restart)
curl -X PATCH http://127.0.0.1:9099/config/global \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"keepalive_timeout": 120}'

# Change + persist to config file
curl -X PATCH "http://127.0.0.1:9099/config/global?save=true" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"keepalive_timeout": 120}'

# Explicitly save running config to disk
curl -X POST http://127.0.0.1:9099/config/save \
  -H "Authorization: Bearer $TOKEN"

Endpoint Reference ​

Config Tree CRUD (Caddy /config/ equivalent) ​

MethodPathDescription
POST/loadHot-load full JSON config (auto-rollback on failure)
GET/config/[path]Read running config subtree
POST/config/[path]Create/replace object | append to array
PUT/config/[path]Insert at array index | strict create (error if exists)
PATCH/config/[path]Replace existing value only
DELETE/config/[path]Delete node (/config/ = clear config, keep running)
POST/config/saveExplicitly save running config to disk (TOML)
POST/config/reloadHot-reload config from disk
POST/config/testValidate disk config file syntax

All write operations support ?save=true query parameter to persist to config file.

@id Node Access (Caddy /id/ equivalent) ​

MethodPathDescription
GET/id/:idAccess config node by @id
GET/id/:id/[path]Access via @id + sub-path

Config Adapter (Caddy /adapt equivalent) ​

MethodPathDescription
POST/adaptTOML → JSON conversion (does not load)

Runtime Status (Caddy equivalents) ​

MethodPathDescription
GET/reverse_proxy/upstreamsUpstream status (Caddy-compatible JSON)
GET/metricsPrometheus text/plain metrics
POST/api/stopGraceful shutdown

System ​

MethodPathDescription
GET/api/healthHealth check (no auth)
GET/api/versionVersion + build info (no auth)
GET/api/systemSystem info (uptime / workers / memory)
GET/api/docAPI documentation JSON (no auth)
GET/api/debugRuntime debug info
GET/api/statsGlobal statistics snapshot

Sites ​

MethodPathDescription
GET/api/sitesSite list + summary
GET/api/sites/:nameSingle site details
DELETE/api/sites/:nameDelete site (takes effect immediately)

Upstreams ​

MethodPathDescription
GET/api/upstreamsAll upstream groups + node status
GET/api/upstreams/:nameSingle upstream group details
POST/api/upstreams/:name/nodes/:addr/enableEnable node
POST/api/upstreams/:name/nodes/:addr/disableDisable node
PUT/api/upstreams/:name/nodes/:addr/weightUpdate node weight

Certificates ​

MethodPathDescription
GET/api/certsTLS certificate list
POST/api/certs/reloadReload certificates from disk
POST/api/certs/acme/renewTrigger immediate ACME renewal (?site=name for specific site)

Cache ​

MethodPathDescription
GET/api/cache/statsCache hit rate statistics
POST/api/cache/purgePurge all caches

Connections / Plugins / Logs ​

MethodPathDescription
GET/api/connectionsActive connections + pool status
GET/api/pluginsRegistered plugin list
GET/api/logs/levelCurrent log level
PUT/api/logs/levelChange log level

Usage Examples ​

Health Check ​

bash
curl http://127.0.0.1:9099/api/health
# {"status":"ok"}

View Running Config ​

bash
# Full config
curl http://127.0.0.1:9099/config/ -H "Authorization: Bearer $TOKEN"

# Global section only
curl http://127.0.0.1:9099/config/global -H "Authorization: Bearer $TOKEN"

# First site (by array index)
curl http://127.0.0.1:9099/config/sites/0 -H "Authorization: Bearer $TOKEN"

Modify Global Config ​

bash
# Runtime-only
curl -X PATCH http://127.0.0.1:9099/config/global \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"keepalive_timeout": 120}'

# Persist to disk
curl -X PATCH "http://127.0.0.1:9099/config/global?save=true" \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"keepalive_timeout": 120}'

Hot-Load Full Config ​

bash
curl -X POST http://127.0.0.1:9099/load \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d @new-config.json

Automatically rolls back to the previous config on failure.

Add a Site ​

bash
curl -X POST http://127.0.0.1:9099/config/sites \
  -H "Authorization: Bearer $TOKEN" \
  -d '{
    "name": "new-site",
    "server_name": ["new.example.com"],
    "listen": [80],
    "root": "/var/www/new-site",
    "locations": [{"path": "/", "handler": "static"}]
  }'

Upstream Node Control ​

bash
# Drain node
curl -X POST http://127.0.0.1:9099/api/upstreams/backend/nodes/127.0.0.1%3A8080/disable \
  -H "Authorization: Bearer $TOKEN"

# Re-enable node
curl -X POST http://127.0.0.1:9099/api/upstreams/backend/nodes/127.0.0.1%3A8080/enable \
  -H "Authorization: Bearer $TOKEN"

# Change weight
curl -X PUT http://127.0.0.1:9099/api/upstreams/backend/nodes/127.0.0.1%3A8080/weight \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"weight": 5}'

TOML → JSON Adapter ​

bash
curl -X POST http://127.0.0.1:9099/adapt \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: text/plain" \
  --data-binary @sweety.toml

Prometheus Metrics ​

bash
curl http://127.0.0.1:9099/metrics

Available metrics:

MetricTypeDescription
sweety_requests_totalcounterTotal requests processed
sweety_active_requestsgaugeCurrent concurrent requests
sweety_errors_4xx_totalcounterTotal 4xx errors
sweety_errors_5xx_totalcounterTotal 5xx errors
sweety_bytes_sent_totalcounterTotal response bytes sent
sweety_websocket_connectionsgaugeCurrent active WebSocket connections

With analysis reports enabled: sweety_avg_response_ms, sweety_error_rate_5xx, sweety_status_total{code="..."}, etc.

Stats Snapshot (/api/stats) ​

bash
curl http://127.0.0.1:9099/api/stats -H "Authorization: Bearer $TOKEN"

Returns JSON:

json
{
  "total_requests": 12345,
  "total_errors_4xx": 23,
  "total_errors_5xx": 2,
  "total_bytes_sent": 1048576,
  "active_requests": 5,
  "active_ws_connections": 1
}

Comparison with Caddy Admin API ​

FeatureCaddySweety
Config tree CRUD /config/[path]✅✅
Hot-load /load✅✅ + auto-rollback
Clear config DELETE /config/✅✅
@id access /id/:id✅✅
Config adapter /adapt✅ Caddyfile→JSON✅ TOML→JSON
Upstream status /reverse_proxy/upstreams✅✅
Prometheus /metrics✅✅ text/plain
Graceful stop /stop✅✅
Optional persistence ?save=true✗ (always persists)✅
Explicit save /config/save✗✅
Reload from disk /config/reload✗✅
Config validation /config/test✗✅
Site CRUD /api/sites✗✅
Node control enable/disable/weight✗✅
Certificate management /api/certs✗✅
Cache management /api/cache✗✅
Runtime debug /api/debug/debug/pprof✅
Log level toggle /api/logs/level✗✅
Plugin list /api/plugins✗✅
Bearer Token authMutual TLS✅
ACME instant renewal /api/certs/acme/renew✗✅ async + SAN multi-domain
CORS support✗✅
API doc endpoint /api/doc✗✅

CLI Integration ​

bash
# Print API doc JSON
sweety --api-doc

# Trigger hot-reload (equivalent to POST /config/reload)
sweety reload

# Validate config file
sweety validate -c sweety.toml

Released under the Apache License 2.0