Installation

Emanix installs from its own live ISO. You build the ISO once on a machine you already have, boot the target from it, and run one command.

Two scripts do the work:

  • fresh-emanix-install ships with the distribution and is baked into the ISO. It runs on the booted target and does the install.
  • bin/emanix-iso is the one script your consuming flake supplies — the repo that declares your hosts. It builds the ISO, and optionally writes it to a USB stick.

Everything below assumes the host is already declared in your flake. If it is not, start with Adding a Host and come back.

1. 1. Build the installer ISO

On an existing machine, from your flake repo:

bin/emanix-iso                 # build; prints the ISO path
bin/emanix-iso --no-keys       # build with NO host keys (rescue / debug ISO)
bin/emanix-iso /dev/sdX        # build and write to a device (destructive)

The ISO stages your whole flake at /etc/emanix/flake and, unless --no-keys, every staged host key at /etc/emanix/keys.

An ISO built with keys IS your identity. It carries the private host keys that decrypt your secrets. Keep the .iso file and the stick exactly as carefully as you keep the keys themselves. Build with --no-keys for anything you intend to hand to someone else or leave in a drawer.

1.1. Why a keys-carrying build is impure

The private halves are gitignored, so staging them means reading the working tree — which pure evaluation forbids. bin/emanix-iso passes --impure for you, and the private keys are copied into /nix/store (world-readable) on the way into the image. The script prints that path so you can delete it afterwards.

A build whose keys directory holds only .pub halves fails at build time, on purpose. The alternative is an ISO that looks key-carrying, boots, and then dies at the installer's preflight on the target's console.

2. 2. Before you go

The ISO bakes in the repo and the keys, so there is no USB staging to get right. What still has to be true:

  • Real values are in the encrypted secrets. Placeholders install a system that activates and then fails to do anything useful with them. See Secrets.
  • The host's public key is committed at keys/<host>_host_ed25519.pub, and the private half is present in the working tree so the ISO can stage it.
  • Secrets are rekeyed for this host, so the encrypted-to-this-machine copies exist.

The public key is the part people skip, and it is the part that matters: secrets are decrypted by the host's own key, so a machine that boots without its key cannot decrypt anything and the first activation fails.

3. 3. Install, from the ISO

  1. Boot the stick. Its volume label is emanix.
  2. Network: ethernet comes up on its own. For WiFi, the ISO ships NetworkManager with the iwd backend, so nmtui, nmcli and iwctl all work:

    nmtui                                    # nothing to remember
    nmcli device wifi connect <ssid> --ask
    

    iwctl works here and not on the machine you end up with: the installed host does not get the iwd backend, so nmtui and nmcli are the two that carry over, and neither needs the interface name. See Network.

  3. Install:

    sudo fresh-emanix-install <host>
    

The host name selects a host you declared in the flake. Give one the flake does not know — or none at all — and the installer switches to interactive mode, asking for the hostname, user, disk, encryption, filesystem and graphics driver. Two options are available:

sudo fresh-emanix-install <host> --check-only     # preflight, then exit
sudo fresh-emanix-install <host> --disk /dev/X    # override disk auto-detection

--check-only needs no root, touches nothing, and prints the checklist below. Run it first.

3.1. The preflight

Check What it means
repo The flake was found. /etc/emanix/flake on the ISO, or $EMANIX_REPO
keys A private host key for <host> was found, and its fingerprint matches the key your secrets are encrypted to
UEFI The machine booted in UEFI mode (/sys/firmware/efi exists)
network cache.nixos.org is reachable
disk A target disk was identified
Secure Boot Reported, not required — see below

Anything missing aborts before the disk is touched.

The fingerprint check is the one worth calling out. It compares the staged private key against keys/<host>_host_ed25519.pub — the actual recipient your secrets are encrypted to — and fails closed on a mismatch. That check exists because the alternative is discovering the wrong key after the disk is gone.

