Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

API reference

Management endpoints use cookie-session authentication and CSRF protection. For multi-instance behavior, see instances.

MethodEndpointDescription
POST/api/auth/sessionsCheck password; return totpRequired when a code is needed (CSRF required)
POST/api/auth/sessions/totpComplete password sign-in with { code } (pending session + CSRF)
POST/api/auth/totp/setupPropose a seed using fresh credential proof (management + CSRF)
POST/api/auth/totp/confirmActivate the proposed seed using { code } (management + CSRF)
DELETE/api/auth/totp/setupCancel proposed enrollment (management + CSRF)
DELETE/api/auth/totpDisable TOTP using fresh credential proof (management + CSRF)
POST/api/auth/passkeys/reauthentication/optionsBegin action-bound passkey verification (management + CSRF)
POST/api/auth/passkeys/reauthenticationVerify assertion; return one-use credential proof (management + CSRF)
DELETE/api/auth/sessions/currentRevoke the current session (CSRF required)
GET/api/auth/csrfObtain the CSRF token for the current or a new pre-login context
POST/api/auth/setupInitialize stored credentials once and return a recovery key (CSRF required)
GET/api/auth/credentialsRead the administrator username (management session required)
PATCH/api/auth/credentialsUpdate username (current password) or password (fresh credential proof); renew session and revoke old sessions (management + CSRF)
GET/api/auth/passkeysList passkey metadata and HTTPS configuration (management session required)
POST/api/auth/passkeys/registration/optionsBegin registration with name and fresh credential proof (management + CSRF)
POST/api/auth/passkeys/registrationVerify and persist a registration response (management session + CSRF)
POST/api/auth/passkeys/authentication/optionsBegin discoverable passkey sign-in (anonymous context + CSRF)
POST/api/auth/passkeys/authenticationVerify a signed assertion and issue a management session (anonymous context + CSRF)
DELETE/api/auth/passkeys/:idRemove with fresh credential proof; revoke old sessions and renew this one (management + CSRF)
POST/api/auth/recoveryReset password using a recovery key and rotate that key (CSRF required)
GET/api/auth/tokensList token metadata (management session only)
POST/api/auth/tokensCreate a read-only integration token (session + CSRF)
DELETE/api/auth/tokens/:idRevoke an integration token (session + CSRF)
GET/api/auth/statusRead authentication, enrollment and session state without credentials
GET/api/metricsParsed HTTP metrics for the Metrics tab
GET/api/metrics/configCheck if Caddy metrics directive is enabled
PUT/api/metrics/configEnable or disable Caddy metrics directive
GET/api/metrics/rawRaw Prometheus metrics (public if CADDY_UI_PUBLIC_METRICS=true)
GET/api/statusServer status, route count, upstream health, and uptime
GET/api/status/caddy-configFull raw Caddy JSON config
GET/api/status/processCaddy process info including version
GET/api/caddyfileRead Caddyfile from disk
GET/api/caddyfile?download=trueDownload Caddyfile as a timestamped attachment
PUT/api/caddyfileSave, validate, format, and reload
POST/api/caddyfile/validationsValidate (and optionally format) without saving
POST/api/caddyfile/reloadsReload Caddy from disk
GET/api/caddyfile/historyList all Caddyfile snapshots
GET/api/caddyfile/history/:filenameRead a specific snapshot
DELETE/api/caddyfile/history/:filenameDelete a snapshot
GET/api/routesList all routes across all HTTP servers
POST/api/routesAdd a reverse proxy route
PATCH/api/routes/:idUpdate a UI-managed route by ID
DELETE/api/routes/:idRemove a route and its Caddyfile block
GET/api/route-notesRead all route notes
PUT/api/route-notes/:domainSet or clear a route note
GET/api/healthLive upstream check via Caddy pool API with TCP fallback (not recorded in uptime history)
GET/api/health/uptimeUptime stats per upstream from persisted history, sampled every 30 seconds by the backend
GET/api/health/historyRaw timestamped checks for one upstream, for the route status history view
GET/api/tlsList all certificates with expiry and status
DELETE/api/tls/:domainDelete an orphaned, superseded, or expired internal cert
GET/api/tls/caDownload Caddy’s root CA certificate
GET/api/logsLast 200 lines of the configured Caddy log; 404 if missing, 503 if the container is unreachable, 500 if reading fails
GET/api/logs/streamSSE stream of live log output; failures include an error code and request ID
GET/api/logs/configRead log configuration; coded read/parse failures
PUT/api/logs/configUpdate validated log configuration
GET/api/server-namesRead server labels for the selected instance
GET/api/server-names/allRead server labels for every instance
PUT/api/server-names/:idSet a server label
DELETE/api/server-names/:idRemove a server label
GET/api/notifications/configRead notification settings
PUT/api/notifications/configUpdate notification settings
POST/api/notifications/testSend a test notification

