Hub mode

pyobs-web-admin can act as a hub to control multiple remote pyobs hosts from a single browser session. When remote hosts are configured, a Hosts section appears at the top of the sidebar; clicking a host switches the active context, and most views (dashboard, config, logs) transparently proxy their actions to that host’s own API instead of the local one.

Setup

On the hub (the machine you browse to), list the remote hosts:

HUB_HOSTS = [
    {"name": "obs1", "url": "http://obs1:8765", "token": "shared-secret"},
    {"name": "obs2", "url": "http://obs2:8765", "token": "another-secret"},
]

On each remote host (a “spoke”), give it a named client entry matching the token the hub sends for it:

HUB_CLIENTS = [
    {"name": "hub", "token": "shared-secret"},   # must match HUB_HOSTS' token above
]

Authentication

The hub – or any other external caller – authenticates to a remote instance via an X-Hub-Token header. A remote instance checks that header against every entry in HUB_CLIENTS (each entry is {"name": ..., "token": ...}); a match bypasses the normal browser-session/CSRF check for that request, which is what lets an external caller invoke the API without a login session of its own. Each caller (a hub, a script, another service) should get its own named entry so it can be revoked or rotated independently, without affecting any other caller. The token is a plain pre-shared string with no other layer on top of it, so treat it like any other bearer credential: long, random, and secret.

The older HUB_TOKEN setting (a single flat token, no name) still works for backwards compatibility – it’s equivalent to adding {"name": "default", "token": HUB_TOKEN} to HUB_CLIENTS. New setups should use HUB_CLIENTS directly so that every caller is independently identifiable and revocable.

This mechanism isn’t hub-specific – any external client that sends a valid X-Hub-Token can call the same endpoints the hub does. See HTTP API reference for the full list.

One active host at a time – and the exception

Most hub-aware views (Dashboard, Config, Logs) follow a “one active host at a time” model: whichever host the sidebar selector points at is the one all actions target, mirroring a single-host session. A few pages instead need to aggregate every configured host on one page regardless of the active-host selection – the ACL matrix and per-module ACL editing matrix, the fleet-wide Overview page, and the fleet-wide Users page (XMPP user management) all fall into this second category, since their entire purpose is a cross-host view. Each of those pages queries every HUB_HOSTS entry independently and shows unreachable hosts as a warning banner rather than failing the whole page or hiding the gap silently.