Disk auto-detection picks the largest non-removable, writable device with no mounted partitions, which skips the stick you booted from. The installer also cross-checks that against the device your disk layout declares and refuses to continue if they disagree — a disagreement usually means a VM, or the wrong pick.

3.2. What it then does

The stages are numbered, so a long step is visibly a step and not a hang.

  • Asks you to type yes to wipe the target — once. disko's own second confirmation is suppressed, because you have already answered it and it would block any unattended install
  • Partitions and formats with disko (destroy,format,mount), prompting for a disk-encryption passphrase if the layout declares LUKS. This prints a wall of + ... shell tracing; that is normal output, not errors
  • Installs a host key to /mnt/etc/ssh/ — the staged one for a known host, a freshly generated one for a new machine, which has no secrets to decrypt
  • Runs nixos-install
  • Prompts for the primary user's password, retrying rather than leaving a passwordless account behind
  • Offers to reboot

Remove the stick on reboot.

3.3. Expect the install to compile Emacs

The nixos-install step is the long one, and it is long for a reason worth understanding rather than waiting through.

Of the 346 store paths a desktop host needs for its Emacs and compositor, 295 come straight from cache.nixos.org. The remaining 51 are compiled on the machine you are installing: ewm-core (Rust, via Smithay) and roughly fifty Emacs Lisp packages.

The Lisp is uncacheable for a structural reason. Every Emacs package is built against Emanix's own emacs-pgtk from emacs-overlay, so even entirely ordinary packages — xref, project, eldoc — exist in the public cache only as builds against a different Emacs. Change the Emacs and all of them rebuild.

The output is small, about 81 MiB, so this costs CPU time rather than bandwidth and it scales with how many cores the machine has. Nothing is wrong while it runs.

A binary cache would remove the step entirely — 81 MiB fits inside any free tier — and that is the intended fix. Until it exists, budget for it.

4. Installing a host the flake has never heard of

Everything above assumes the host is already declared. It does not have to be. Run the installer with no host name and it switches to interactive mode, which invents the host as it goes:

sudo fresh-emanix-install

It decides by asking the flake, not by guessing: if the name you give matches a nixosConfigurations attribute it takes the pre-staged path unchanged, and anything else — including no name at all — is treated as a new machine.

4.1. What it asks

Six questions, in this order:

Question Notes
Hostname Validated as RFC 1123 — lowercase letters, digits, hyphens
Username Your account on the new machine, same character rules
LUKS Whole-disk encryption, on by default
Filesystem btrfs (with subvolumes) or ext4
Swap A size like 8G, or 0 for none
Graphics amd, intel or none; lspci supplies the default

Network is not a question — it checks, and only involves you if there is no route, in which case it offers to open nmtui.

The graphics answer matters more than it looks. EWM launches from tty1 and loses the DRM-master race unless the driver is in the initrd, so a wrong answer here is a black screen on a machine whose owner has no other console. It is asked rather than assumed for exactly that reason.

4.2. What it generates

A complete flake in /etc/nixos, whose only machine-specific file is host.nix:

{
  hostName   = "testbox";
  device     = "/dev/vda";
  luks       = false;
  filesystem = "btrfs";
  swapSize   = "2G";
  gpu        = null;              # "amd" or "intel" on a graphical host
  hardwareModule = null;          # a nixos-hardware module, if you know yours
}

Everything else in that flake reads from those values. The disk layout comes from emanix.lib.mkDisk, so the disk parameters above are the whole description of the machine's disk; gpu is the only other thing a graphical host must set.

Before anything is erased the installer prints your answers back — hostname, username, encryption, filesystem, swap, graphics — immediately above the wipe confirmation. The preflight proves the machine is ready; that block is how you check the installer understood you.

4.3. After the reboot

You land in Emacs. It is the desktop here, not an application inside one.

Key Does
s-<return> A terminal
s-d Launch an application
s-1 … s-9 Switch frame slots
C-c ? Reopen the welcome buffer

A welcome buffer opens on the first start with those keys and a pointer back here. Dismiss it with q for now, or n to never see it again.