Empty and unavailable results

An empty result means the resource is empty, not that it couldn’t be read:

  • GET /api/routes returns [] only when Caddy has no HTTP routes. If Caddy’s config can’t be read, it returns 503 with { "code": "CADDY_CONFIG_UNAVAILABLE" }.
  • GET /api/tls returns [] when Caddy hasn’t stored any certificates yet. Caddy only creates its data directory when it first stores something, so a missing data path also returns []; in local mode the backend log notes when that path may be a missing volume mount. If certificate storage exists but can’t be read (permissions, or the container can’t be reached), it returns 500 with { "code": "CERTIFICATE_READ_FAILED" }. Check the backend log for the reason and path.
  • When certificate storage is readable but Caddy’s config isn’t, GET /api/tls still lists the certificates with isManaged: null. Without Caddy’s config, caddy/ui can’t tell whether a certificate is still in use, so none are marked orphaned.
  • GET /api/route-notes returns {} when no notes file exists yet. If the notes file can’t be read or isn’t a valid JSON object, it returns 500 with { "code": "ROUTE_NOTES_READ_FAILED" }. PUT /api/route-notes/:domain fails the same way and leaves the file unchanged.
  • GET /api/caddyfile/history returns [] when there are no snapshots. If the history directory can’t be read, it returns 500 with { "code": "CADDYFILE_HISTORY_READ_FAILED" }.
  • GET /api/logs returns 200 with { "lines": [], "path": "..." } for an empty readable file. A missing file returns 404 with LOG_FILE_MISSING, and a Docker-mode container that can’t be reached returns 503 with LOG_SOURCE_UNAVAILABLE. Permissions, command or other read failures return 500 with LOG_READ_FAILED. Failure responses include a request ID; the application logs retain the underlying reason and instance path.
  • GET /api/logs/stream reports failures as SSE events on the established HTTP stream. Events include code, error and requestId, using LOG_FILE_MISSING for a missing file, LOG_SOURCE_UNAVAILABLE for an unreachable container and LOG_STREAM_ERROR for other failures. The UI stops failed live mode; start it again after correcting the problem.

The Caddy log source reads the selected instance’s configured log file, rather than Docker’s captured stdout/stderr. A writable directory mount alone does not enable file logging: Caddy must be configured to write to the selected path. The UI displays unavailable reads separately from an empty file. Refresh retries the read and clears the error after success.

Logging configuration

GET /api/logs/config returns defaults when the Caddyfile has no default logger. A Caddyfile read failure returns 500 with CADDYFILE_READ_FAILED; a configuration the structural scanner cannot interpret returns 500 with LOG_CONFIG_PARSE_FAILED. Both include a request ID and retain the cause in the application logs. Parsing failures never masquerade as disabled logging. The configuration panel shows a localized error instead of loading indefinitely.

PUT /api/logs/config requires a boolean enabled. When enabling logging, provide a nonempty string path without control characters, a single size token such as 50mb or 1.5GiB for rollSize, a non-negative safe integer for rollKeep, json or console for format, and DEBUG, INFO, WARN or ERROR for level. Paths containing spaces are supported. Invalid request values return 400 with VALIDATION_FAILED before a write is prepared. Disabling requires only { "enabled": false }; unused option values are not serialized.

Caddy still validates the edited configuration before it is written and applied. A semantic rejection returns 422 with CADDYFILE_VALIDATION_FAILED, leaving the file and live configuration unchanged. Logging edits replace the existing default logger, including a bare log or log default, and preserve named loggers and unrelated source bytes. New logger text follows the local indentation and line endings; the whole file is not formatted.