-
-
Save byrongibson/fe8e24d2433d2e082bc238315c0b3483 to your computer and use it in GitHub Desktop.
NixOS install script based on @grahamc's "Erase Your Darlings" blog post
This file contains hidden or 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: | |
| # | |
| # - Erase Your Darlings (https://grahamc.com/blog/erase-your-darlings) | |
| # - 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 on and an authorized public ssh key to log in as | |
| # 'root' remotely. The script must also be executed as root. | |
| # | |
| # Example: `sudo ./install.sh sde "ssh-rsa AAAAB..."` | |
| # | |
| 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 | |
| export AUTHORIZED_SSH_KEY=$2 | |
| 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 ! [[ -v AUTHORIZED_SSH_KEY ]]; then | |
| err "Missing argument. Expected public SSH key, e.g. 'ssh-rsa AAAAB...'" | |
| exit 1 | |
| fi | |
| if [[ "$EUID" > 0 ]]; then | |
| err "Must run as root" | |
| exit 1 | |
| fi | |
| export ZFS_POOL="rpool" | |
| # ephemeral datasets | |
| export ZFS_LOCAL="${ZFS_POOL}/local" | |
| export ZFS_DS_ROOT="${ZFS_LOCAL}/root" | |
| export ZFS_DS_NIX="${ZFS_LOCAL}/nix" | |
| # persistent datasets | |
| export ZFS_SAFE="${ZFS_POOL}/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 ..." | |
| parted "$DISK_PATH" -- mklabel gpt | |
| parted "$DISK_PATH" -- mkpart primary 512MiB 100% | |
| parted "$DISK_PATH" -- mkpart ESP fat32 1MiB 512MiB | |
| parted "$DISK_PATH" -- set 2 boot on | |
| export DISK_PART_ROOT="${DISK_PATH}1" | |
| export DISK_PART_BOOT="${DISK_PATH}2" | |
| info "Formatting boot partition ..." | |
| mkfs.fat -F 32 -n boot "$DISK_PART_BOOT" | |
| info "Creating '$ZFS_POOL' ZFS pool for '$DISK_PART_ROOT' ..." | |
| zpool create -f "$ZFS_POOL" "$DISK_PART_ROOT" | |
| info "Enabling compression for '$ZFS_POOL' ZFS pool ..." | |
| zfs set compression=on "$ZFS_POOL" | |
| 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 '$DISK_PART_BOOT' to /mnt/boot ..." | |
| mkdir /mnt/boot | |
| mount "$DISK_PART_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 /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 /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 /mnt/persist | |
| mount -t zfs "$ZFS_DS_PERSIST" /mnt/persist | |
| info "Creating persistent directory for host SSH keys ..." | |
| mkdir -p /mnt/persist/etc/ssh | |
| info "Generating NixOS configuration (/mnt/etc/nixos/*.nix) ..." | |
| nixos-generate-config --root /mnt | |
| info "Enter password for the root user ..." | |
| ROOT_PASSWORD_HASH="$(mkpasswd -m sha-512 | sed 's/\$/\\$/g')" | |
| export NIXOS_CONFIG_PATH=/mnt/etc/nixos/configuration.nix | |
| export NIXOS_CONFIG_BACKUP_PATH="${NIXOS_CONFIG_PATH}.original" | |
| if [[ -f "$NIXOS_CONFIG_BACKUP_PATH" ]]; then | |
| info "Restoring copy of the original NixOS config to '${NIXOS_CONFIG_PATH}' ..." | |
| cp "$NIXOS_CONFIG_BACKUP_PATH" "$NIXOS_CONFIG_PATH" | |
| else | |
| info "Saving a copy of the original '${NIXOS_CONFIG_PATH}' to '${NIXOS_CONFIG_BACKUP_PATH}' ..." | |
| cp "$NIXOS_CONFIG_PATH" "$NIXOS_CONFIG_BACKUP_PATH" | |
| fi | |
| info "Injecting extra configuration into /mnt/etc/nixos/configuration.nix ..." | |
| EXTRA_NIXOS_CONFIG=" | |
| # source: https://grahamc.com/blog/erase-your-darlings | |
| boot.initrd.postDeviceCommands = lib.mkAfter '' | |
| zfs rollback -r ${ZFS_BLANK_SNAPSHOT} | |
| ''; | |
| # source: https://grahamc.com/blog/nixos-on-zfs | |
| boot.kernelParams = [ \"elevator=none\" ]; | |
| networking.hostId = \"$(head -c 8 /etc/machine-id)\"; | |
| users = { | |
| mutableUsers = false; | |
| users.root.initialHashedPassword = \"${ROOT_PASSWORD_HASH}\"; | |
| users.root.openssh.authorizedKeys.keys = [ | |
| \"${AUTHORIZED_SSH_KEY}\" | |
| ]; | |
| }; | |
| services.openssh = { | |
| enable = true; | |
| hostKeys = [ | |
| { | |
| path = \"/persist/etc/ssh/ssh_host_ed25519_key\"; | |
| type = \"ed25519\"; | |
| } | |
| { | |
| path = \"/persist/etc/ssh/ssh_host_rsa_key\"; | |
| type = \"rsa\"; | |
| bits = 4096; | |
| } | |
| ]; | |
| }; | |
| " | |
| nix-shell -p ed --command "ed \"${NIXOS_CONFIG_PATH}\" <<EOF | |
| 16i${EXTRA_NIXOS_CONFIG}. | |
| wq | |
| EOF | |
| " | |
| sed -i "s/{ config, pkgs, ... }:/{ config, pkgs, lib, ... }:/" "$NIXOS_CONFIG_PATH" | |
| info "Installing NixOS to /mnt ..." | |
| nixos-install --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