-
-
Save mx00s/ea2462a3fe6fdaa65692fe7ee824de3e to your computer and use it in GitHub Desktop.
| #!/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 -t vfat "$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 "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 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')" | |
| 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 | |
| info "Backing up the this installer script to /persist/etc/nixos/install.sh.original ..." | |
| cp "$0" /mnt/persist/etc/nixos/install.sh.original | |
| info "Writing NixOS configuration to /persist/etc/nixos/ ..." | |
| cat <<EOF > /mnt/persist/etc/nixos/configuration.nix | |
| { config, pkgs, lib, ... }: | |
| { | |
| imports = | |
| [ | |
| ./hardware-configuration.nix | |
| ]; | |
| nix.nixPath = | |
| [ | |
| "nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos" | |
| "nixos-config=/persist/etc/nixos/configuration.nix" | |
| "/nix/var/nix/profiles/per-user/root/channels" | |
| ]; | |
| # Use the systemd-boot EFI boot loader. | |
| boot.loader.systemd-boot.enable = true; | |
| boot.loader.efi.canTouchEfiVariables = true; | |
| # 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)"; | |
| networking.useDHCP = false; | |
| networking.interfaces.enp3s0.useDHCP = true; | |
| environment.systemPackages = with pkgs; | |
| [ | |
| emacs | |
| ]; | |
| services.zfs = { | |
| autoScrub.enable = true; | |
| autoSnapshot.enable = true; | |
| # TODO: autoReplication | |
| }; | |
| services.openssh = { | |
| enable = true; | |
| permitRootLogin = "no"; | |
| passwordAuthentication = false; | |
| hostKeys = | |
| [ | |
| { | |
| path = "/persist/etc/ssh/ssh_host_ed25519_key"; | |
| type = "ed25519"; | |
| } | |
| { | |
| path = "/persist/etc/ssh/ssh_host_rsa_key"; | |
| type = "rsa"; | |
| bits = 4096; | |
| } | |
| ]; | |
| }; | |
| users = { | |
| mutableUsers = false; | |
| users = { | |
| root = { | |
| initialHashedPassword = "${ROOT_PASSWORD_HASH}"; | |
| }; | |
| ${USER_NAME} = { | |
| createHome = true; | |
| initialHashedPassword = "${USER_PASSWORD_HASH}"; | |
| extraGroups = [ "wheel" ]; | |
| group = "users"; | |
| uid = 1000; | |
| home = "/home/${USER_NAME}"; | |
| useDefaultShell = true; | |
| openssh.authorizedKeys.keys = [ "${AUTHORIZED_SSH_KEY}" ]; | |
| }; | |
| }; | |
| }; | |
| # This value determines the NixOS release from which the default | |
| # settings for stateful data, like file locations and database versions | |
| # on your system were taken. It‘s perfectly fine and recommended to leave | |
| # this value at the release version of the first install of this system. | |
| # Before changing this value read the documentation for this option | |
| # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html). | |
| system.stateVersion = "20.03"; # Did you read the comment? | |
| } | |
| 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 |
👍 thanks! I will need to fix this in my blog post ... :)
I started looking into this on my NixOS 20.03 (kernel `5.4.43) and haven't seen any errors like what @cole-h reports.
Mention of the parameter was removed from docs ini rev f97eeb6cf of the kernel and the error message was introduced in f8db3835. I haven't worked out yet how to specify the desired behavior using sysfs/NixOS.
Notably, the only options supported for elevator= according to Documentation/block/switching-sched.rst in the first rev were deadline, noop, and cfq (default). @grahamc, did you perhaps mean to use noop instead of none?
I only saw that message appear in dmesg's output, not journalctl -b -- maybe try looking there? I was using linuxPackages_latest when I posted my earlier comment (which was 5.6.xx at the time).
When I run cat /sys/block/sda/queue/scheduler, I can only see [mq-deadline] kyber none as options -- noop doesn't seem to exist (maybe it's an internal internal setting?). Though I wonder if the docs are outdated, considering mq-deadline and kyber are missing.
I finally figured out how to set the scheduler to none for ZFS partitions using services.udev.extraRules:
Thanks to this Reddit post: https://www.reddit.com/r/zfs/comments/iluh00/zfs_linux_io_scheduler/g3uxm3m/
@mx00s thanks for this script! With NixOS 21.11 you'll need to add isNormalUser = true; to L236.
Most guides seem to also call for -o ashift=12 and -o autotrim=on but I'm no zfs expert.
@mx00s @operator-name @cole-h @grahamc
Does this work because I'm about to try it and don't want any unwelcome surprises.
Thank you, @cole-h. I just saw your comment as I updating this script here.
@grahamc, you may be interested in this too.