BuildBot

Inference & Ops

Deploying & one-click self-update

Lesson 10 of 10

What you'll learn

  • See how a Go binary is deployed and kept running with systemd
  • Understand the release flow for a cross-platform desktop app
  • Model the desktop self-updater as a state machine

The relay is a single cross-compiled Go binary — no runtime, no dependencies — so deploying it is "copy a file and keep it running." You build for Linux, scp it to the VPS, and let systemd supervise it: start on boot, restart on crash, capture logs.

GOOS=linux GOARCH=amd64 go build -o quorum-relay .
scp quorum-relay root@vps:/opt/quorum-relay/quorum-relay-new
ssh root@vps "cd /opt/quorum-relay && mv quorum-relay quorum-relay-bak \
  && mv quorum-relay-new quorum-relay && systemctl restart quorum-relay"
# /etc/systemd/system/quorum-relay.service
[Service]
ExecStart=/opt/quorum-relay/quorum-relay
Restart=always          # supervise: bring it back if it exits
[Install]
WantedBy=multi-user.target

Restart=always is the supervision contract: if the process dies, systemd starts it again. The dashboard is a Next.js app that ships to Vercel, and the desktop app is built per-platform and published to GitHub Releases.

Updating the thing on people's machines

A desktop app can't redeploy itself the way a website does — it's a binary already installed on someone's computer. So Quorum self-updates: it checks the latest release, and if there's a newer version, downloads the bundle, replaces itself on disk, and relaunches — no manual reinstall. The flow is a small state machine, and each step can fail and recover.

Replace, then relaunch — in that order

You can't overwrite a running binary in place on every OS. The updater downloads to a temp path, swaps the bundle, then relaunches into the new copy. Get the order wrong and you relaunch the old version or corrupt the install.

The challenge models the updater: compare versions, then walk download → replace → relaunch, short-circuiting when already current.

Self-update state machine (JS model)

Run it. It updates when a newer version exists and no-ops when current. Try setting latest = current.

Loading editor…
Knowledge check

Why must the updater replace the bundle before relaunching, rather than after?

That's the full stack — from a single node holding a model to a self-updating fleet reachable from anywhere. You now have the mental model for every layer of Quorum.

Saved on this device. Sign in to sync your progress everywhere.