Realtime (Mercure)
How FeatherPanel pushes live updates through the Mercure hub in FrankenPHP: turning it on or off, the JWT keys, private topics, proxies and the polling fallback.
On this page
FeatherPanel uses the Mercure hub built into FrankenPHP to tell browsers that something changed, so pages refresh at once instead of polling. Events only say what changed, never the data itself; the browser fetches the new data through the normal API.
What uses it
| Topic | Events |
|---|---|
/servers/<uuidShort> | Server state and backup changes. |
/notifications | Announcements created, edited or deleted by an admin. |
/users/<uuid> | New items in the user’s notification inbox. |
/admin/webspaces | WebSpace changes in the admin list. |
How it is turned on
On start, the backend sources caddy/frankenphp-env.sh, which reads FEATHERPANEL_MERCURE:
auto(default): usesMERCURE_SUBSCRIBER_JWT_KEYandMERCURE_PUBLISHER_JWT_KEYfrom the environment, else fromstorage/config/.env, else generates both once and saves them to.env. If both are at least 32 characters, the hub is mounted.off: no hub, the panel polls.
The startup log prints FrankenPHP: live updates (Mercure) on or off.
How browsers connect
- The frontend calls
POST /api/user/realtime/tokenwith the topics it wants. The backend only grants topics the user may see and signs a token valid for one hour. - The browser opens one stream per tab to
/api/mercureand sends the token in theAuthorizationheader, never in the URL. - After a reconnect the page refetches, because the hub stores nothing (
transport local).
Reverse proxies
The stream goes through /api/mercure, so any proxy that already forwards /api/* works. It must not buffer or compress
the response. The hub sends X-Accel-Buffering: no for nginx and a heartbeat every 25 seconds to keep idle connections
open. See Web server.
MERCURE_PUBLIC_URL overrides the URL the browser uses and MERCURE_PUBLISH_URL lets the backend publish to an
external hub over HTTP. Neither is needed with the bundled setup.
Frequently asked questions
No. The backend container generates the two keys on first start and turns the hub on by itself. Set FEATHERPANEL_MERCURE=off to disable it.
The panel falls back to polling, so pages still refresh, just less quickly. Check that your proxy does not buffer /api/mercure.
No. Topics are private and the subscriber token only lists topics the signed-in user may see.