Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/gunnar

.nornir/installer-build-thing-variants.md

The installer is a Build Thing: estate shapes are gunnar variants

Owner, 2026-09-24:

What is wrong today

private-gunnar-ops/xtask is half the installer. After the boxes pair themselves through the door, estate rebuild's pairing step still does work:

The mock (rebuild_mock.rs) is a second copy of those steps. It refuses the pairing step and pairs from the laptop (--xtask-pairs), so a mock PASS says nothing about the real installer.

The variants (owner's names, 2026-09-24)

variant what it installs
solo one gunnar box
gunnar-twin main + twin, paired through the door; no monetize
gunnar-twin-one main + twin METERED, booking in the ONE monetize (the estate enrols there first); the front runs no monetize

There is exactly ONE monetize: the ONE box (monetize.ignalina.dk; owner 2026-10-12). It is where the products are shown and sold. Monetize never runs on Gunnar's front or UI server: gunnar-twin-monetize and gunnar-twin-monetize-provided are retired, and the kit refuses them by name ([variant-retired]).

Open source is the default. Pro is the suite (owner 2026-09-24): "the Build Thing that uses plugins from vetra/monetize-impl is pro = suite". Pro is not a gunnar feature. It is the COMMERCIAL suite that monetize-impl-build-thing declares (--suite COMMERCIAL --build njord --build holger, monetize-impl branch agent/monetize-build-thing 14fb45b, not yet on main). No variant carries a monetize: the ONE box runs it, open or from the pro suite. There may be more variants.

Model: variant → features → settings → typ. where is a setting on every variant, not a variant of its own:

setting values meaning
where kvm · upcloud (later aws, azure) where the VMs run. kvm is what "the mock" was

The same variant runs on kvm or on upcloud. Only the place the VM lives changes. The medium, the seed, the door, the join, the election, the certificates, the tunnel and the follow are the same code with the same bytes. That makes the mock exact by construction.

Each variant carries an SVG of its system

A Build Thing can carry an SVG of the system it installs (owner 2026-09-24). Each variant gets one: which VMs, the door, the tunnel, and (the ONE variant) the ONE monetize outside the estate. It lives at .nornir/assets/<variant>.svg, the way dwarves' own .nornir/assets/*.svg do. dwarves has no field on a variant for it yet (today its SVGs are doc pictures only), so that is a dwarves gap.

The pictures are generated by cargo xtask svg from xtask/src/variant_svg.rs, with the same renderer and layout checks as the quick start's pictures. A test pins two rules: main and twin boot the SAME medium, and both of them JOIN the door.

vm1, vm2, vm3

Two media per estate (owner 2026-09-25)

The owner, 2026-09-25: "twin/main gunnar share ISO, but NOT the ui!! BUILD an iso for them using build thing!!!" (monetize is the ONE box's, owner 2026-10-12.)

medium Build Thing variant payload boots on
the gunnar medium gunnar-installer-open (or -metered) gunnar-server vm2 main, vm3 twin
the front medium gunnar-front-installer-open gunnar-front vm1 front

Build the front medium like the other one:

cargo xtask iso-installer --variant gunnar-front-installer-open --build kernel \
    --param pairing_seed=@<seed.toml of kind front> --param clock=<the front's own sources>

The front medium is derived from the open row in code (gunnar-recipe, front_installer). It has the same kernel, the same machine and the same pairing seed parameter. It lays gunnar-front instead of the git server, and it has no git server argument.

What gunnar-front does at boot, by itself:

  1. It brings both network cards up and opens the installer's WireGuard link.
  2. It presents itself to the installer as kind front. The door only takes a front on the FRONT slot.
  3. It is fed, and it keeps what it was fed in /data/pairing/joined.toml.
  4. It runs the relay on udp/51820 with its own tunnel key.
  5. It certifies the twin against the primary.
  6. It keeps its own clock from the clock sources and serves signed time on its utility address, port 50123.

What it makes itself at first boot and OFFERS the installer (the installer passes each on as offer.<vm>.<key>):

offer value who takes it
version the build it runs the install check
certify_pubkey its certify key the primary enrols it as front-certify
clock_key its time key every box's clock
clock_peer peer://<utility>:50123 every box's clock

The installer feeds only the operator key, the CA and the estate identity.

The gunnar medium is never the front. If it is fed role front, it refuses by name ([gunnar-medium-is-not-the-front]). The front medium takes no other role ([front-medium-is-only-the-front]).

The front medium also carries the estate's web face (2026-09-25):

  1. It serves HTTPS itself on tcp/80 and tcp/443 of its public address. There is no Caddy. The certificate is one the installer feeds (tls.<host>.cert and tls.<host>.key), else the one kept on its data disk, else a new one from Let's Encrypt. It asks Let's Encrypt in its own process (HTTP-01 on :80) only when nothing valid has 30 days left. After a failed attempt it waits 15 minutes, doubling up to 6 hours, and the wait survives a reboot. A new certificate is served from the next handshake, with no restart.
  2. It serves the console: gunnar-ui-server linked in, and the built console (gunnar-ui-web dist/) embedded in the binary. It dials the fed primary's :50051. When the feed names another primary, it is rebuilt and swapped in live.
  3. The metered medium gunnar-front-installer-metered (the front of gunnar-twin-one) runs NO monetize: its console sells through the ONE box with the estate's own bearer, and the boxes pull from the ONE box.

The feed keys the front reads (all optional). They go in the FRONT VM's own feed (edda nordisk-pairing 0.5.0 PlanVm::feed): tls.*, plugin.*, plugin_root.* and console_admin_token are refused in the shared feed and on a box, so main and twin never receive them.

feed key value
web_hosts the served names, comma-separated; the first names the certificate (default: the estate)
tls.<host>.cert, tls.<host>.key a PEM chain and its key, to carry a certificate over a rebuild
acme_directory, acme_contact the ACME directory (default Let's Encrypt production) and an e-mail
console_admin_token the console's break-glass bearer for the first passkey (at least 32 random characters)

What the front offers besides (the primary enrols each from the offer):

offer value who takes it
console_pubkey the console's key principal gunnar-ui, machine, gunnar-admin
guest_pubkey the console's guest key principal gunnar-guest, machine, no grant

What the front HANDS OVER at the end of an install (the installer's secret offer, edda nordisk-pairing 0.5.0, asked right before the close): every valid certificate it keeps on its data disk and its private key, as tls.<host>.cert + tls.<host>.key. The installer keeps them in the operator's run folder (secret-offers.toml, 0600) and nowhere else; the next rebuild feeds them to the new front (installer::successor_feed), which serves them at once and asks Let's Encrypt nothing (five certificates per week for the same names).

The installer does the whole install

What xtask does today moves to the door and the boxes:

today (xtask, after the read) moves to
operator, monetize and gunnar-guest enrolled on the primary door FEED keys, installed by the primary itself, the same way admin_pubkey already is
the primary's ticket key into the ONE monetize the install's notice to the ONE box carries it (attach::tell_installed)
the front re-rendered with the elected roles the front reads the door's verdict itself

xtask afterwards

One line: build the chosen estate variant with where=upcloud. Everything else under private-gunnar-ops/xtask/src that ran the install (rebuild.rs, rebuild_mock.rs, pair, elect, twin, appliance_key, the front re-render) is deleted. That happens only once the variant has passed on where=kvm and on where=upcloud.

Open

  1. DNS switch (grey, orange) and tearing down the previous installation: do they stay as xtask's one line, or become part of the estate variant?
  2. gunnar-twin has no monetize: does it still have a vm1 front for the door, clock and relay, or does the door live on one of the two boxes?
  3. gunnar-twin-monetize-provided Retired 2026-10-12: there is exactly ONE monetize, the ONE box; gunnar-twin-one enrols there.
  4. vm1 as an OS-less tunnr image, or first as it is today? Answered 2026-09-25: vm1 boots its own OS-less medium, gunnar-front-installer-open (see "Two media per estate"). The UI runs on it (never monetize), and it holds its own web certificate (points 7 to 9 there).