refactor: migrate idols-ai to new ssd (#247)

* 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
This commit is contained in:
Ryan Yin
2026-03-16 10:07:08 +08:00
committed by GitHub
parent 850a7b2c43
commit a5295500f1
9 changed files with 337 additions and 403 deletions

6
flake.lock generated
View File

@@ -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": {

View File

@@ -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

View File

@@ -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
];
};
}

View File

@@ -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
```

View File

@@ -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

128
hosts/idols-ai/disko-fs.nix Normal file
View File

@@ -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";
};
};
};
};
};
};
};
};
};
}

View File

@@ -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-crypts 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

View File

@@ -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 hosts 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)

View File

@@ -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
];