# Public rerun viewer — rerun.omidlab.net

How any rerun session running on a robot station (russet today) is viewable at a
public HTTPS URL, with no `ssh -L` on the viewer's laptop. Set up 2026-07-08;
the cloudflare + DNS pieces are permanent, the ssh relay is the only part that
ever needs re-arming.

**Viewer URL (bookmark this):**

```
https://rerun.omidlab.net/?url=rerun%2Bhttps%3A%2F%2Frerun-grpc.omidlab.net%2Fproxy
```

(decoded: `?url=rerun+https://rerun-grpc.omidlab.net/proxy` — the `?url=` param
makes the web viewer connect through the public gRPC hostname instead of
whatever host the server advertised internally.)

## Architecture

```
browser
  → https://rerun.omidlab.net            (cloudflare edge, TLS)
  → named tunnel 350655a2-4ba4-4a88-beb5-405192dcbff3   (cloudflared on omid-fleet)
  → 127.0.0.1:9877 / :9878 on omid-fleet
  → ssh -L relay: omid-fleet 0.0.0.0:9877/9878 → russet localhost:9877/9878
  → rerun on russet: web viewer :9877, gRPC message proxy :9878
```

Two hostnames because rerun needs two channels: `rerun.omidlab.net` serves the
web-viewer HTML/wasm (:9877), `rerun-grpc.omidlab.net` carries the gRPC-web
message stream (:9878).

## Layer 1 — rerun server (in your script, on the station)

```python
import rerun as rr
rr.init("my_session")
server_uri = rr.serve_grpc(grpc_port=9878)
rr.serve_web_viewer(web_port=9877, open_browser=False, connect_to=server_uri)
```

Convention: **always ports 9877/9878**. Any script on russet using these ports
is instantly public at the viewer URL — no infra changes per session.

Script-side gotchas (learned the hard way, see agent memory):
- Log images as JPEG (`rr.EncodedImage`), never raw RGB — raw at even 2 Hz
  saturates the gRPC channel and the SDK's exit-flush hangs the process.
- Send an explicit `rerun.blueprint` grid; auto-layout buries once-logged panels.

## Layer 2 — ssh relay (omid-fleet)

```bash
ssh -f -N -o BatchMode=yes -o ConnectTimeout=5 -o StrictHostKeyChecking=no \
    -o ExitOnForwardFailure=yes \
    -L 0.0.0.0:9877:localhost:9877 -L 0.0.0.0:9878:localhost:9878 \
    robot-lab@100.123.182.78
```

- `0.0.0.0` bind is required — cloudflared connects to these ports.
- Check before arming (avoid duplicates): `pgrep -af "ssh.*9877"`.
- **To point the public URL at a different host** (e.g. yukon instead of
  russet): kill the existing relay **by PID** (`pgrep -af "ssh.*9877"`, then
  `kill <pid>`), start the same command against the new host. Nothing else
  changes.

## Layer 3 — cloudflared named tunnel (omid-fleet, permanent)

`/home/cameronsmith/.cloudflared/config.yml` — these rules exist and must stay
ABOVE the `*.omidlab.net` wildcard:

```yaml
  - hostname: rerun.omidlab.net
    service: http://127.0.0.1:9877
  - hostname: rerun-grpc.omidlab.net
    service: http://127.0.0.1:9878
```

DNS routes (already created, one-time):

```bash
cloudflared tunnel route dns 350655a2-4ba4-4a88-beb5-405192dcbff3 rerun.omidlab.net
cloudflared tunnel route dns 350655a2-4ba4-4a88-beb5-405192dcbff3 rerun-grpc.omidlab.net
```

Hard rules:
- Use `127.0.0.1`, **not** `localhost`, in ingress services (localhost can
  resolve to `::1` and the forward silently fails).
- **NEVER `pkill -f "cloudflared tunnel"` on omid-fleet** — that pattern
  matches the PRODUCTION omidlab.net tunnel. If you must restart cloudflared
  (e.g. after a config.yml edit), find the PID and kill only it; a supervisor
  respawns it with the new config.
- Don't use quick tunnels (`trycloudflare.com`) — they intermittently 404 at
  the edge. The named tunnel is the reliable path.

## Diagnosing by status code

| Symptom at rerun.omidlab.net | Meaning | Fix |
|---|---|---|
| `502` | Tunnel + relay chain fine, but no rerun server on station :9877 | Start your rerun script (expected idle state) |
| `404` (cloudflare page) | Ingress rule missing / below wildcard | Fix config.yml order, restart cloudflared by PID |
| Hangs / connection refused | ssh relay dead | Re-arm Layer 2 command |
| Viewer loads but "connecting…" forever | gRPC leg broken — check `rerun-grpc.omidlab.net` reachable, and that the script used `serve_grpc(grpc_port=9878)` | Fix ports / relay |

## Quick health check (from omid-fleet)

```bash
pgrep -af "ssh.*9877"                                   # relay alive?
curl -s -o /dev/null -w "%{http_code}\n" https://rerun.omidlab.net/   # 200=live session, 502=idle
```
