Created
October 17, 2021 19:50
-
-
Save lucasvo/35e0745b72dd384dcb9b9ee5bae5fecb to your computer and use it in GitHub Desktop.
NixOS with ZFS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# | |
# NixOS install script synthesized from: | |
# | |
# - https://gist.github.com/mx00s/ea2462a3fe6fdaa65692fe7ee824de3e | |
# - Erase Your Darlings (https://grahamc.com/blog/erase-your-darlings) | |
# - OpenZFS NixOS manual (https://openzfs.github.io/openzfs-docs/Getting%20Started/NixOS/Root%20on%20ZFS/0-overview.html) | |
# - ZFS Datasets for NixOS (https://grahamc.com/blog/nixos-on-zfs) | |
# - NixOS Manual (https://nixos.org/nixos/manual/) | |
# | |
# It expects the name of the block device (e.g. 'sda') to partition | |
# and install NixOS. The script must also be executed as root. | |
# | |
# Example: `sudo ./install.sh sde` | |
# | |
set -euo pipefail | |
################################################################################ | |
export COLOR_RESET="\033[0m" | |
export RED_BG="\033[41m" | |
export BLUE_BG="\033[44m" | |
function err { | |
echo -e "${RED_BG}$1${COLOR_RESET}" | |
} | |
function info { | |
echo -e "${BLUE_BG}$1${COLOR_RESET}" | |
} | |
################################################################################ | |
export DISK=$1 | |
if ! [[ -v DISK ]]; then | |
err "Missing argument. Expected block device name, e.g. 'sda'" | |
exit 1 | |
fi | |
export DISK_PATH="/dev/${DISK}" | |
if ! [[ -b "$DISK_PATH" ]]; then | |
err "Invalid argument: '${DISK_PATH}' is not a block special file" | |
exit 1 | |
fi | |
if [[ "$EUID" > 0 ]]; then | |
err "Must run as root" | |
exit 1 | |
fi | |
export ZFS_POOL="rpool" | |
# ephemeral datasets | |
export ZFS_ENCRYPTED="${ZFS_POOL}/encrypted" | |
export ZFS_LOCAL="${ZFS_ENCRYPTED}/local" | |
export ZFS_DS_ROOT="${ZFS_LOCAL}/root" | |
export ZFS_DS_NIX="${ZFS_LOCAL}/nix" | |
# persistent datasets | |
export ZFS_SAFE="${ZFS_ENCRYPTED}/safe" | |
export ZFS_DS_HOME="${ZFS_SAFE}/home" | |
export ZFS_DS_PERSIST="${ZFS_SAFE}/persist" | |
export ZFS_BLANK_SNAPSHOT="${ZFS_DS_ROOT}@blank" | |
################################################################################ | |
info "Running the UEFI (GPT) partitioning and formatting directions from the NixOS manual ..." | |
blkdiscard -f "$DISK_PATH" | |
sgdisk --zap-all "$DISK_PATH" | |
sgdisk -n 0:1M:+513M -t 0:EF00 "$DISK_PATH" | |
sgdisk -n 0:0:+24G -t 0:8200 "$DISK_PATH" | |
sgdisk -n 0:0:0 -t 0:EF00 "$DISK_PATH" | |
export BOOT="${DISK_PATH}p1" | |
export SWAP="${DISK_PATH}p2" | |
export ZFS="${DISK_PATH}p3" | |
partprobe "$DISK_PATH" | |
sleep 1 | |
BOOT_DISK_UUID="$(blkid --match-tag UUID --output value $BOOT)" | |
SWAP_DISK_PARTUUID="$(blkid --match-tag PARTUUID --output value $SWAP)" | |
info "Formatting boot & swap partition ..." | |
mkfs.vfat -n boot "$BOOT" | |
mkswap $SWAP | |
swapon $SWAP | |
info "Creating '$ZFS_POOL' ZFS pool for '$ZFS' ..." | |
zpool create \ | |
-O acltype=posixacl \ | |
-O compression=on \ | |
-O normalization=formD \ | |
-O xattr=sa \ | |
-f $ZFS_POOL $ZFS | |
ZFS_DISK_UUID="$(blkid --match-tag UUID --output value $ZFS)" | |
info "Creating '$ZFS_ENCRYPTED' ZFS pool for '$ZFS' ..." | |
zfs create \ | |
-p \ | |
-o mountpoint=legacy \ | |
-o encryption=aes-256-gcm \ | |
-o keylocation=prompt \ | |
-o keyformat=passphrase \ | |
"$ZFS_DS_ROOT" | |
info "Creating '$ZFS_DS_ROOT' ZFS dataset ..." | |
zfs create -p -o mountpoint=legacy "$ZFS_DS_ROOT" | |
info "Configuring extended attributes setting for '$ZFS_DS_ROOT' ZFS dataset ..." | |
zfs set xattr=sa "$ZFS_DS_ROOT" | |
info "Configuring access control list setting for '$ZFS_DS_ROOT' ZFS dataset ..." | |
zfs set acltype=posixacl "$ZFS_DS_ROOT" | |
info "Creating '$ZFS_BLANK_SNAPSHOT' ZFS snapshot ..." | |
zfs snapshot "$ZFS_BLANK_SNAPSHOT" | |
info "Mounting '$ZFS_DS_ROOT' to /mnt ..." | |
mount -t zfs "$ZFS_DS_ROOT" /mnt | |
info "Mounting '$BOOT' to /mnt/boot ..." | |
mkdir -p /mnt/boot | |
mount -t vfat "$BOOT" /mnt/boot | |
info "Creating '$ZFS_DS_NIX' ZFS dataset ..." | |
zfs create -p -o mountpoint=legacy "$ZFS_DS_NIX" | |
info "Disabling access time setting for '$ZFS_DS_NIX' ZFS dataset ..." | |
zfs set atime=off "$ZFS_DS_NIX" | |
info "Mounting '$ZFS_DS_NIX' to /mnt/nix ..." | |
mkdir -p /mnt/nix | |
mount -t zfs "$ZFS_DS_NIX" /mnt/nix | |
info "Creating '$ZFS_DS_HOME' ZFS dataset ..." | |
zfs create -p -o mountpoint=legacy "$ZFS_DS_HOME" | |
info "Mounting '$ZFS_DS_HOME' to /mnt/home ..." | |
mkdir -p /mnt/home | |
mount -t zfs "$ZFS_DS_HOME" /mnt/home | |
info "Creating '$ZFS_DS_PERSIST' ZFS dataset ..." | |
zfs create -p -o mountpoint=legacy "$ZFS_DS_PERSIST" | |
info "Mounting '$ZFS_DS_PERSIST' to /mnt/persist ..." | |
mkdir -p /mnt/persist | |
mount -t zfs "$ZFS_DS_PERSIST" /mnt/persist | |
info "Permit ZFS auto-snapshots on ${ZFS_SAFE}/* datasets ..." | |
zfs set com.sun:auto-snapshot=true "$ZFS_DS_HOME" | |
zfs set com.sun:auto-snapshot=true "$ZFS_DS_PERSIST" | |
info "Creating persistent directories ..." | |
mkdir -p /mnt/persist/etc/ssh | |
mkdir -p /persist/etc/NetworkManager/system-connections | |
mkdir -p /persist/var/lib/bluetooth | |
mkdir -p /persist/etc/ssh | |
info "Generating NixOS configuration (/mnt/etc/nixos/*.nix) ..." | |
nixos-generate-config --root /mnt | |
info "Enter personal user name ..." | |
read USER_NAME | |
info "Enter password for '${USER_NAME}' user ..." | |
USER_PASSWORD_HASH="$(mkpasswd -m sha-512 | sed 's/\$/\\$/g')" | |
info "Moving generated hardware-configuration.nix to /persist/etc/nixos/ ..." | |
mkdir -p /mnt/persist/etc/nixos | |
mv /mnt/etc/nixos/hardware-configuration.nix /mnt/persist/etc/nixos/ | |
info "Backing up the originally generated configuration.nix to /persist/etc/nixos/configuration.nix.original ..." | |
mv /mnt/etc/nixos/configuration.nix /mnt/persist/etc/nixos/configuration.nix.original | |
NIXEL="$(dirname "$(readlink -fm "$0")")" | |
cp -r $NIXEL /mnt/persist/etc/nixel | |
info "Writing NixOS configuration to /persist/etc/nixos/ ..." | |
cat <<EOF > /mnt/persist/etc/nixos/configuration.nix | |
{ config, pkgs, lib, ... }: | |
{ | |
imports = | |
[ | |
../nixel/configuration.nix | |
./hardware-configuration.nix | |
]; | |
fileSystems."/" = | |
{ device = "rpool/encrypted/local/root"; | |
fsType = "zfs"; | |
options= [ "zfsutil" ]; | |
}; | |
fileSystems."/boot" = | |
{ device = "/dev/disk/by-uuid/${BOOT_DISK_UUID}"; | |
fsType = "vfat"; | |
}; | |
fileSystems."/nix" = | |
{ device = "rpool/encrypted/local/nix"; | |
fsType = "zfs"; | |
options= ["zfsutil"]; | |
}; | |
fileSystems."/home" = | |
{ device = "rpool/encrypted/safe/home"; | |
fsType = "zfs"; | |
options= ["zfsutil"]; | |
}; | |
fileSystems."/persist" = | |
{ device = "rpool/encrypted/safe/persist"; | |
fsType = "zfs"; | |
options= ["zfsutil"]; | |
}; | |
swapDevices = [ | |
{ device = "/dev/disk/by-partuuid/${SWAP_DISK_PARTUUID}"; randomEncryption.enable = true;} | |
]; | |
boot.supportedFilesystems = [ "zfs" ]; | |
boot.zfs.devNodes="${DISK_PATH}"; | |
boot.initrd.postDeviceCommands = lib.mkAfter '' | |
zfs rollback -r ${ZFS_BLANK_SNAPSHOT} | |
''; | |
networking = { | |
hostId = "$(head -c 8 /etc/machine-id)"; | |
}; | |
environment.etc."machine-id".text = "$(cat /etc/machine-id)"; | |
services.zfs = { | |
autoScrub.enable = true; | |
autoSnapshot.enable = true; | |
# TODO: autoReplication | |
}; | |
users = { | |
mutableUsers = false; | |
users = { | |
${USER_NAME} = { | |
initialHashedPassword = "${USER_PASSWORD_HASH}"; | |
extraGroups = [ "wheel" "nixel" "audio" "video" "bluetooth" "networkmanager" "docker" "libvirtd"]; | |
isNormalUser = true; | |
uid = 1000; | |
home = "/home/${USER_NAME}"; | |
}; | |
}; | |
}; | |
} | |
EOF | |
info "Installing NixOS to /mnt ..." | |
ln -s /mnt/persist/etc/nixos/configuration.nix /mnt/etc/nixos/configuration.nix | |
nixos-install -I "nixos-config=/mnt/persist/etc/nixos/configuration.nix" --no-root-passwd # already prompted for and configured password |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for this, it's been super helpful
I think line 113 should be
"$ZFS_ENCRYPTED"