The clone step named a repository that does not exist, so following the procedure verbatim failed before reaching the install. The remote is alexion/dotfiles.
154 lines
7.3 KiB
Markdown
154 lines
7.3 KiB
Markdown
# Installing `neogaia`
|
|
|
|
This is the one-shot procedure that turns the `neogaia` `Host` in this flake into a running, encrypted Dell XPS 13 laptop, installed from the NixOS live ISO.
|
|
|
|
It is destructive: it formats `/dev/nvme0n1` in full.
|
|
Read it end to end before starting, because the laptop is the only machine and the reimage is irreversible.
|
|
|
|
The whole install is a single `disko-install` against the `neogaia` `Host`, followed by setting a bootstrap login password by hand.
|
|
Everything the installed system needs — the LUKS layout, the CachyOS kernel, the wifi firmware, the user, and the terminal tooling — is already declared in the flake, so this document is only the mechanics of getting that flake onto the disk.
|
|
|
|
## Bootstrap ordering
|
|
|
|
The install consumes the flake from Gitea, so **the flake must already be on Gitea before you start** — the repo cannot pull a config that hasn't been pushed.
|
|
The bootstrap login password is likewise set by hand at the end and is **never committed**, which is what keeps the public repo free of any secret while still yielding a working login on first boot.
|
|
|
|
Two secrets are set by hand during this install, both entered interactively and neither stored in the repo:
|
|
|
|
1. The **LUKS passphrase** that encrypts the disk, entered when `disko-install` formats it and again at every boot.
|
|
2. The **bootstrap login password** for the `alexion` user, set through `nixos-enter` just before the reboot.
|
|
|
|
## 0. Push the repo to Gitea
|
|
|
|
From your working checkout, make sure `main` is committed and pushed to the Gitea remote:
|
|
|
|
```console
|
|
$ git push origin main
|
|
```
|
|
|
|
The install reads only committed, git-tracked content, so anything uncommitted will not make it onto the laptop.
|
|
|
|
## 1. Boot the live ISO and join wifi
|
|
|
|
Boot the machine from a NixOS live ISO (the minimal installer is enough).
|
|
The installer logs in as the `nixos` user, who has passwordless `sudo`.
|
|
|
|
On the minimal ISO, bring up wifi with `wpa_supplicant`:
|
|
|
|
```console
|
|
$ sudo systemctl start wpa_supplicant
|
|
$ wpa_cli
|
|
> add_network
|
|
0
|
|
> set_network 0 ssid "YOUR_SSID"
|
|
> set_network 0 psk "YOUR_WIFI_PASSWORD"
|
|
> enable_network 0
|
|
> quit
|
|
```
|
|
|
|
On the graphical ISO, which ships NetworkManager, use `nmcli` instead:
|
|
|
|
```console
|
|
$ nmcli device wifi connect "YOUR_SSID" password "YOUR_WIFI_PASSWORD"
|
|
```
|
|
|
|
Confirm you have connectivity (`ping -c1 github.com`) before continuing.
|
|
|
|
## 2. Clone the repo locally
|
|
|
|
Clone this repo onto the live ISO and work from that local checkout:
|
|
|
|
```console
|
|
$ git clone ssh://gitea@git.alexion.dev:2022/alexion/dotfiles.git
|
|
$ cd dotfiles
|
|
```
|
|
|
|
Cloning over SSH needs your Gitea SSH key present in the live session, since the ISO starts with none.
|
|
If getting the key onto the ISO is inconvenient, clone over HTTPS instead and tell git to skip the self-signed certificate:
|
|
|
|
```console
|
|
$ git -c http.sslVerify=false clone https://git.alexion.dev/alexion/dotfiles.git
|
|
$ cd dotfiles
|
|
```
|
|
|
|
Do **not** point `disko-install` straight at the Gitea flake URL.
|
|
Gitea serves HTTPS with a self-signed certificate and expects authentication, and Nix's flake fetcher has no easy way to skip certificate verification or supply those credentials mid-install.
|
|
A plain `git clone` sidesteps that entirely — over SSH there is no TLS, and over HTTPS git takes the `sslVerify=false` above that the flake fetcher won't — and then `disko-install` consumes the flake from a local path, where no fetch of our repo happens during the build.
|
|
(The public flake inputs — `nixpkgs`, `chaotic`, `disko` — are still fetched from GitHub over ordinary, valid TLS; only our own repo is the problem the local clone solves.)
|
|
|
|
## 3. Run `disko-install`
|
|
|
|
Run the install as root from inside the clone:
|
|
|
|
```console
|
|
$ sudo nix --extra-experimental-features 'nix-command flakes' run \
|
|
github:nix-community/disko/latest#disko-install -- \
|
|
--flake .#neogaia \
|
|
--disk main /dev/nvme0n1 \
|
|
--write-efi-boot-entries \
|
|
--option extra-substituters https://nyx-cache.chaotic.cx/ \
|
|
--option extra-trusted-public-keys nyx-cache.chaotic.cx:dJxTrgMC3V3cFfyIiBQDQorG6k1LsqurH/srpMSq7qk=
|
|
```
|
|
|
|
What each part does:
|
|
|
|
- `--flake .#neogaia` installs the `neogaia` `Host` from the local clone.
|
|
- `--disk main /dev/nvme0n1` maps disko's `main` disk to the NVMe device; it matches the device declared in `hosts/neogaia/disk.nix` and is stated explicitly so there is no doubt about the target.
|
|
- `--write-efi-boot-entries` writes the systemd-boot entry into this machine's NVRAM, because the disk stays in the laptop it was installed from.
|
|
- The two `--option` lines are the important part: they hand the **chaotic binary cache** to the install-time Nix daemon on the live ISO.
|
|
|
|
The chaotic substituter must be passed here explicitly.
|
|
The `nix.settings` in the flake configure the substituters of the *installed* system, not the live ISO's daemon that runs this build; the ISO's daemon has no `substituters` beyond `cache.nixos.org`.
|
|
Without these two `--option` flags, the build cannot fetch the prebuilt CachyOS kernel and **compiles `linuxPackages_cachyos` (and its toolchain) from source on the USB stick** — a very long detour that the cache avoids.
|
|
Because the install runs as root, and root is a trusted Nix user, the daemon honours these client-supplied substituter settings.
|
|
|
|
Partway through, disko formats the LUKS container and **prompts for a disk-encryption passphrase**.
|
|
This is the passphrase you will type at every boot to unlock the disk; choose it deliberately.
|
|
|
|
When it finishes it prints `disko-install succeeded`.
|
|
`disko-install` unmounts the target filesystem on exit, so nothing is mounted at this point — step 4 remounts it.
|
|
|
|
## 4. Set the bootstrap login password
|
|
|
|
The installed system was written with no login password (`nixos-install --no-root-password`, and the flake sets none for `alexion`), so it cannot yet be logged into.
|
|
Set a bootstrap password by hand before rebooting.
|
|
|
|
First remount the just-installed system with disko, which reopens the LUKS container (prompting for the passphrase from step 3) and mounts the subvolumes under `/mnt`:
|
|
|
|
```console
|
|
$ sudo nix --extra-experimental-features 'nix-command flakes' run \
|
|
github:nix-community/disko/latest#disko -- \
|
|
--mode mount --flake .#neogaia
|
|
```
|
|
|
|
Then enter the installed system and set the password for your user:
|
|
|
|
```console
|
|
$ sudo nixos-enter --root /mnt
|
|
[nixos-enter]# passwd alexion
|
|
[nixos-enter]# exit
|
|
```
|
|
|
|
This password lives only on the laptop's disk; it is **never committed** anywhere.
|
|
|
|
## 5. Reboot
|
|
|
|
Unmount and reboot into the installed system:
|
|
|
|
```console
|
|
$ sudo umount -R /mnt
|
|
$ sudo reboot
|
|
```
|
|
|
|
Remove the USB stick.
|
|
At boot you are prompted for the LUKS passphrase from step 3; after unlocking, log in at the console as `alexion` with the bootstrap password from step 4 and you have a working system with fish, tmux, nvim, and Claude Code.
|
|
|
|
## First post-boot task
|
|
|
|
Setting the login password by hand is a bootstrap shortcut, not the end state.
|
|
The first thing to do on the running laptop is to move that password to a `hashedPasswordFile` backed by a `sops-nix` secret, so it is declared and reproducible like everything else.
|
|
|
|
This is deliberately out of scope for the install itself.
|
|
Per ADR 0001, each `Host`'s secrets are encrypted to an age key derived from that `Host`'s SSH host key — and that host key does not exist until this first install generates it.
|
|
So the sops wiring can only happen *after* the machine is up, which is exactly why it is the first follow-up rather than part of this procedure.
|