AtomixOS Bootstrap Provisioning
An operator can give a freshly installed, approved, online AtomixOS device its complete first configuration: a
config.toml or an approved config bundle. The server opens the device's own atomixos-bootstrap FRP route, posts the
file unchanged to AtomixOS's /api/config, follows the resulting job, records the outcome, and then closes the route.
The server never writes to the device's filesystem, unpacks archives, uses the browser-only /apply flow, or resends an
upload that AtomixOS has accepted. The original plan is in the design record.
What changed for users
- Upload the file with
POST /api/v1/provisioning/devices/:device_id, as rawapplication/octet-streambytes. - Check progress and diagnostics with
GET /api/v1/provisioning/deliveries/:id. - Release a route that was kept open after an unclear outcome with
POST /api/v1/provisioning/deliveries/:id/withdraw. - When something is wrong (no permission, a device that is unapproved or offline, an invalid file, a missing route, a failure, an expired lease, or an unknown outcome) the delivery stops, and nothing is quietly uploaded twice.
How it fits in
Provisioning reuses what already exists: device permissions, the online check, remote-access leases, Caddy's wildcard
routing, the device's versioned FRP profiles, and the usual Logger and PubSub audit events. The server only picks the
atomixos-bootstrap profile by name; the device decides where it points, how it serves HTTP, and the fixed Host
rewrite.
Running it
- Files can be up to 32 MiB, and are tracked by their lowercase SHA-256.
- Every response from AtomixOS is capped at 1 MiB while it is read, before decoding or saving.
- The server follows a job for up to five minutes by default, and each request times out after 30 seconds.
- Only an HTTP
409on upload is retried, at most twice. - An unclear upload becomes
indeterminate, and keeps its route open until you withdraw it or the lease expires. ATOMIXOS_PROVISIONING_BASE_URLoverrides the per-device address, which is otherwise built fromBASE_DOMAIN.
Differences from the design
- Deliveries are stored. Each delivery is saved, so operators can see its status, and the latest job events and result are kept. That is because AtomixOS reports progress through its job resource, not through a second Nixstasis command.
- Each delivery owns its lease. A delivery's route lease belongs to its UUID and is saved. Withdrawing, or resuming after a restart, uses that same lease, never a new one with a fresh expiry. Finishing or withdrawing a delivery voids its credential, regardless of other operators' leases. While a delivery runs, its profile takes priority; afterwards, other leases get their own profiles and expiries back.
Not included
- The design's broader 90-second usability target was not measured.
- Re-applying configuration after the first boot is not part of this action.
- There is no direct file writer, archive extractor, browser
/applyendpoint, route definition from the client, arbitraryHostrewrite, automatic re-upload, or following of forwarding URLs.
Tests
packages/server/test/nixstasis/provisioning/artifact_test.exs: file size limits and SHA-256 tracking.packages/server/test/nixstasis/provisioning_test.exs: permission and approval checks, upload, job polling, success,409retries, unclear uploads, lease expiry, resolvingindeterminatedeliveries, and withdrawal.packages/server/test/nixstasis/provisioning/http_client_test.exs: the 1 MiB response cap, before JSON decoding.packages/server/test/nixstasis/devices/remote_access_leases_test.exs: saved, provisioning-owned route leases.packages/server/test/nixstasis_web/controllers/provisioning_controller_test.exs: the provisioning HTTP API.mix ash.codegen --check: the delivery resource and its migration.