158 lines
15 KiB
Markdown
158 lines
15 KiB
Markdown
# Administration API and configuration automation
|
||
|
||
RustProxy exposes an authenticated administration API on the **separate administration listener** (normally `127.0.0.1:9090`). Open **`/docs → API`** after signing in to view the bundled OpenAPI/Swagger schema, including request bodies and available actions. That schema is the endpoint reference; server validation remains authoritative.
|
||
|
||
## Selected API endpoints
|
||
|
||
The current bundled `src/admin/openapi.json` declares these operations (among others):
|
||
|
||
| Method and path | Purpose |
|
||
|---|---|
|
||
| `GET /healthz` | Minimal health response, without privileged state. |
|
||
| `GET /api/auth/status` | Whether first-time administrator setup is required. |
|
||
| `POST /api/auth/login` · `POST /api/auth/logout` | Start/end a browser admin session. |
|
||
| `GET /api/auth/session` | Validate current admin session. |
|
||
| `GET /api/config` · `PUT /api/config` | Read or replace validated, revisioned configuration. GET also returns read-only `storage` metadata (SQLite/JSON source and paths). |
|
||
| `POST /api/config/reload` | Revalidate and hot-reload manually changed `--config` JSON; revision-aware. |
|
||
| `GET/POST /api/api-tokens` · `DELETE /api/api-tokens/{id}` | List/generate/revoke general RO/RW API tokens (browser-admin-only). |
|
||
| `GET/POST/DELETE /api/prometheus-token` | Inspect/generate/rotate/revoke a standalone Prometheus scrape token (browser-admin-only). |
|
||
| `GET /api/config/{section}` · `PUT /api/config/{section}` | Read or atomically replace one of 23 supported configuration sections. |
|
||
| `POST /api/config/geoip/update` | Run a GeoIP download/check/reload immediately using already-saved GeoIP settings; does not change revision. |
|
||
| `GET /api/config/history` · `POST /api/config/history/restore` | Review/restore retained configuration snapshots. |
|
||
| `GET /api/status` · `GET /api/backends` | Operational status and backend observations. |
|
||
| `GET /api/cache` · `POST /api/cache/purge` · `POST /api/cache/invalidate` | Cache observations and authenticated invalidation. `GET` supports the lightweight `view=live` polling view. |
|
||
| `GET /api/transform` | Transform observations and resource usage. Supports the lightweight `view=live` polling view. |
|
||
| `GET /api/logs` · `GET /api/live-logs` | Recent and streaming request logs. |
|
||
| `GET /api/file-logs` · `GET /api/file-logs/query` | Stored-log exploration. |
|
||
| `GET /api/traffic` · `GET /api/system-info` | Traffic and system observations. Traffic supports the lightweight `view=live` polling view. |
|
||
| `GET /api/metrics/json` · `GET /api/metrics/summary` | Full JSON snapshot (includes all Prometheus samples and `summary`) or compact computed `summary` only, both pull-only. [Monitoring](MONITORING.md). |
|
||
| `GET /api/docker` · `POST /api/docker/refresh` | Docker-agent observation and refresh. |
|
||
| `GET /api/certificates` · `POST /api/certificates/upload` | Certificate inventory/import. |
|
||
| `POST /api/certificates/inspect` | Read DNS SAN coverage from a managed/external public PEM path for the editor; admin browser session only. |
|
||
| `GET /api/acme` · `POST /api/acme/issue` · `POST /api/acme/renew` | Managed certificate jobs. |
|
||
| `GET/PUT /api/preferences` | Personal UI settings, including theme/layout and optional `interface_icons` (default `false`). |
|
||
| `GET /api/dashboard-presets` and named preset operations | Saved Overview presets. |
|
||
| `GET /docs/openapi.json` | Protected machine-readable API specification. |
|
||
|
||
Some paths have additional DELETE/PATCH operations, job-status resources, query parameters or restricted actions. Use OpenAPI for the **actual fields/methods**, not guesses based on a table. `GET /metrics` here is not a replacement for the separate Prometheus exporter.
|
||
|
||
For browser polling, `GET /api/cache?view=live`, `GET /api/transform?view=live` and `GET /api/traffic?view=live` omit static response members that do not need to be retransmitted on every interval. Their `revision` identifies the active configuration; when it changes, clients should fetch the corresponding endpoint without `view=live` and refresh their cached static fields. Requests without `view=live` remain the complete compatibility form. Cache live responses contain metrics/dashboard/bans, Transform live responses contain resources/metrics, and Traffic live responses retain current settings/GeoIP/analytics while omitting the static Vhost list. Unknown `view` values are rejected.
|
||
|
||
Certificate inspection accepts `{ "cert_file": "filename.pem" }` for a managed file or an absolute external path and returns `{ "cert_file": "...", "covered_hosts": ["example.com"] }`. It applies the existing certificate-file trust and size checks and reads no private key. It makes no configuration or permission changes. This POST requires the signed-in administrator's normal Origin, request-marker and CSRF checks; general RO/RW API tokens and certificate-only credentials cannot call it.
|
||
|
||
## Access and authentication
|
||
|
||
The administration listener is HTTP on loopback (`127.0.0.1:9090`) by default and is separate from the public Vhost listeners. No administrator password is bundled: complete first-time setup with the local CLI (`admin setup-token` or `admin init`). For remote access prefer an SSH tunnel; for direct access enable administration HTTPS with a trusted certificate and restrict the network before binding outside loopback.
|
||
|
||
| Credential | Scope |
|
||
|---|---|
|
||
| Browser session | Full administration. HttpOnly, SameSite=Strict cookie (Secure on HTTPS), absolute lifetime 7–30 days. Writes require matching Origin, `X-CSRF-Token` and `X-RustProxy-Request: 1`. |
|
||
| General API token (`ro` / `rw`) | Created in **Settings → Security → API tokens**. Displayed once, stored as a hash, bound to a mandatory IP/CIDR allowlist. Sent as `Authorization: Bearer <token>`. `ro` reads resources and sections; `rw` also writes configuration sections and selected operations. Cannot manage authentication, backups, tokens or certificate credentials. |
|
||
| Certificate API key | Key ID + Bearer token limited to specific certificate IDs and actions (reload by default, deploy opt-in). |
|
||
| Prometheus token | Scrape-only credential for the separate exporter; see [Monitoring](MONITORING.md). |
|
||
|
||
IP checks use the transport peer, never forwarded headers. Outside loopback, Bearer credentials require administration HTTPS.
|
||
|
||
### `/docs` Reader and Swagger
|
||
|
||
The authenticated `/docs` page has two tabs: **Reader** with the guides embedded at build time, and **API** with the bundled OpenAPI schema rendered by Swagger UI. All assets are served locally; no CDN is used. Swagger uses the current session, executes read calls directly and asks for confirmation before any write.
|
||
|
||
### Publishing the panel behind a reverse proxy
|
||
|
||
This is a special-risk topology. Configure a fixed HTTPS public origin, an allowed hostname and a trusted forwarding boundary. Ordinary public Vhosts never forward administration cookies to an upstream. Re-test CSRF/Origin validation and cookie security after any topology change.
|
||
|
||
## Authentication and safe writes
|
||
|
||
- Ordinary API calls require an administrator browser/session cookie on the admin listener, or a scoped general API Bearer token for explicitly allowlisted API methods/paths. Browser-session writes require the matching Origin, `X-CSRF-Token` and `X-RustProxy-Request: 1`, in addition to Host validation. Scoped Bearer-token requests are exempt from browser CSRF requirements; the server enforces the token permission, source IP allowlist and HTTPS for non-loopback access instead.
|
||
- The Swagger **API** tab uses the signed-in session. Read calls can be executed; mutations require explicit confirmation. It cannot bypass server-side authorization.
|
||
- The serialized configuration limit is 2 MiB across all sections; JSON request bodies allow a bounded 64 KiB formatting overhead. Saves over the limit are rejected without applying partial changes.
|
||
- Configuration writes are revisioned (`expected_revision`) and rejected if based on a stale save. `GET /api/config` returns `{revision, config, storage}`; `storage` is runtime metadata and must not be copied inside the editable `config` object or included as a write parameter. PUT and history-restore responses remain `{revision, config}`. Prefer section updates over replacing the entire document when practical.
|
||
- Each supported section has the same **GET** and **PUT** value shape. `GET /api/config/cache` returns `{revision, section: "cache", value: {…}}`. `PUT /api/config/cache` accepts `{"expected_revision": 12, "value": {…}}`, using the **entire** section value from a fresh GET after modification. The response is the full updated `{revision, config}` envelope (not a section view). Even changes to different sections must use the latest global revision: concurrent stale writes return 409. This is replacement, not JSON Merge Patch.
|
||
- Section boundaries: `logging` uses `{"logging": {…}, "error_log": {…}}`; `response` uses `{"server_header": {…}, "diagnostic_headers": {…}, "compression": {…}}`; `global-security` uses a **single** `GlobalSecurity` object including `user_agent_blocking`. For this section, omitting `user_agent_blocking` is an invalid PUT rather than silently clearing the denylist. Independent `user-agent-blocking` and `error_log` section endpoints do not exist. The prior logging-only `PUT /api/config/logging` payload is no longer accepted: read the full logging section and send the paired value.
|
||
- The section names use kebab-case (e.g. `not-found-hosts`, `docker-agents`, `global-security`) even when the matching configuration JSON key is snake_case (`not_found_hosts`, `docker_agents`, `global_security`). GeoIP configuration lives at `GET/PUT /api/config/geoip` (serialized from `config.geoip_updates`). After saving, `POST /api/config/geoip/update` triggers a source refresh. The old standalone `/api/geoip/update` no longer exists. This action changes loaded database files, **not** the config revision. A read-only API token cannot execute it; a read/write token can.
|
||
- Full-document config imports remain backward compatible with older root-level `user_agent_blocking`; it is migrated into `global_security.user_agent_blocking` when validated. If both positions contain conflicting policies, the import is rejected. Canonical GET and saved config use the nested field. Per-vhost `user_agent_blocking` is unchanged. RO General API tokens may GET sections, RW tokens may PUT sections; the same existing authentication, Host/Origin, revision and audit checks apply.
|
||
- `/docs`, API schemas, configuration, logs, certificates and most observations are **not anonymous**. Keep the listener restricted and use HTTPS or a tunnel for remote access.
|
||
|
||
### Available configuration sections
|
||
|
||
The section name in the URL and its corresponding JSON member in a full configuration are:
|
||
|
||
| Section path (`/api/config/…`) | JSON member(s) in `config` |
|
||
|---|---|
|
||
| `listeners` | `listeners` |
|
||
| `docker-agents` | `docker_agents` |
|
||
| `http2` | `http2` |
|
||
| `pages` | `pages` |
|
||
| `cache` | `cache` |
|
||
| `transform` | `transform` |
|
||
| `forwarding` | `forwarding` |
|
||
| `headers` | `headers` |
|
||
| `prometheus` | `prometheus` |
|
||
| `geoip` | `geoip_updates` |
|
||
| `administration` | `administration` |
|
||
| `tls` | `tls` |
|
||
| `vhosts` | `vhosts` |
|
||
| `web-services` | `web_services` |
|
||
| `php-fpm-profiles` | `php_fpm_profiles` |
|
||
| `redirects` | `redirects` |
|
||
| `not-found-hosts` | `not_found_hosts` |
|
||
| `streams` | `streams` |
|
||
| `acl-profiles` | `acl_profiles` |
|
||
| `host-policies` | `host_policies` |
|
||
| `response` | `server_header`, `diagnostic_headers`, `compression` |
|
||
| `logging` | `logging`, `error_log` |
|
||
| `global-security` | `global_security`, including `user_agent_blocking` |
|
||
|
||
Every GET returns a `value` object or array whose shape can be sent unchanged to the matching PUT. For the three grouped sections the `value` contains exactly the named members; for the other sections it is the serialized value of the matching configuration member. Saving does not alter unrelated sections. An ordinary Vhost may configure mutually exclusive `oidc`, `authelia` and `authentik` objects alongside existing `tinyauth`/`basic_auth` settings; every optional provider defaults to disabled. OIDC uses `/_rustproxy/oidc/callback` on an exact Vhost HTTPS hostname and requires issuer/client/session secrets. See [Access](ACCESS.md).
|
||
|
||
### Complete section-update example
|
||
|
||
```http
|
||
GET /api/config/global-security
|
||
```
|
||
|
||
```json
|
||
{
|
||
"revision": 7,
|
||
"section": "global-security",
|
||
"value": {
|
||
"user_agent_blocking": {"enabled": true, "patterns": ["bad-bot"]},
|
||
"country_access": {"mode": "off", "countries": []},
|
||
"acl": null,
|
||
"method_policy": {"mode": "off", "methods": []},
|
||
"content_type_policy": {"enabled": false, "blocked": []},
|
||
"rate_limit": {"enabled": false, "requests": 100, "window_seconds": 60, "burst": 20},
|
||
"security_headers": {"hsts": {"enabled": false, "max_age_seconds": 31536000, "include_subdomains": false, "preload": false}, "nosniff": false, "frame_options": "preserve", "referrer_policy": null, "content_security_policy": null, "permissions_policy": null}
|
||
}
|
||
}
|
||
```
|
||
|
||
Use the actual **complete** `value` returned from GET as the PUT `value` after editing it; the example is illustrative, not a substitute for fetching the active defaults. Then send `PUT /api/config/global-security` with `{"expected_revision":7,"value":{...}}`. A successful PUT returns the complete new configuration envelope; HTTP **409** requires re-reading the section and applying the intended changes to the newer revision. GET never writes. The UI and API use the same validation and transaction path.
|
||
|
||
## Local CLI alternatives
|
||
|
||
The included `rust-proxy` program supports configuration and backup operations without turning browser sessions into automation tokens:
|
||
|
||
```bash
|
||
rust-proxy --data-dir /var/lib/rustproxy config get
|
||
rust-proxy --data-dir /var/lib/rustproxy config validate config.json
|
||
rust-proxy --data-dir /var/lib/rustproxy config apply config.json
|
||
rust-proxy --data-dir /var/lib/rustproxy config reload
|
||
rust-proxy --data-dir /var/lib/rustproxy backup create --output /private/site.rpb
|
||
```
|
||
|
||
Run CLI commands as an authorized local operator with the correct private data directory. The `admin` subcommands provide first setup, password recovery, session revocation and status; `tls` supports certificate generate/import/deploy/reload. Run `rust-proxy --help` for exact options.
|
||
|
||
## Restricted Certificate API credentials
|
||
|
||
**Settings → Certificate API** can create credentials containing a **Key ID + Bearer token** with explicit certificate-ID grants. New keys default to reload-only; deploy permission is separate. The clear token is displayed at creation/rotation and is not a general admin API token.
|
||
|
||
An authorized client sends:
|
||
|
||
```text
|
||
Authorization: Bearer <secret>
|
||
X-RustProxy-Certificate-Key: <key-id>
|
||
```
|
||
|
||
The credential can be used only for allowed certificate reload/deploy operations, not configuration, users, metrics or secret management. Non-loopback use requires the appropriate administration HTTPS security boundary. Rotate broad or legacy credentials. See [Certificates](CERTIFICATES.md).
|