> ## Documentation Index
> Fetch the complete documentation index at: https://orbit.nckrtl.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Realtime events with Reverb

> Turn on realtime events with the websocket role, what its converge installs, how to move it, and how to verify it.

# Realtime events with Reverb

## Problem

The web app and `realtime:tail` need the Gateway to push events. The Gateway publishes through Laravel Reverb, and clients subscribe at `wss://reverb.orbit`. [Realtime events](/docs/reference/events) defines the channels and the events.

## Cause

Reverb holds long-lived WebSocket connections, so it runs outside the Gateway process. It is a plain Laravel app with no Orbit code. The Gateway installs and runs it as the `websocket` role, the same way the `metrics` role runs Prometheus and Grafana.

## Solution

### Add the role

```bash theme={"dark"}
orbit node:role:add gateway websocket
```

The `websocket` role is a singleton. It conflicts with no other role, so it can share a Node with `gateway` and `vpn`. No Project, Instance, Route, or `.env` edit is involved.

### What the converge does

1. It installs the role packages: `caddy`, `composer`, `git`, `openssl`, `php-curl`, and `php-xml`. `php-curl` and `php-xml` let `composer install` pass its platform check on a fresh Ubuntu 26.04 Node.
2. It generates a Reverb app ID, app key, app secret, and a Laravel `APP_KEY` the first time, and reuses them later. It stores them as settings of that Node. The secret and `APP_KEY` are encrypted.
3. It checks out `https://github.com/nckrtl/orbit-reverb.git` at `main` into `/opt/orbit/websocket` as the managed user and runs `composer install --no-dev`.
4. It writes the app's `.env` with mode `0600`.
5. It installs and starts `orbit-websocket.service`, which runs `php artisan reverb:start --host=127.0.0.1 --port=8790` with `Restart=always`.
6. It issues an Orbit CA certificate for `reverb.orbit` and adds a Caddy site on the Node that proxies to Reverb. Caddy admits the WebSocket upgrade.
7. It publishes `reverb.orbit` in private DNS with the Node's WireGuard address.

Before any change, the converge refuses a Node that lacks an address its Caddy sites bind, so a refused converge leaves a running Reverb alone. When a step after the runtime fails, the converge stops the runtime again. A failed rollback reports `websocket.rollback_failed`.

`ORBIT_WEBSOCKET_REPOSITORY`, `ORBIT_WEBSOCKET_REF`, `ORBIT_WEBSOCKET_INSTALL_PATH`, and `ORBIT_WEBSOCKET_PORT` in the Gateway `.env` change the defaults. Another Reverb app must accept client events from channel members (`accept_client_events_from` set to `members`), as `orbit-reverb` does. Without it, the [Node agent channels](/docs/reference/events#node-agent-channels) carry no agent events.

The Gateway reads the connection from the active role assignment. It needs no broadcast setting in its `.env`.

### Move the role

```bash theme={"dark"}
orbit node:role:relocate <node> websocket --force
```

Relocate copies the Reverb identity to the target when the target has none, and never overwrites one. It converges the target and points `reverb.orbit` at it. It then waits 31 seconds, the private DNS answer TTL plus one second, so clients that resolved the old address resolve again. Then it removes the runtime and publication from the source. The Reverb checkout stays on the source. Clients keep the same key. Removing the role and adding it again would generate a new identity, and every client would need the new key. [`node:role:relocate`](/docs/cli/node#orbit-noderolerelocate) describes `--from` for a target that already holds the role.

### Remove the role

`orbit node:role:remove <node> websocket --force` withdraws the Caddy site, stops and disables the unit, removes the certificate and DNS record, and deletes the stored credentials. `--purge-data` also deletes the checkout. With `--offline`, the Gateway removes only the DNS record and the credentials.

## Limits

This covers one Reverb server behind one `websocket` assignment. It does not cover several Reverb Nodes, Redis-backed scaling, or rotating the Reverb secret without a reconnect.

## Verification

```bash theme={"dark"}
orbit realtime:show
orbit doctor --node=<node-id> --family=role
getent ahostsv4 reverb.orbit
```

`orbit realtime:show` reports `configured` and `wss://reverb.orbit`. `getent` resolves `reverb.orbit` to the role Node's WireGuard address. On the Node, `systemctl is-active orbit-websocket` prints `active`. From a Node that trusts the Orbit CA, `curl -i -X POST https://reverb.orbit/apps/<app-id>/events` answers `401` with `Authentication signature invalid`, which proves that Reverb answers behind the Caddy site.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.