Installation
Table of Contents
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-installships with the distribution and is baked into the ISO. It runs on the booted target and does the install.bin/emanix-isois 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
- Boot the stick. Its volume label is
emanix. Network: ethernet comes up on its own. For WiFi, the ISO ships NetworkManager with the
iwdbackend, sonmtui,nmcliandiwctlall work:nmtui # nothing to remember nmcli device wifi connect <ssid> --askiwctlworks here and not on the machine you end up with: the installed host does not get theiwdbackend, sonmtuiandnmcliare the two that carry over, and neither needs the interface name. See Network.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
yesto 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 nixosat 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
- Disk passphrase, if the layout has LUKS
- The compositor starts (autologin is opt-in per host; without it you get a login prompt and EWM starts on your first tty1 login)
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.