Operating a bridge

Operator notes for running the bridge and the ring behind it: load a plan, survive a restart, keep contribution flowing, and keep the engine off the internet.

The gateway (public entry point) and the bridge (engine face) are the two long-lived services an operator keeps healthy, with the p4 agents and their stage servers behind them. The engine speaks no authentication at all — it assumes the machines that can reach each other are meant to — so everything public converges on the gateway, and the bridge is reached through a tunnel rather than published.

Loading

A plan, and the number it is loaded under

  • Placement is a plan you write, not a request you make: the bridge answers 409 to anyone asking it to serve. Generate the plan, dry-run it, then load with --confirm.
  • The load generation is written to disk before the first command leaves. It is chosen by the loader, checked for exact equality on every session and on unload, and recorded nowhere on the machines — lose it and a loaded model cannot even be taken down.
  • The node generation is that same number. Load a ring with two different ones and it serves exactly one request before the head stops; the next session hangs part-loaded. Use a fresh value per load, or a registration left behind by a failed attempt collides with it.
  • The agent refuses to load without its operational journal. That is the admission record a replay-safe load needs, not a debug flag.
Survive a restart

What comes back and what does not

  • An agent restart drops its nodes. Stage servers are runtime-only; the model has to be loaded again from the plan. That is the recovery procedure, not a failure of one.
  • The gateway will not reload it for you. Its ring watchdog notices a model that stopped serving, learns from the bridge's 409 that placement is external, says so once, and stops asking.
  • Contribution counters live in the bridge's memory. The gateway polls every 30 s and delta-credits; a restart loses only what had not been polled, and the gateway re-baselines rather than double-paying when a counter goes backwards.
Lock it down

The engine is not internet-facing

  • Bind the bridge to loopback and give it a service token. Without the token it authenticates nobody, and anything that reaches it can run the ring for free — it says so at startup rather than letting you find out later.
  • Agents advertise the address other agents dial. Use the fastest network the hosts share, never loopback across hosts, and keep that network off the public internet.
  • If something must sit on a public IP, remember Docker's published ports are DNAT'd before the INPUT chain, so a rule on dport will not match. Filter in the DOCKER-USER chain on conntrack's original destination port (--ctorigdstport), and persist with a systemd oneshot ordered After=docker.service.
Footguns

Two that cost real time

  • An unset operator wallet reads as zero earnings. The gateway skips any contribution row without an owner and logs nothing. The nodes look idle while they are serving.
  • `pkill` matches its own command line. ssh host 'pkill -f server.js; ...' kills the shell running it. Put the pattern in a script file rather than the remote command, use a character class (server[.]js), and remember a process started as a bare node server.js carries no path to match on — find it by its listening port instead.