Overview
Installingproxy-hopper-webserver (pip install proxy-hopper-webserver) adds a second HTTP server, on its own port (default 8081), exposing:
The GraphQL API lets you query and mutate targets, IP pools, and providers at runtime — without restarting the server and without editing the config file.
Embedded vs separate process
There are two ways to run the admin server, and which one is correct depends entirely on which backend you’re using:
Since
backend: memory only ever supports a single proxy instance anyway (there’s no way to share its state across replicas without Redis), embedding admin doesn’t cost you anything you didn’t already have — there was never going to be more than one node.
If
proxy-hopper-webserver isn’t installed, --admin fails startup immediately with a clear error rather than silently running without it — the same fail-fast behavior as requesting --backend redis without proxy-hopper-redis installed.Enabling the admin server
Both the embedded (run --admin) and separate-process (admin subcommand) topologies share the same server.admin/adminPort/adminHost config fields:
Read-only mode
By default, the admin server can both query and mutate runtime state — targets, pools, and providers created or edited through the GraphQL API are held in the config store (or, with no config store configured, an in-process store that doesn’t survive a restart). Setserver.adminReadOnly to run it as monitoring-only instead: every GraphQL mutation is rejected, and all config comes from the YAML file alone.
PermissionError in the GraphQL errors array — the same shape as a role-based permission failure, so existing error handling in a client or the admin UI needs no special case for it. Queries are completely unaffected: status, targets, pools, providers, and targetMetrics all keep working, which is the point — you still get a fully usable monitoring surface, just not a mutable one.
adminReadOnly is checked before role-based auth, so it applies even when auth.enabled is false. It’s also independent of configStoreUrl/configStore.dialect — the two combine into four real deployment shapes:status query (and GET /api/v1/status) reports the current mode via readOnly, so a client or dashboard can detect it without attempting a mutation first:
Authentication
Ifauth.enabled: true is set, every request to protected endpoints must include an Authorization: Bearer <token> header. The token can be:
- A JWT obtained from
POST /auth/login(requiresauth.adminto be configured) - An API key declared in
auth.apiKeys - An OIDC token (when
auth.oidcis configured)
/health endpoint is always public.
When auth is disabled, all endpoints are accessible without credentials. This is acceptable for internal-only deployments where the admin port is not exposed outside your network.
Obtaining a JWT
GraphQL playground
With the admin server running, openhttp://localhost:8081/graphql in a browser to access the interactive GraphQL playground. You can explore the schema, run queries, and test mutations directly from the browser.
If auth is enabled, add your token via the playground’s “Headers” panel: