API Documentation
All API endpoints require authentication unless otherwise noted. Three authentication methods are supported:
auth-tokenheader — a browser-session token fromPOST /api/auth/loginor the OIDC flow (below).Authorization: Bearer <token>header — a self-service API token (PAT, see API Tokens), for scripts/CI without a browser session.- OIDC (browser) — if the proxy is configured as an OIDC client of an SSO
(
app_oidc__*/conf.oidc, see DEPLOYMENT.md), users can log in viaGET /api/auth/oidc/startinstead of posting a username/password.
The proxy can also be configured as a direct LDAP client (app_ldap__* /
conf.ldap) for looking up/validating users, independent of the OIDC flow —
see DEPLOYMENT.md for the full configuration reference.
Authenticated requests also carry RBAC (role-based access control):
global admins can manage everything; other users are scoped to viewer or
manager rights on specific domains via Permissions and
Groups.
Base URL: https://your-proxy-host.com/api
Authentication
Login
POST /api/auth/login
Authenticate a user and receive an auth token.
curl -H "Content-Type: application/json" \
-X POST \
-d '{"username": "myuser", "password": "mypassword"}' \
https://proxy-host.com/api/auth/login
Responses:
200{"login": true, "token": "027d3964-7d81-4462-a6f9-2c1f9b40b4be", "message": "myuser logged in!"}401{"name": "LoginFailed", "message": "Invalid Credentials, login failed."}
Logout
ALL /api/auth/logout
Invalidate the current auth token.
curl -H "auth-token: your-token-here" \
-X POST \
https://proxy-host.com/api/auth/logout
Responses:
200{"message": "Bye"}
OIDC Login (start)
GET /api/auth/oidc/start
Begin the OIDC authorization-code flow: creates a PKCE + state challenge and
redirects the browser to the configured SSO’s authorize endpoint. Only
available when conf.oidc.enabled is true.
Query Parameters:
redirect- Internal path to return to after login (optional; sanitized to same-origin)
curl -i "https://proxy-host.com/api/auth/oidc/start?redirect=/hosts"
Responses:
302Redirect to the SSO’s authorization endpoint404{"name": "OidcDisabled", "message": "OIDC login is not enabled."}
OIDC Callback
GET /api/auth/oidc/callback
Redirect target for the SSO after login. Validates the one-time state,
exchanges the authorization code for tokens, reads identity from the
userinfo endpoint, establishes a session, and redirects the browser back to
the login page with the app’s own auth-token in a URL fragment.
Query Parameters:
code(required) - Authorization code from the SSOstate(required) - State value from thestartstep
# Not called directly — the SSO redirects the browser here after login.
Responses:
302Redirect to/login#token=...&redirect=...400{"name": "OidcCallbackInvalid", "message": "Missing code or state."}or expired/unknown state
API Tokens
Self-service personal access tokens (PATs) for scripting/CI without a browser
session. Every endpoint is owner-scoped: a user only sees/manages tokens they
created. Mounted at /api/api-token.
List API Tokens
GET /api/api-token
List the current user’s API tokens.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/api-token
Responses:
200{"results": [{"id": "...", "name": "ci", ...}, ...]}
Create API Token
POST /api/api-token
Create a new API token. The raw token string is only returned once, at creation.
Parameters:
name(required) - Display namedescription(optional)expires_in_days(optional) -0or omitted means no expiry
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"name": "ci", "expires_in_days": 90}' \
https://proxy-host.com/api/api-token
Responses:
200{"results": {...}, "token": "prx_<id>_<secret>", "message": "API token 'ci' created. Save it now — it will not be shown again."}
Get API Token
GET /api/api-token/:id
Get a token’s metadata (not the raw secret, which is never stored/returned again).
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/api-token/<id>
Responses:
200{"results": {...}}403Not your token
Update API Token
PUT /api/api-token/:id
Update a token’s name/description/expiry.
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X PUT \
-d '{"name": "ci-updated"}' \
https://proxy-host.com/api/api-token/<id>
Responses:
200{"results": {...}, "message": "API token 'ci-updated' updated."}
Delete (Revoke) API Token
DELETE /api/api-token/:id
Revoke a token immediately.
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/api-token/<id>
Responses:
200{"id": "<id>", "message": "API token 'ci' revoked."}
Rotate API Token
POST /api/api-token/:id/rotate
Issue a new secret for an existing token (same id, new raw value shown once).
curl -H "auth-token: your-token-here" \
-X POST \
https://proxy-host.com/api/api-token/<id>/rotate
Responses:
200{"token": "prx_<id>_<new-secret>", "message": "API token 'ci' rotated. Save it — it will not be shown again."}
Users
All user endpoints require authentication. GET /me and PUT /password
(self-service) work for any authenticated user; everything else (listing,
creating, deleting users, resetting another user’s password) requires global
admin.
List Users
GET /api/user
Get list of all users. Admin only.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/user
Query Parameters:
detail- Include full user details (optional)
Responses:
200{"results": ["user1", "user2"]}200{"results": [{"username": "user1", ...}, ...]}(with?detail=true)403Not an admin
Get Current User
GET /api/user/me
Get the currently authenticated user’s identity and effective RBAC rights (drives the web UI’s nav/button gating).
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/user/me
Responses:
200{"username": "myuser", "groups": [...], "localGroups": [...], "externalGroups": [...], "isAdmin": false, "global": null, "domains": {...}}
Create User
POST /api/user
Create a new local user. Admin only.
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"username": "newuser", "password": "newpassword"}' \
https://proxy-host.com/api/user
Responses:
200User created successfully403Not an admin409Username already exists422{"name": "ObjectValidateError", "message": ...}Validation error (also returned for weak passwords)
Delete User
DELETE /api/user/:username
Delete a user account. Admin only.
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/user/olduser
Responses:
200{"username": "olduser", "results": ...}403Not an admin404User not found
Change Password (Self)
PUT /api/user/password
Change the password for the currently authenticated user.
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X PUT \
-d '{"password": "newpassword"}' \
https://proxy-host.com/api/user/password
Responses:
200{"results": ...}Password changed successfully422Weak password rejected by the password policy
Change Password (Other User)
PUT /api/user/password/:username
Change the password for another user. Admin only.
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X PUT \
-d '{"password": "newpassword"}' \
https://proxy-host.com/api/user/password/otheruser
Responses:
200{"results": ...}Password changed successfully403Not an admin404User not found
Permissions
RBAC: grants a viewer or manager role to a user or group, either globally
or scoped to one domain. Global-admin-only. Mounted at /api/permission.
List Permissions
GET /api/permission
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/permission
Responses:
200{"results": [{"id": "...", "subjectType": "user", "subject": "alice", "role": "manager", "scope": "domain", "domain": "example.com", ...}, ...]}
List Permission Subjects
GET /api/permission/subjects
Autocomplete source for the “Subject” field: known usernames plus known group
names (local groups, groups already used in permissions, and groups from
conf.auth.adminGroups / conf.auth.groupRoleMap).
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/permission/subjects
Responses:
200{"users": ["alice", "bob"], "groups": ["ops", "sre"]}
Create Permission
POST /api/permission
Grant a role to a subject.
Parameters:
subjectType(required) -userorgroupsubject(required) - username or group namerole(required) -viewerormanagerscope(required) -globalordomaindomain(required ifscopeisdomain)
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"subjectType": "user", "subject": "alice", "role": "manager", "scope": "domain", "domain": "example.com"}' \
https://proxy-host.com/api/permission
Responses:
200{"message": "Granted manager to user \"alice\" on example.com.", ...}422Validation error
Delete Permission
DELETE /api/permission/:id
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/permission/<id>
Responses:
200{"message": "Permission <id> removed."}
Groups
Local groups (independent of any SSO/LDAP groups) used as subjects for
permission grants. Global-admin-only. Mounted at /api/group.
List Groups
GET /api/group
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/group
Responses:
200{"results": [{"name": "ops", "members": ["alice", "bob"], ...}, ...]}
Create Group
POST /api/group
Parameters:
name(required)members(optional) - array of usernames
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"name": "ops", "members": ["alice"]}' \
https://proxy-host.com/api/group
Responses:
200{"message": "Group \"ops\" created.", ...}
Delete Group
DELETE /api/group/:name
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/group/ops
Responses:
200{"message": "Group \"ops\" removed."}
Add Group Member
POST /api/group/:name/members
Parameters:
username(required)
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"username": "bob"}' \
https://proxy-host.com/api/group/ops/members
Responses:
200{"message": "Added \"bob\" to \"ops\".", ...}
Remove Group Member
DELETE /api/group/:name/members/:username
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/group/ops/members/bob
Responses:
200{"message": "Removed \"bob\" from \"ops\".", ...}
Hosts
Manage proxy host configurations.
List Hosts
GET /api/host
Get list of all configured hosts.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/host
Query Parameters:
detail- Include full host details (optional)
Responses:
200{"results": ["example.com", "*.wildcard.com"]}200{"results": [{"host": "example.com", "ip": "192.168.1.10", ...}, ...]}(with?detail=true)
Get Host
GET /api/host/:host
Get configuration for a specific host.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/host/example.com
Responses:
200{"item": "example.com", "results": {"host": "example.com", "ip": "192.168.1.10", "targetPort": 8080, ...}}404{"name": "HostNotFound", "message": "Host does not exists"}
Lookup Host
GET /api/host/lookup/:domain
Test the host lookup algorithm (supports wildcard matching).
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/host/lookup/sub.example.com
Responses:
200{"string": "sub.example.com", "results": {"host": "*.example.com", ...}}200{"string": "sub.example.com", "results": null}(no match)
Get Lookup Tree
GET /api/host/lookupobj
Get the internal lookup tree structure (for debugging).
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/host/lookupobj
Responses:
200{"results": {"com": {"example": {...}}}}
Create Host
POST /api/host
Add a new host configuration.
Parameters:
host(required) - Domain name (e.g.,example.com,*.example.com)ip(required) - Target IP address or FQDNtargetPort(required) - Target port number (1-65535)forcessl(optional) - Force HTTPS redirect (default: true)targetssl(optional) - Use HTTPS to backend (default: false)challengeType(optional) - For wildcards:DNS-01-wildcardorwildcardChild
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"host": "example.com", "ip": "192.168.1.10", "targetPort": 8080, "forcessl": true, "targetssl": false}' \
https://proxy-host.com/api/host
Responses:
200{"message": "\"example.com\" added.", "host": "example.com", ...}409{"name": "HostNameUsed", "message": "Host already exists"}422{"name": "ObjectValidateError", "message": ...}Validation error
Update Host
PUT /api/host/:host
Update an existing host configuration.
Parameters: Same as Create Host (all optional)
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X PUT \
-d '{"ip": "192.168.1.20", "targetPort": 9000}' \
https://proxy-host.com/api/host/example.com
Responses:
200{"message": "\"example.com\" updated.", ...}404{"name": "HostNotFound", "message": "Host does not exists"}422Validation error
Delete Host
DELETE /api/host/:host
Remove a host configuration.
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/host/example.com
Responses:
200{"message": "example.com deleted", ...}404{"name": "HostNotFound", "message": "Host does not exists"}
Clear Host Cache
DELETE /api/host/cache
Remove all cached wildcard-subdomain host lookups. Cache entries are created on demand when a wildcard host serves a subdomain; clearing them forces the next request for each subdomain to be resolved fresh through the lookup tree. Admin only.
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/host/cache
Responses:
200{"message": "Cleared 3 cached hosts.", "count": 3}
Renew Wildcard Certificate
PUT /api/host/:host/renew
Manually trigger wildcard certificate renewal.
curl -H "auth-token: your-token-here" \
-X PUT \
https://proxy-host.com/api/host/*.example.com/renew
Responses:
200{"message": "Requesting wildcard cert for *.example.com"}404Host not found
DNS Providers
Manage DNS provider integrations for wildcard SSL certificates.
List DNS Providers
GET /api/dns
Get list of configured DNS providers.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/dns
Query Parameters:
detail- Include full provider details (optional)
Responses:
200{"results": ["provider-id-1", "provider-id-2"]}
List Available Provider Types
OPTIONS /api/dns
Get list of supported DNS provider types and their configuration requirements.
curl -H "auth-token: your-token-here" \
-X OPTIONS \
https://proxy-host.com/api/dns
Responses:
200{"results": [{"name": "Cloudflare", "fields": {...}}, {"name": "DigitalOcean", ...}, {"name": "PorkBun", ...}, {"name": "DuckDns", ...}]}
Create DNS Provider
POST /api/dns
Configure a new DNS provider.
Cloudflare:
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"name": "My Cloudflare", "dnsProvider": "Cloudflare", "token": "your-api-token"}' \
https://proxy-host.com/api/dns
DigitalOcean:
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"name": "My DO", "dnsProvider": "DigitalOcean", "token": "your-api-token"}' \
https://proxy-host.com/api/dns
PorkBun:
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"name": "My PorkBun", "dnsProvider": "PorkBun", "apiKey": "pk_xxx", "secretApiKey": "sk_xxx"}' \
https://proxy-host.com/api/dns
DuckDNS (free):
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"name": "My DuckDNS", "dnsProvider": "DuckDns", "token": "your-duckdns-token", "subdomains": "myhost,myhost2"}' \
https://proxy-host.com/api/dns
subdomains is a comma-separated list of the subdomains you’ve registered at
duckdns.org (e.g. myhost for
myhost.duckdns.org), since DuckDNS has no API to list them for you.
DuckDNS only supports one A/AAAA record and one TXT record per domain (no
arbitrary sub-records) — enough for dynamic DNS and DNS-01 wildcard certs.
Responses:
200{"message": "\"provider-id\" added.", ...}422Validation error or invalid API credentials
Get DNS Provider
GET /api/dns/:id
Get a specific DNS provider configuration.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/dns/provider-id
Responses:
200{"item": "provider-id", "results": {...}}404Provider not found
Update DNS Provider
PUT /api/dns/:id
Update DNS provider configuration.
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X PUT \
-d '{"name": "Updated Name"}' \
https://proxy-host.com/api/dns/provider-id
Responses:
200{"message": "\"provider-id\" updated.", ...}404Provider not found
Delete DNS Provider
DELETE /api/dns/:id
Remove a DNS provider and all associated domains.
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/dns/provider-id
Responses:
200{"message": "provider-id deleted", ...}404Provider not found
List Domains
GET /api/dns/domain
List all domains from all configured providers.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/dns/domain
Query Parameters:
detail- Include full domain details (optional)
Responses:
200{"results": ["example.com", "test.com"]}
Get Domain
GET /api/dns/domain/:domain
Get details for a specific domain.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/dns/domain/example.com
Responses:
200{"results": [{"domain": "example.com", "zoneId": "...", ...}]}404Domain not found
Refresh Domains
POST /api/dns/domain/refresh/:providerId
Refresh the domain list from a DNS provider’s API.
curl -H "auth-token: your-token-here" \
-X POST \
https://proxy-host.com/api/dns/domain/refresh/provider-id
Responses:
200{"results": ...}Updated domain list404Provider not found
Dynamic DNS
A-records kept automatically pointed at this box’s public (WAN) IP. All
/api/dns/dynamic* routes are viewer/manager scoped to the record’s domain
(via Permissions), not admin-only like the rest of /api/dns.
Get Current Public IP
GET /api/dns/dynamic/ip
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/dns/dynamic/ip
Responses:
200{"ip": "203.0.113.5"}
List Dynamic Records
GET /api/dns/dynamic
Lists records the caller may view (their own/granted domains, or all for admins).
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/dns/dynamic
Responses:
200{"results": [{"id": "...", "domain": "example.com", "name": "home", "last_status": "ok", ...}, ...]}
Create Dynamic Record
POST /api/dns/dynamic
Requires manager rights on the target domain. Applies the record immediately
against the current public IP (best-effort — failures are recorded in
last_status and retried by the scheduler).
Parameters:
domain(required)name(required) - sub-label, or@for the apex
curl -H "Content-Type: application/json" \
-H "auth-token: your-token-here" \
-X POST \
-d '{"domain": "example.com", "name": "home"}' \
https://proxy-host.com/api/dns/dynamic
Responses:
200{"message": "\"home.example.com\" added.", ...}403Missingmanagerrights on the domain422Validation error
Refresh Dynamic Record
POST /api/dns/dynamic/:id/refresh
Force an immediate refresh of one record against the current public IP.
Requires manager rights on the record’s domain.
curl -H "auth-token: your-token-here" \
-X POST \
https://proxy-host.com/api/dns/dynamic/<id>/refresh
Responses:
200{"message": "Refreshed \"home.example.com\".", "result": {...}}403Missingmanagerrights on the domain
Delete Dynamic Record
DELETE /api/dns/dynamic/:id
Stop managing a record. Requires manager rights on the record’s domain.
Leaves the provider’s A record in place at its last value.
curl -H "auth-token: your-token-here" \
-X DELETE \
https://proxy-host.com/api/dns/dynamic/<id>
Responses:
200{"message": "home.example.com removed.", ...}403Missingmanagerrights on the domain
Certificates
Retrieve SSL certificate information.
Get Certificate
GET /api/cert/:host
Get the SSL certificate for a host.
curl -H "auth-token: your-token-here" \
https://proxy-host.com/api/cert/example.com
Responses:
200Certificate data includingcert_pem,fullchain_pem,privkey_pem, expiry information404Certificate not found
Error Responses
All endpoints may return the following error responses:
401{"name": "LoginFailed", "message": "Invalid Credentials, login failed."}- Authentication required or invalid404{"name": "NotFound", "message": "..."}- Resource not found422{"name": "ObjectValidateError", "message": [...], "keys": [...]}- Validation errors500Internal server error
Notes
- All timestamps are in milliseconds since epoch
- Authenticated endpoints accept either the
auth-tokenheader (browser session / OIDC login) or anAuthorization: Bearer <token>API token - Host names support wildcards:
*(single level) and**(multi-level) - DNS providers are validated on creation - invalid API credentials will be rejected
- Wildcard certificates are automatically renewed 30 days before expiration