The bundled admin-http-rpc plugin exposes an allowlisted set of Gateway control-plane methods over HTTP, for trusted host automation that cannot keep a Gateway WebSocket connection open.

It ships with Apus but is disabled by default; when disabled, the route is not registered. When enabled, it adds POST /api/v1/admin/rpc on the same listener as the Gateway (http://<gateway-host>:<port>/api/v1/admin/rpc).

Enable it only for private host tooling, tailnet automation, or a trusted internal ingress. Never expose this route directly to the public internet.

Before you enable it

Admin HTTP RPC is a full operator control-plane surface: any caller that passes Gateway HTTP auth can invoke the allowlisted methods below. Enable it only when all of these are true:

For Apus clients and interactive tools that can keep a Gateway WebSocket connection open, use WebSocket RPC instead.

Enable

Enable the bundled plugin:

CLI

```bash
apus plugins enable admin-http-rpc
```

Config

```json5
{
  plugins: {
    entries: {
      "admin-http-rpc": { enabled: true },
    },
  },
}
```

Enablement applies to a running Gateway automatically. If it is offline, start it to register the route. With the default hybrid reload mode, plugin config and load-path changes also apply automatically. After source or manifest edits, run apus plugins reload admin-http-rpc. See Apply changes and inspect.

Disable it when you no longer need the HTTP surface:

apus plugins disable admin-http-rpc

Verify the route

Use health as the smallest safe request:

curl -sS http://<gateway-host>:<port>/api/v1/admin/rpc \
  -H 'Authorization: Bearer <gateway-token>' \
  -H 'Content-Type: application/json' \
  -d '{"method":"health","params":{}}'

A successful response has ok: true:

{
  "id": "generated-request-id",
  "ok": true,
  "payload": {
    "status": "ok"
  }
}

When the plugin is disabled, the route returns 404 because it is not registered.

Authentication

The plugin route uses Gateway HTTP auth.

Common authentication paths:

Security model

Treat this plugin as a full Gateway operator surface.

Request

POST /api/v1/admin/rpc
Authorization: Bearer <gateway-token>
Content-Type: application/json
{
  "id": "optional-request-id",
  "method": "health",
  "params": {}
}

Fields:

The default max request body size is 1 MB.

Response

Success responses use the Gateway RPC shape:

{
  "id": "optional-request-id",
  "ok": true,
  "payload": {}
}

Gateway method errors use:

{
  "id": "optional-request-id",
  "ok": false,
  "error": {
    "code": "INVALID_REQUEST",
    "message": "bad params"
  }
}

HTTP status follows the error code:

Error code HTTP status
INVALID_REQUEST 400
APPROVAL_NOT_FOUND 404
NOT_LINKED, NOT_PAIRED 409
UNAVAILABLE 503
AGENT_TIMEOUT 504
any other code 500

Allowed methods

Other Gateway methods are blocked until they are intentionally added.

WebSocket comparison

The normal Gateway WebSocket RPC path remains the preferred control-plane API for Apus clients. Use admin HTTP RPC only for host tooling that needs a request/response HTTP surface.

Shared-token WebSocket clients without a trusted device identity cannot self-declare admin scopes during connect. Admin HTTP RPC deliberately follows the existing trusted HTTP operator model: when the plugin is enabled, shared-secret bearer auth is treated as full operator access for this admin surface.

Troubleshooting

404 Not Found The plugin is disabled, runtime application failed, or the request is going to a different Gateway process. Check the enablement result and inspect the plugin.

401 Unauthorized The request did not satisfy Gateway HTTP auth. Check the bearer token or the trusted-proxy identity headers.

405 Method Not Allowed The request used something other than POST.

413 Payload Too Large The request body exceeded the 1 MB limit.

400 INVALID_REQUEST The request body is not valid JSON, the method field is missing, the method is not in the plugin allowlist, or a suspension resume ID does not match the active lease.

503 UNAVAILABLE The Gateway method is starting, rate-limited, suspended, or waiting on a competing suspension/resume operation. Inspect error.details when present and honor error.retryAfterMs before retrying.

Related