LAN bootstrap: handing a fresh machine the binary
A machine with no spt on it is not yet a node. It has no network identity, so no access grant can be checked for it and nothing on the node’s own serving surface can reach it. The LAN bootstrap listener exists for exactly that moment: a second, opt-in server that hands a stranger on your LAN the spt binary and nothing else.
It is a second listener, and it is off by default
The serving server on port 5474 is loopback-only and stays that way. The
bootstrap listener is a different server on a different port, 5470, bound on
all interfaces, and it starts only when you say so:
$ spt serve lan --bootstrap
LAN_BOOTSTRAP_UP: http://192.168.1.81:5470/install (port 5470)
sha256 x86_64-pc-windows-msvc c1e0…4b7a
sha256 x86_64-unknown-linux-gnu 8f22…0d16
sha256 x86_64-unknown-linux-musl a904…7c31
LAN-EXPOSED: anyone who can reach this socket may pull the binary until `spt serve lan --stop`.
Take it down when the bootstrap is finished:
$ spt serve lan --stop
LAN_BOOTSTRAP_DOWN: the bootstrap listener is stopped
A bare spt serve lan reports the current state without changing it.
Three properties are worth stating plainly, because each one is a decision rather than an accident:
- While it is up, anyone who can reach the socket may pull the binary. The
listener has no membership concept and must never grow one — a fresh box has
no identity to present. Your explicit start is the only gate, which is why
the now-signal carries a standing
LAN_EXPOSEDline for the whole window. - It serves three routes and 404s everything else.
/bin/<triple>/spt(orspt.exefor a Windows triple), that file’s.release.jsonsidecar, and/install. There is no fall-through into the serving router, so a routing mistake on this port cannot reach your docs or your served files. - It never comes back on its own. No up-state is written to disk, so a daemon restart comes back with the listener down. Off-by-default is a property of every boot.
The port follows the usual layering: SPT_LAN_BOOTSTRAP_PORT beats
daemon.json’s lan_bootstrap_port, which beats the default 5470. Setting
the port never starts the listener.
What it serves, and how you know the bytes are real
The machine at the other end is about to execute what it downloads, over plain HTTP, on a network you can only mostly vouch for. So the bytes carry their own provenance, in three parts that all have to hold.
It serves the applied signed release set, or it serves nothing. At start, the listener checks that the running daemon’s own binary is the host platform’s artifact in a signed release set, and that the node has actually applied that set. If either fails it refuses to start and names why:
$ spt serve lan --bootstrap
LAN_BOOTSTRAP_REFUSED:sha-mismatch
The three refusals are unsigned-exe (the running binary belongs to no signed
set this node trusts), sha-mismatch (it is not that set’s host artifact — a
development build, or a hand-copied executable), and set-not-applied (the set
is staged but not yet running). There is no “serve it anyway, marked unsigned”
option, and a newer staged set is never served: a stranger receives what this
node runs, never what it is about to run.
Each platform is checked again as it is served. The listener holds several platforms at once, and a triple’s bytes go out only if they still hash to that triple’s digest in the same signed metadata. A platform that is missing or no longer matches answers a 404 naming itself, and the others keep serving:
LAN_BOOTSTRAP_TRIPLE_UNAVAILABLE:x86_64-unknown-linux-musl:missing
That isolation is deliberate: a missing Linux artifact must not block a Windows-to-Windows bootstrap.
You are the last check, and that is the point. The signature and the sidecar
travel with the download, which makes them circular on their own — a tampered
binary would carry tampered trust roots. The line that closes the loop is the
one you read off two screens. The serving machine prints
sha256 <triple> <hex> at start; the install page bakes that same hex into the
command; and the puller prints the hash of what it actually downloaded before
it verifies anything. Two machines on one LAN and a human comparing two lines is
the only honest anchor a bootstrap without transport security can offer.
On the fresh machine
Open http://<serving-host>:5470/install, pick your own platform’s triple — the
page lists them and never guesses for you — and run what that page prints:
$ curl -fsSLO http://192.168.1.81:5470/bin/x86_64-unknown-linux-gnu/spt
$ curl -fsSLO http://192.168.1.81:5470/bin/x86_64-unknown-linux-gnu/spt.release.json
$ chmod +x ./spt
$ ./spt install --expect-sha256 8f22…0d16 --release-json ./spt.release.json
INSTALL_SHA256: 8f22…0d16
INSTALL_VERIFIED: signed set 102 (0.68.0), key rel-primary-2026
INSTALL_OK: placed /home/you/.spt/bin/spt
--expect-sha256 refuses anything but those exact bytes and writes nothing on a
mismatch. --release-json re-runs the signature and digest checks against the
keys built into the binary you just downloaded. Compare the INSTALL_SHA256
line against the serving machine’s sha256 line before you trust the result —
that comparison is the part no software can do for you.
From there the new node is ordinary: first run mints its identity, and it joins a subnet the usual way.