Skip to content

Instantly share code, notes, and snippets.

@byrongibson
Forked from mx00s/install.sh
Created May 23, 2021 05:06
Show Gist options
  • Save byrongibson/fe8e24d2433d2e082bc238315c0b3483 to your computer and use it in GitHub Desktop.
Save byrongibson/fe8e24d2433d2e082bc238315c0b3483 to your computer and use it in GitHub Desktop.

Revisions

  1. @mx00s mx00s revised this gist May 27, 2020. 1 changed file with 98 additions and 38 deletions.
    136 changes: 98 additions & 38 deletions install.sh
    Original file line number Diff line number Diff line change
    @@ -107,7 +107,7 @@ mount -t zfs "$ZFS_DS_ROOT" /mnt

    info "Mounting '$DISK_PART_BOOT' to /mnt/boot ..."
    mkdir /mnt/boot
    mount "$DISK_PART_BOOT" /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"
    @@ -133,6 +133,10 @@ 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

    @@ -142,60 +146,116 @@ 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"
    info "Enter personal user name ..."
    read USER_NAME

    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 "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;
    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\" ];
    boot.kernelParams = [ "elevator=none" ];
    networking.hostId = \"$(head -c 8 /etc/machine-id)\";
    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}\"
    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;
    hostKeys = [
    {
    path = \"/persist/etc/ssh/ssh_host_ed25519_key\";
    type = \"ed25519\";
    }
    {
    path = \"/persist/etc/ssh/ssh_host_rsa_key\";
    type = \"rsa\";
    bits = 4096;
    }
    ];
    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;
    }
    ];
    };
    "
    nix-shell -p ed --command "ed \"${NIXOS_CONFIG_PATH}\" <<EOF
    16i${EXTRA_NIXOS_CONFIG}.
    wq
    EOF
    "
    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?
    sed -i "s/{ config, pkgs, ... }:/{ config, pkgs, lib, ... }:/" "$NIXOS_CONFIG_PATH"
    }
    EOF

    info "Installing NixOS to /mnt ..."
    nixos-install --no-root-passwd # already prompted for and configured password
    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
  2. @mx00s mx00s created this gist May 24, 2020.
    201 changes: 201 additions & 0 deletions install.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,201 @@
    #!/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