Do not run emanix-firstboot on a machine installed this way. That command is the consuming flake's seam — it runs whatever your flake put in emanix.firstboot.text, and a generated host has set nothing, so it prints a message about configuring it and exits. It is for a fleet, not for a machine the installer just invented.

4.4. Making the config yours

The installer leaves a working flake in /etc/nixos. That is enough to run and not enough to live in: root-owned, no git, nowhere to put a secret.

emanix-init

This copies it to ~/flake, initialises git, adds a keys/ directory whose .gitignore commits the public halves and never the private ones, records this machine's own public host key as a future secrets recipient, and runs nix flake check to prove the result still evaluates. It refuses rather than overwrites, and leaves /etc/nixos untouched, so a failed adoption costs nothing.

The welcome buffer offers this as [i] when it finds no config repo.

Rebuild from there afterwards:

sudo nixos-rebuild switch --flake ~/flake

5. ⚠ Firmware: disable Secure Boot

Disable Secure Boot in the machine's firmware setup (on a ThinkPad: F1 at the logo → Security → Secure Boot → Disabled) and confirm UEFI mode.

The bootloader is unsigned. With Secure Boot enabled the system installs cleanly and then will not boot — a far more confusing failure than an install-time error, which is why the installer warns rather than assumes.

6. Installing over SSH

The ISO runs sshd. The nixos user has an empty password, so nothing can log in until you set one:

  • add live.nixos.passwd=<pw> to the kernel command line at boot, or
  • run sudo passwd nixos at the target's console

then ssh nixos@<ip> and drive the install from your own machine. The ISO's host keys are generated fresh at every boot — it runs on tmpfs, so they are ephemeral by construction.

7. First boot

  1. Disk passphrase, if the layout has LUKS
  2. The compositor starts (autologin is opt-in per host; without it you get a login prompt and EWM starts on your first tty1 login)
  3. Run the one-time setup:

    emanix-firstboot
    

This runs whatever your flake put in emanix.firstboot.text. Emanix supplies the command and shellchecks the body at build time — so a broken first-boot script fails your build rather than failing at the one moment nobody is watching a screen they can debug from. It does not supply the steps, because joining a network and pairing file sync are decisions about your infrastructure, not the distribution's.

A typical script joins a mesh VPN, prints the file-sync device id to pair with a hub, and confirms secrets decrypted. If you set nothing, emanix-firstboot prints a message saying so and exits.

If yours pairs file sync, remember that pairing is two-sided: the hub must also accept the new device and share the folders. Printing the id is half the handshake, not all of it.

8. Ongoing

cd ~/dotfiles && sudo nixos-rebuild switch --flake .#<host>

See Build and Deploy.

9. Manual fallback

If the installer fails partway, everything it automates is an ordinary command. Note that disko reads the layout from the flake — there is no separate config file to write:

# Partition, format and mount, from the declarative layout
sudo disko --mode destroy,format,mount --flake /etc/emanix/flake#<host>

# Install the host key so agenix can decrypt on first boot
sudo install -d -m 755 /mnt/etc/ssh
sudo install -m 600 /etc/emanix/keys/<host>_host_ed25519     /mnt/etc/ssh/ssh_host_ed25519_key
sudo install -m 644 /etc/emanix/keys/<host>_host_ed25519.pub /mnt/etc/ssh/ssh_host_ed25519_key.pub

# Install, then set the user's password
sudo nixos-install --flake /etc/emanix/flake#<host> --no-root-password
sudo nixos-enter --root /mnt -c 'passwd <username>'

sudo reboot

10. WSL hosts

A wsl host is not installed this way at all — there is no disk layout, no bootloader and no host hardware. The WSL module supplies boot and mounts; you import a distribution image and apply the flake.

One platform quirk is worth knowing: the system must not set its own hostname at activation, because that breaks the WSL user-session bootstrap. The host composer sets the hostname as a default precisely so a WSL host can force it empty.