API Documentation

← Back to Home

All API endpoints require authentication unless otherwise noted. Three authentication methods are supported:

  • auth-token header — a browser-session token from POST /api/auth/login or 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 via GET /api/auth/oidc/start instead 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:

  • 302 Redirect to the SSO’s authorization endpoint
  • 404 {"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 SSO
  • state (required) - State value from the start step
# Not called directly — the SSO redirects the browser here after login.

Responses:

  • 302 Redirect 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 name
  • description (optional)
  • expires_in_days (optional) - 0 or 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": {...}}
  • 403 Not 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)
  • 403 Not 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:

  • 200 User created successfully
  • 403 Not an admin
  • 409 Username already exists
  • 422 {"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": ...}
  • 403 Not an admin
  • 404 User 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 successfully
  • 422 Weak 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 successfully
  • 403 Not an admin
  • 404 User 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) - user or group
  • subject (required) - username or group name
  • role (required) - viewer or manager
  • scope (required) - global or domain
  • domain (required if scope is domain)
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.", ...}
  • 422 Validation 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 FQDN
  • targetPort (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-wildcard or wildcardChild
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"}
  • 422 Validation 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"}
  • 404 Host 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.", ...}
  • 422 Validation 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": {...}}
  • 404 Provider 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.", ...}
  • 404 Provider 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", ...}
  • 404 Provider 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": "...", ...}]}
  • 404 Domain 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 list
  • 404 Provider 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.", ...}
  • 403 Missing manager rights on the domain
  • 422 Validation 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": {...}}
  • 403 Missing manager rights 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.", ...}
  • 403 Missing manager rights 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:

  • 200 Certificate data including cert_pem, fullchain_pem, privkey_pem, expiry information
  • 404 Certificate not found

Error Responses

All endpoints may return the following error responses:

  • 401 {"name": "LoginFailed", "message": "Invalid Credentials, login failed."} - Authentication required or invalid
  • 404 {"name": "NotFound", "message": "..."} - Resource not found
  • 422 {"name": "ObjectValidateError", "message": [...], "keys": [...]} - Validation errors
  • 500 Internal server error

Notes

  • All timestamps are in milliseconds since epoch
  • Authenticated endpoints accept either the auth-token header (browser session / OIDC login) or an Authorization: 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