From a5295500f14bf9bbf26b48ee4db87e41a9cbe544 Mon Sep 17 00:00:00 2001 From: Ryan Yin Date: Mon, 16 Mar 2026 10:07:08 +0800 Subject: [PATCH] refactor: migrate idols-ai to new ssd (#247) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: migrate idols-ai to new ssd * fix: github repo mi2ebi/tree-sitter-bovex 404 • Updated input 'helix': 'github:mattwparas/helix/908d48c5dd9700ddff65bcfce8850eea74af0360?narHash=sha256-hXxc3JqZ%2BxF2VjTOczmYHVttRIWlxGh5RmYZ9OcMPD8%3D' (2026-02-15) → 'github:mattwparas/helix/bb5efb6ec09792a91dc6b4dec1a4d6534b7185dc?narHash=sha256-FfbsMeo8p0JUUCf4TnYu5G35vVkFSuqh%2BEHXHyV1/UI%3D' (2026-03-13) * chore: disable helix * fix: failed to mount swapfile --- flake.lock | 6 +- home/base/tui/editors/helix/default.nix | 3 +- home/base/tui/editors/neovim/default.nix | 5 +- hosts/idols-ai/README.md | 119 ++++++-- hosts/idols-ai/default.nix | 9 +- hosts/idols-ai/disko-fs.nix | 128 ++++++++ hosts/idols-ai/hardware-configuration.nix | 128 +------- nixos-installer/README.md | 337 ++++++---------------- nixos-installer/flake.nix | 5 + 9 files changed, 337 insertions(+), 403 deletions(-) create mode 100644 hosts/idols-ai/disko-fs.nix diff --git a/flake.lock b/flake.lock index 7cf9721f..d0b1a8e1 100644 --- a/flake.lock +++ b/flake.lock @@ -416,11 +416,11 @@ "rust-overlay": "rust-overlay_2" }, "locked": { - "lastModified": 1771121283, - "narHash": "sha256-hXxc3JqZ+xF2VjTOczmYHVttRIWlxGh5RmYZ9OcMPD8=", + "lastModified": 1773422822, + "narHash": "sha256-FfbsMeo8p0JUUCf4TnYu5G35vVkFSuqh+EHXHyV1/UI=", "owner": "mattwparas", "repo": "helix", - "rev": "908d48c5dd9700ddff65bcfce8850eea74af0360", + "rev": "bb5efb6ec09792a91dc6b4dec1a4d6534b7185dc", "type": "github" }, "original": { diff --git a/home/base/tui/editors/helix/default.nix b/home/base/tui/editors/helix/default.nix index d3405a4c..6fd23231 100644 --- a/home/base/tui/editors/helix/default.nix +++ b/home/base/tui/editors/helix/default.nix @@ -1,4 +1,5 @@ { + lib, config, pkgs, helix, @@ -17,7 +18,7 @@ in ]; programs.helix = { - enable = true; + enable = lib.mkForce false; # enable steel as the plugin system # https://github.com/helix-editor/helix/pull/8675 # https://github.com/mattwparas/helix/blob/steel-event-system/STEEL.md diff --git a/home/base/tui/editors/neovim/default.nix b/home/base/tui/editors/neovim/default.nix index 5f292bdc..5fcf7e77 100644 --- a/home/base/tui/editors/neovim/default.nix +++ b/home/base/tui/editors/neovim/default.nix @@ -67,14 +67,11 @@ in # We should install packages that will compile locally or download FHS binaries via Nix! # and use lazy.nvim's `dir` option to specify the package directory in nix store. # so that these plugins can work on NixOS. - # - # related project: - # https://github.com/b-src/lazy-nix-helper.nvim plugins = with pkgs.vimPlugins; [ # search all the plugins using https://search.nixos.org/packages telescope-fzf-native-nvim - nvim-treesitter.withAllGrammars + # nvim-treesitter.withAllGrammars ]; }; } diff --git a/hosts/idols-ai/README.md b/hosts/idols-ai/README.md index 58deac7e..8b5be999 100644 --- a/hosts/idols-ai/README.md +++ b/hosts/idols-ai/README.md @@ -1,8 +1,12 @@ # Host - AI +Desktop (NixOS + preservation, LUKS + btrfs on nvme). Disk layout is declarative via +[disko](./disko-fs.nix) (target device: **nvme1n1**). + Related: -- [/nixos-installer/README.md](/nixos-installer/README.md) +- [nixos-installer README](/nixos-installer/README.md) – install from ISO using disko +- [disko-fs.nix](./disko-fs.nix) – partition/layout definition (ESP + LUKS + btrfs) ## TODOs @@ -10,7 +14,7 @@ Related: ## Info -disk status & mountpoints: +Current disk status and mountpoints (example; after migration layout is on nvme1n1): ```bash › df -Th @@ -36,50 +40,129 @@ tmpfs tmpfs 100K 0 100K 0% /var/lib/lxd/devlxd ~ › lsblk NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS -zram0 253:0 0 15.6G 0 disk [SWAP] nvme0n1 259:0 0 1.8T 0 disk -├─nvme0n1p1 259:2 0 598M 0 part /boot -└─nvme0n1p2 259:3 0 1.8T 0 part - └─crypted-nixos 254:0 0 1.8T 0 crypt /tmp - /swap/swapfile +├─nvme0n1p1 259:1 0 598M 0 part /boot +└─nvme0n1p2 259:2 0 1.8T 0 part + └─crypted-nixos 254:0 0 1.8T 0 crypt /swap/swapfile + /gnu/store /swap + /tmp /snapshots - /home/ryan/tmp + /gnu + /btr_pool + /var/log + /var/lib/qemu + /var/lib/tailscale + /var/lib/systemd + /var/lib/private + /var/lib/nixos + /var/lib/lxd + /var/lib/netbird-homelab + /var/lib/lxc + /var/lib/libvirt + /var/lib/iwd + /var/lib/flatpak + /var/lib/containers + /var/lib/cni + /var/lib/NetworkManager + /var/lib/bluetooth + /home/ryan/work /home/ryan/nix-config + /home/ryan/tmp /home/ryan/go /home/ryan/codes /home/ryan/Videos /home/ryan/Pictures /home/ryan/Music + /home/ryan/Games /home/ryan/Downloads + /home/ryan/.zoom /home/ryan/Documents /home/ryan/.wakatime + /home/ryan/.vscode + /home/ryan/.var + /home/ryan/.terraform.d/plugin-cache + /home/ryan/.steam /home/ryan/.ssh + /home/ryan/.pulumi /home/ryan/.pki /home/ryan/.npm /home/ryan/.mozilla - /home/ryan/.local/state - /home/ryan/.local/share + /home/ryan/.m2 + /home/ryan/.local/state/wireplumber + /home/ryan/.local/state/nvim + /home/ryan/.local/state/home-manager + /home/ryan/.local/share/uv + /home/ryan/.local/state/Heroic + /home/ryan/.local/state/nix/profiles + /home/ryan/.local/share/zoxide + /home/ryan/.local/share/umu + /home/ryan/.local/share/tiled + /home/ryan/.local/share/steel + /home/ryan/.local/share/remmina + /home/ryan/.local/share/password-store + /home/ryan/.local/share/opencode + /home/ryan/.local/share/nvim + /home/ryan/.local/share/nix + /home/ryan/.local/share/krita + /home/ryan/.local/share/lutris + /home/ryan/.local/share/keyrings + /home/ryan/.local/share/k9s + /home/ryan/.local/share/jupyter + /home/ryan/.local/share/flatpak + /home/ryan/.local/share/io.github.clash-verge-rev.clash-verge-rev + /home/ryan/.local/share/feral-interactive + /home/ryan/.local/share/direnv + /home/ryan/.local/share/clash-verge + /home/ryan/.local/share/containers + /home/ryan/.local/share/atuin + /home/ryan/.local/share/Steam + /home/ryan/.local/share/StardewValley + /home/ryan/.local/share/GOG.com + /home/ryan/.local/bin + /home/ryan/.local/pipx /home/ryan/.kube + /home/ryan/.gradle /home/ryan/.gnupg + /home/ryan/.kimi + /home/ryan/.ipython + /home/ryan/.gemini /home/ryan/.docker + /home/ryan/.config/sunshine + /home/ryan/.cursor + /home/ryan/.context7 /home/ryan/.config/remmina /home/ryan/.config/pulse + /home/ryan/.config/opencode + /home/ryan/.config/obs-studio + /home/ryan/.config/mozc + /home/ryan/.config/nushell + /home/ryan/.config/lutris + /home/ryan/.config/joplin + /home/ryan/.config/heroic /home/ryan/.config/google-chrome - /home/ryan/.config/github-copilot + /home/ryan/.config/gcloud /home/ryan/.config/freerdp + /home/ryan/.config/blender + /home/ryan/.config/chromium + /home/ryan/.config/LDtk + /home/ryan/.config/Joplin + /home/ryan/.config/Cursor + /home/ryan/.config/Code + /home/ryan/.conda + /home/ryan/.cargo + /home/ryan/.codex + /home/ryan/.cache /home/ryan/.aws + /home/ryan/.aliyun /etc/ssh /etc/secureboot /etc/nix/inputs - /etc/agenix /etc/NetworkManager/system-connections - /etc/machine-id - /home/ryan/.config/nushell/history.txt - /home/ryan/.wakatime.cfg + /etc/agenix + /etc/netbird-homelab /nix/store - /var/log - /var/lib - /nix + /etc/machine-id /persistent + /nix ``` diff --git a/hosts/idols-ai/default.nix b/hosts/idols-ai/default.nix index 3ac82a3b..e65bfdfc 100644 --- a/hosts/idols-ai/default.nix +++ b/hosts/idols-ai/default.nix @@ -1,4 +1,9 @@ -{ myvars, lib, ... }: +{ + disko, + myvars, + lib, + ... +}: ############################################################# # # Ai - my main computer, with NixOS + I5-13600KF + RTX 4090 GPU, for gaming & daily use. @@ -14,6 +19,8 @@ let in { imports = [ + disko.nixosModules.default + ./disko-fs.nix ./netdev-mount.nix # Include the results of the hardware scan. ./hardware-configuration.nix diff --git a/hosts/idols-ai/disko-fs.nix b/hosts/idols-ai/disko-fs.nix new file mode 100644 index 00000000..eac1781f --- /dev/null +++ b/hosts/idols-ai/disko-fs.nix @@ -0,0 +1,128 @@ +# Disko layout for idols-ai on nvme1n1 (target disk after migration). +# Same structure as current nvme0n1: ESP + LUKS + btrfs with ephemeral root (tmpfs). +# +# Format & mount (from installer or live system): +# nix run github:nix-community/disko -- --mode disko ./disko-fs.nix +# Mount only (after first format): +# nix run github:nix-community/disko -- --mode mount ./disko-fs.nix +# +# Use by-id for stability; override device when installing, e.g.: +# nixos-install --flake .#ai --option disko.devices.disk.nixos-ai.device /dev/nvme1n1 +{ + # Ephemeral root; preservation mounts /persistent for state. + fileSystems."/persistent".neededForBoot = true; + + disko.devices = { + # Ephemeral root; relatime and mode=755 so systemd does not set 777. + nodev."/" = { + fsType = "tmpfs"; + mountOptions = [ + "relatime" # Update inode access times relative to modify/change time + "mode=755" + ]; + }; + + disk.nixos-ai = { + type = "disk"; + # Override at install time if needed: --option disko.devices.disk.nixos-ai.device /dev/nvme1n1 + device = "/dev/nvme1n1"; + content = { + type = "gpt"; + partitions = { + # EFI system partition; must stay unencrypted for UEFI to load the bootloader. + ESP = { + priority = 1; + name = "ESP"; + start = "1M"; + end = "600M"; + type = "EF00"; # EF00 = ESP in GPT + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ + "fmask=0177" # File mask: 777-177=600 (owner rw-, group/others ---) + "dmask=0077" # Directory mask: 777-077=700 (owner rwx, group/others ---) + "noexec,nosuid,nodev" # Security: no execution, ignore setuid, no device nodes + ]; + }; + }; + # Root partition: LUKS encrypted, then btrfs with subvolumes. + root = { + size = "100%"; + content = { + type = "luks"; + name = "nixos-luks"; # Mapper name; match boot.initrd.luks + settings = { + allowDiscards = true; # TRIM for SSDs; slightly less secure, better performance + }; + # Add boot.initrd.luks.devices so initrd prompts for passphrase at boot + initrdUnlock = true; + # cryptsetup luksFormat options + extraFormatArgs = [ + "--type luks2" + "--cipher aes-xts-plain64" + "--hash sha512" + "--iter-time 5000" + "--key-size 256" + "--pbkdf argon2id" + "--use-random" # Block until enough entropy from /dev/random + ]; + extraOpenArgs = [ + "--timeout 10" + ]; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; # Force overwrite if filesystem already exists + subvolumes = { + # Top-level subvolume (id 5); used for btrfs send/receive and snapshots + "/" = { + mountpoint = "/btr_pool"; + mountOptions = [ "subvolid=5" ]; + }; + "@nix" = { + mountpoint = "/nix"; + mountOptions = [ + "compress-force=zstd:1" # Save space and reduce I/O on SSD + "noatime" + ]; + }; + "@guix" = { + mountpoint = "/gnu"; + mountOptions = [ + "compress-force=zstd:1" + "noatime" + ]; + }; + "@persistent" = { + mountpoint = "/persistent"; + mountOptions = [ + "compress-force=zstd:1" + ]; + }; + "@snapshots" = { + mountpoint = "/snapshots"; + mountOptions = [ + "compress-force=zstd:1" + ]; + }; + "@tmp" = { + mountpoint = "/tmp"; + mountOptions = [ + "compress-force=zstd:1" + ]; + }; + # Swap subvolume read-only; disko creates swapfile and adds swapDevices + "@swap" = { + mountpoint = "/swap"; + swap.swapfile.size = "20G"; + }; + }; + }; + }; + }; + }; + }; + }; + }; +} diff --git a/hosts/idols-ai/hardware-configuration.nix b/hosts/idols-ai/hardware-configuration.nix index 256da21a..3037319c 100644 --- a/hosts/idols-ai/hardware-configuration.nix +++ b/hosts/idols-ai/hardware-configuration.nix @@ -58,132 +58,8 @@ "exfat" ]; - boot.initrd = { - # unlocked luks devices via a keyfile or prompt a passphrase. - luks.devices."crypted-nixos" = { - # NOTE: DO NOT use device name here(like /dev/sda, /dev/nvme0n1p2, etc), use UUID instead. - # https://github.com/ryan4yin/nix-config/issues/43 - device = "/dev/disk/by-uuid/a21ca82a-9ee6-4e5c-9d3f-a93e84e4e0f4"; - # the keyfile(or device partition) that should be used as the decryption key for the encrypted device. - # if not specified, you will be prompted for a passphrase instead. - #keyFile = "/root-part.key"; - - # whether to allow TRIM requests to the underlying device. - # it's less secure, but faster. - allowDiscards = true; - # Whether to bypass dm-crypt’s internal read and write workqueues. - # Enabling this should improve performance on SSDs; - # https://wiki.archlinux.org/index.php/Dm-crypt/Specialties#Disable_workqueue_for_increased_solid_state_drive_(SSD)_performance - bypassWorkqueues = true; - }; - }; - - fileSystems."/btr_pool" = { - device = "/dev/disk/by-uuid/1167076c-dee1-486c-83c1-4b1af37555cd"; - fsType = "btrfs"; - # btrfs's top-level subvolume, internally has an id 5 - # we can access all other subvolumes from this subvolume. - options = [ "subvolid=5" ]; - }; - - # equal to `mount -t tmpfs tmpfs /` - fileSystems."/" = { - device = "tmpfs"; - fsType = "tmpfs"; - # set mode to 755, otherwise systemd will set it to 777, which cause problems. - # relatime: Update inode access times relative to modify or change time. - options = [ - "relatime" - "mode=755" - ]; - }; - - fileSystems."/nix" = { - device = "/dev/disk/by-uuid/1167076c-dee1-486c-83c1-4b1af37555cd"; - fsType = "btrfs"; - options = [ - "subvol=@nix" - "noatime" - "compress-force=zstd:1" - ]; - }; - - # for guix store, which use `/gnu/store` as its store directory. - fileSystems."/gnu" = { - device = "/dev/disk/by-uuid/1167076c-dee1-486c-83c1-4b1af37555cd"; - fsType = "btrfs"; - options = [ - "subvol=@guix" - "noatime" - "compress-force=zstd:1" - ]; - }; - - fileSystems."/persistent" = { - device = "/dev/disk/by-uuid/1167076c-dee1-486c-83c1-4b1af37555cd"; - fsType = "btrfs"; - options = [ - "subvol=@persistent" - "compress-force=zstd:1" - ]; - # preservation's data is required for booting. - neededForBoot = true; - }; - - fileSystems."/snapshots" = { - device = "/dev/disk/by-uuid/1167076c-dee1-486c-83c1-4b1af37555cd"; - fsType = "btrfs"; - options = [ - "subvol=@snapshots" - "compress-force=zstd:1" - ]; - }; - - fileSystems."/tmp" = { - device = "/dev/disk/by-uuid/1167076c-dee1-486c-83c1-4b1af37555cd"; - fsType = "btrfs"; - options = [ - "subvol=@tmp" - "compress-force=zstd:1" - ]; - }; - - # mount swap subvolume in readonly mode. - fileSystems."/swap" = { - device = "/dev/disk/by-uuid/1167076c-dee1-486c-83c1-4b1af37555cd"; - fsType = "btrfs"; - options = [ - "subvol=@swap" - "ro" - ]; - }; - - # remount swapfile in read-write mode - fileSystems."/swap/swapfile" = { - # the swapfile is located in /swap subvolume, so we need to mount /swap first. - depends = [ "/swap" ]; - - device = "/swap/swapfile"; - fsType = "none"; - options = [ - "bind" - "rw" - ]; - }; - - fileSystems."/boot" = { - device = "/dev/disk/by-uuid/90FB-9F88"; - fsType = "vfat"; - options = [ - "fmask=0177" # File mask: 777-177=600 (Owner: rw-, Group/Others: ---) - "dmask=0077" # Directory mask: 777-077=700 (Owner: rwx, Group/Others: ---) - "noexec,nosuid,nodev" # Security: Block execution, ignore setuid, and disable device nodes - ]; - }; - - swapDevices = [ - { device = "/swap/swapfile"; } - ]; + # LUKS initrd, all fileSystems (/, /boot, /btr_pool, /nix, /gnu, /persistent, /snapshots, /tmp, /swap) + # and swap (including /swap/swapfile bind and swapDevices) are managed by disko (disko-fs.nix). # Enables DHCP on each ethernet and wireless interface. In case of scripted networking # (the default) this is the recommended approach. When using systemd-networkd it's diff --git a/nixos-installer/README.md b/nixos-installer/README.md index 8a41a00a..d3f33eeb 100644 --- a/nixos-installer/README.md +++ b/nixos-installer/README.md @@ -1,297 +1,134 @@ # Nix Environment Setup for Host: Idols - Ai -> :red_circle: **IMPORTANT**: **Once again, you should NOT deploy this flake directly on your -> machine :exclamation: Please write your own configuration from scratch, and use my configuration -> and documentation for reference only.** +> :red_circle: **IMPORTANT**: **Do not deploy this flake directly on your machine.** Write your own +> configuration from scratch and use this only as reference.\*\* -This flake prepares a Nix environment for setting my desktop [/hosts/idols_ai](/hosts/idols_ai/)(in -main flake) up on a new machine. +This flake prepares a Nix environment for setting up the desktop host +[hosts/idols-ai](../hosts/idols-ai/) (from the main flake) on a new machine. Other docs: -- README for [/hosts/12kingdoms_shoukei](/hosts/12kingdoms_shoukei): - [./README.shoukei.md](./README.shoukei.md) +- [README for 12kingdoms-shoukei](./README.shoukei.md) -TODOs: +## Why this flake exists -- [ ] declarative disk partitioning with [disko](https://github.com/nix-community/disko) +The main flake is heavy and slow to deploy. This minimal flake helps to: -## Why an extra flake is needed? +1. Adjust and verify `hardware-configuration.nix` and disk layout before deploying the main flake. +2. Test preservation, Secure Boot, TPM2, encryption, etc. on a VM or fresh install. -The configuration of the main flake, [/flake.nix](/flake.nix), is heavy, and it takes time to debug -& deploy. This simplified flake is tiny and can be deployed very quickly, it helps me to: +Disk layout is **declarative** via [disko](https://github.com/nix-community/disko); manual +partitioning is no longer needed. -1. Adjust & verify my `hardware-configuration.nix` modification quickly before deploying the main - flake. -2. Test some new filesystem related features on a NixOS virtual machine, such as preservation, - Secure Boot, TPM2, Encryption, etc. +## Steps to deploy -## Steps to Deploying this flake +1. Create a USB install medium from the official NixOS ISO and boot from it. -First, create a USB install medium from NixOS's official ISO image and boot from it. +### 1. Partition and mount with disko (recommended) -### 1. Encrypting with LUKS(everything except ESP) - -> https://nixos.org/manual/nixos/stable/#sec-installation-manual-partitioning - -> [dm-crypt/Encrypting an entire system - Arch Wiki](https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system) - -> [Encrypted /boot - GRUB2 - Arch Wiki](https://wiki.archlinux.org/title/GRUB#Encrypted_/boot) - -> [Frequently asked questions (FAQ) - cryptsetup](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions) - -Securing a root file system is where dm-crypt excels, feature and performance-wise. An encrypted -root file system protects everything on the system, it make the system a black box to the attacker. - -1. The EFI system partition(ESP) must be left unencrypted, and is mounted at `/boot` - 1. Since the UEFI firmware can only load boot loaders from unencrypted partitions. -2. Secure Boot is enabled, everything in ESP is signed. -3. The BTRFS file system with subvolumes is used for the root partition, and the swap area is a - swapfile on a dedicated BTRFS subvolume, thus the swap area is also encrypted. - -And the boot flow is: - -1. The UEFI firmware loads the boot loader from the ESP(`/boot`). -2. The boot loader loads the kernel and initrd from the ESP(`/boot`). -3. **The initrd prompts for the passphrase to unlock the root partition**. -4. The initrd unlocks the root partition and mounts it at `/`. -5. The initrd continues the boot process, and hands over the control to the kernel. - -Partitioning the disk: +Layout is defined in [../hosts/idols-ai/disko-fs.nix](../hosts/idols-ai/disko-fs.nix): **nvme1n1**, +ESP (450M) + LUKS + btrfs (subvolumes: @nix, @guix, @persistent, @snapshots, @tmp, @swap). Root is +tmpfs; [preservation](https://github.com/nix-community/preservation) uses `/persistent`. ```bash -# NOTE: `cat README.md | grep part-1 > part-1.sh` to generate this script - -# Create a GPT partition table -parted /dev/nvme0n1 -- mklabel gpt # part-1 - -# NixOS by default uses the ESP (EFI system partition) as its /boot partition -# Create a 512MB EFI system partition -parted /dev/nvme0n1 -- mkpart ESP fat32 2MB 629MB # part-1 - -# set the boot flag on the ESP partition -# Format: -# set partition flag state -parted /dev/nvme0n1 -- set 1 esp on # part-1 - -# Create the root partition using the rest of the disk -# Format: -# mkpart [part-type name fs-type] start end -parted /dev/nvme0n1 -- mkpart primary 630MB 100% # part-1 - -# show disk status -lsblk -``` - -Encrypting the root partition: - -```bash -lsblk -# show cryptsetup's compiled in defaults -cryptsetup --help - -# NOTE: `cat shoukei.md | grep luks > luks.sh` to generate this script -# encrypt the root partition with luks2 and argon2id, will prompt for a passphrase, which will be used to unlock the partition. -cryptsetup luksFormat --type luks2 --cipher aes-xts-plain64 --hash sha512 --iter-time 5000 --key-size 256 --pbkdf argon2id --use-random --verify-passphrase /dev/nvme0n1p2 - -# show status -cryptsetup luksDump /dev/nvme0n1p2 - -# open(unlock) the device with the passphrase you just set -cryptsetup luksOpen /dev/nvme0n1p2 crypted-nixos - -# show disk status -lsblk -``` - -Formatting the root partition: - -```bash -# NOTE: `cat shoukei.md | grep create-btrfs > btrfs.sh` to generate this script -mkfs.fat -F 32 -n ESP /dev/nvme0n1p1 # create-btrfs -# format the root partition with btrfs and label it -mkfs.btrfs -L crypted-nixos /dev/mapper/crypted-nixos # create-btrfs - -# mount the root partition and create subvolumes -mount /dev/mapper/crypted-nixos /mnt # create-btrfs -btrfs subvolume create /mnt/@nix # create-btrfs -btrfs subvolume create /mnt/@guix # create-btrfs -btrfs subvolume create /mnt/@tmp # create-btrfs -btrfs subvolume create /mnt/@swap # create-btrfs -btrfs subvolume create /mnt/@persistent # create-btrfs -btrfs subvolume create /mnt/@snapshots # create-btrfs -umount /mnt # create-btrfs - -# NOTE: `cat shoukei.md | grep mount-1 > mount-1.sh` to generate this script -# Remount the root partition with the subvolumes you just created -# -# Enable zstd compression to: -# 1. Reduce the read/write operations, which helps to: -# 1. Extend the life of the SSD. -# 2. improve the performance of disks with low IOPS / RW throughput, such as HDD and SATA SSD. -# 2. Save the disk space. -mkdir /mnt/{nix,gnu,tmp,swap,persistent,snapshots,boot} # mount-1 -mount -o compress-force=zstd:1,noatime,subvol=@nix /dev/mapper/crypted-nixos /mnt/nix # mount-1 -mount -o compress-force=zstd:1,noatime,subvol=@guix /dev/mapper/crypted-nixos /mnt/gnu # mount-1 -mount -o compress-force=zstd:1,subvol=@tmp /dev/mapper/crypted-nixos /mnt/tmp # mount-1 -mount -o subvol=@swap /dev/mapper/crypted-nixos /mnt/swap # mount-1 -mount -o compress-force=zstd:1,noatime,subvol=@persistent /dev/mapper/crypted-nixos /mnt/persistent # mount-1 -mount -o compress-force=zstd:1,noatime,subvol=@snapshots /dev/mapper/crypted-nixos /mnt/snapshots # mount-1 -mount /dev/nvme0n1p1 /mnt/boot # mount-1 - -# create a swapfile on btrfs file system -# This command will disable CoW / compression on the swap subvolume and then create a swapfile. -# because the linux kernel requires that swapfile must not be compressed or have copy-on-write(CoW) enabled. -btrfs filesystem mkswapfile --size 96g --uuid clear /mnt/swap/swapfile # mount-1 - -# check whether the swap subvolume has CoW disabled -# the output of `lsattr` for the swap subvolume should be: -# ---------------C------ /swap/swapfile -# if not, delete the swapfile, and rerun the commands above. -lsattr /mnt/swap - -# mount the swapfile as swap area -swapon /mnt/swap/swapfile # mount-1 -``` - -Now, the disk status should be: - -```bash -# show disk status -$ lsblk -nvme0n1 259:0 0 1.8T 0 disk -├─nvme0n1p1 259:2 0 600M 0 part /mnt/boot -└─nvme0n1p2 259:3 0 1.8T 0 part - └─crypted-nixos 254:0 0 1.8T 0 crypt /mnt/swap - /mnt/persistent - /mnt/snapshots - /mnt/nix - /mnt/tmp - -# show swap status -$ swapon -s -Filename Type Size Used Priority -/swap/swapfile file 100663292 0 -2 -``` - -### 2. Generating the NixOS Configuration and Installing NixOS - -Clone this repository: - -```bash -# enter an shell with git/vim/ssh-agent available -nix-shell -p git vim just - -# clone this repository git clone https://github.com/ryan4yin/nix-config.git +cd nix-config/nixos-installer + +# WARNING: destroys all data on nvme1n1. Layout is mounted at /mnt by default. +sudo su +nix run github:nix-community/disko -- --mode destroy,format,mount ../hosts/idols-ai/disko-fs.nix ``` -Then, generate the NixOS configuration: +### 2. Install NixOS ```bash -# nixos configurations -nixos-generate-config --root /mnt +sudo su -# we need to update our filesystem configs in old hardware-configuration.nix according to the generated one. -cp /etc/nixos/hardware-configuration.nix ./nix-config/hosts/idols_ai/hardware-configuration-new.nix -vim . +# add ssh key to ssh-agent, it's required to pull my asahi=firmware +$(ssh-agent) +ssh-add /path/to/ssh-key + +# From nix-config/nixos-installer +nixos-install --root /mnt --flake .#ai --no-root-password ``` -Then, Install NixOS: +### 3. Copy data into /persistent and reboot + +Preservation expects state under `/persistent`; copy or migrate data there (e.g. from an old disk), +then leave the chroot and reboot. ```bash -cd ~/nix-config/hosts/idols_ai/nixos-installer - -# run this command if you're retrying to run nixos-install -rm -rf /mnt/etc - -# install nixos -# NOTE: the root password you set here will be discarded when reboot -nixos-install --root /mnt --flake .#ai --no-root-password --show-trace --verbose # instlall-1 - -# if you want to use a cache mirror, run this command instead -# replace the mirror url with your own -nixos-install --root /mnt --flake .#shoukei --no-root-password --show-trace --verbose --option substituters "https://mirrors.ustc.edu.cn/nix-channels/store https://cache.nixos.org/" # install-2 - -# enter into the installed system, check password & users -# `su ryan` => `sudo -i` => enter ryan's password => successfully login -# if login failed, check the password you set in install-1, and try again nixos-enter -# NOTE: DO NOT skip this step!!! -# copy the essential files into /persistent -# otherwise the / will be cleared and data will lost -## NOTE: preservation just create links from / to /persistent -## We need to copy files into /persistent manually!!! -mv /etc/machine-id /persistent/etc/ -mv /etc/ssh /persistent/etc/ - - -# delete the generated configuration after editing -rm -f /mnt/etc/nixos -rm ~/nix-config/hosts/idols_ai/hardware-configuration-new.nix - -# NOTE: `cat shoukei.md | grep git-1 > git-1.sh` to generate this script -# commit the changes after installing nixos successfully -git config --global user.email "ryan4yin@linux.com" # git-1 -git config --global user.name "Ryan Yin" # git-1 -git commit -am "feat: update hardware-configuration" - -# copy our configuration to the installed file system -cp -r ../nix-config /mnt/etc/nixos - -# sync the disk, unmount the partitions, and close the encrypted device -sync -swapoff /mnt/swap/swapfile +# Copy/migrate into /persistent as needed (e.g. from old nvme0n1) +# At minimum for a fresh install: +# mkdir -p /persistent/etc +# mv /etc/machine-id /persistent/etc/ +# mv /etc/ssh /persistent/etc/ +# Then exit and: +exit umount -R /mnt -cryptsetup close /dev/mapper/crypted-nixos reboot ``` -And then reboot. +After reboot, set the boot order in firmware so the system boots from nvme1n1. The old disk (e.g. +nvme0n1) can be reused for something else. -## Deploying the main flake's NixOS configuration - -After rebooting, we need to generate a new SSH key for the new machine, and add it to GitHub, so -that the new machine can pull my private secrets repo: +### Optional: use a cache mirror ```bash -# 1. Generate a new SSH key with a strong passphrase -ssh-keygen -t ed25519 -a 256 -C "ryan@idols-ai" -f ~/.ssh/idols_ai -# 2. Add the ssh key to the ssh-agent, so that nixos-rebuild can use it to pull my private secrets repo. -ssh-add ~/.ssh/idols_ai +nixos-install --root /mnt --flake .#ai --no-root-password \ + --option substituters "https://mirrors.ustc.edu.cn/nix-channels/store https://cache.nixos.org/" ``` -Then follow the instructions in [../secrets/README.md](../secrets/README.md) to rekey all my secrets -with the new host's system-level SSH key(`/etc/ssh/ssh_host_ed25519_key`), so that agenix can -decrypt them automatically on the new host when I deploy my NixOS configuration. +## Deploying the main flake after install -After all these steps, we can finally deploy the main flake's NixOS configuration by: +After the first boot: + +1. **SSH key** (for pulling the private secrets repo): + + ```bash + ssh-keygen -t ed25519 -a 256 -C "ryan@idols-ai" -f ~/.ssh/idols_ai + ssh-add ~/.ssh/idols_ai + ``` + +2. Rekey secrets for the new host: follow [../secrets/README.md](../secrets/README.md) so agenix can + decrypt using this host’s SSH key. + +3. Deploy the main config: + + ```bash + sudo mv /etc/nixos ~/nix-config + sudo chown -R ryan:ryan ~/nix-config + cd ~/nix-config + just hypr + ``` + +4. **Secure Boot**: follow + [lanzaboote Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) + and [hosts/idols-ai/secureboot.nix](../hosts/idols-ai/secureboot.nix). + +## Changing LUKS2 passphrase ```bash -sudo mv /etc/nixos ~/nix-config -sudo chown -R ryan:ryan ~/nix-config +# Test current passphrase +sudo cryptsetup --verbose open --test-passphrase /path/to/device -cd ~/nix-config +# Change passphrase +sudo cryptsetup luksChangeKey /path/to/device -# deploy the configuration via Justfile -just hypr +# Verify +sudo cryptsetup --verbose open --test-passphrase /path/to/device ``` -Finally, to enable secure boot, follow the instructions in -[lanzaboote - Quick Start](https://github.com/nix-community/lanzaboote/blob/master/docs/QUICK_START.md) -and -[nix-config/ai/secure-boot.nix](https://github.com/ryan4yin/nix-config/blob/main/hosts/idols_ai/secureboot.nix) +## Reference: layout and manual partitioning -## Change LUKS2's passphrase +The layout (ESP + LUKS + btrfs, ephemeral root, preservation on `/persistent`) is described in +[../hosts/idols-ai/disko-fs.nix](../hosts/idols-ai/disko-fs.nix). Prefer using disko; manual +partitioning is no longer documented here. -```bash -# test the old passphrase -sudo cryptsetup --verbose open --test-passphrase /path/to/dev/ +Background: -# change the passphrase -sudo cryptsetup luksChangeKey /path/to/dev/ - -# test the new passphrase -sudo cryptsetup --verbose open --test-passphrase /path/to/dev/ -``` +- [NixOS manual installation](https://nixos.org/manual/nixos/stable/#sec-installation-manual-partitioning) +- [dm-crypt / Encrypting an entire system (Arch)](https://wiki.archlinux.org/title/Dm-crypt/Encrypting_an_entire_system) +- [cryptsetup FAQ](https://gitlab.com/cryptsetup/cryptsetup/wikis/FrequentlyAskedQuestions) diff --git a/nixos-installer/flake.nix b/nixos-installer/flake.nix index 02f63a8b..e9b12e8e 100644 --- a/nixos-installer/flake.nix +++ b/nixos-installer/flake.nix @@ -4,6 +4,8 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; preservation.url = "github:nix-community/preservation"; + disko.url = "github:nix-community/disko/v1.11.0"; + disko.inputs.nixpkgs.follows = "nixpkgs"; nuenv.url = "github:DeterminateSystems/nuenv"; nixos-apple-silicon = { @@ -21,6 +23,7 @@ outputs = inputs@{ nixpkgs, + disko, nixos-apple-silicon, my-asahi-firmware, ... @@ -48,6 +51,8 @@ ../modules/nixos/base/user-group.nix ../modules/nixos/base/ssh.nix + disko.nixosModules.default + ../hosts/idols-ai/disko-fs.nix ../hosts/idols-ai/hardware-configuration.nix ../hosts/idols-ai/preservation.nix ];