diff --git a/README.md b/README.md index 11c5d11..464cb0e 100644 --- a/README.md +++ b/README.md @@ -4,24 +4,11 @@ This repository contains my configuration for my Nixos systems. I don't provide any garantuees that it will work on other systems. In addition some of the scripts required for installation will destroy your data when used. -## Preparation - -On a PC you don't have to do anything special. - -For a Raspberry Pi you need to prepare the SD card first with a UEFI partition. On a PC navigate into this project and run the following commands: - -- `nix-shell` -- `sudo create-uefi-partition.sh` - -This will format the SD card at `/dev/mmcblk0`, create a partition and download and copy all the required files for running UEFI on a Pi 4. - ## Installation -1. Insert an USB stick with the latest NixOS ISO into your device. -1. `curl https://git.2li.ch/Nebucatnetzer/nixos/archive/master.tar.gz | tar xz` -1. `cd nixos && nix-shell setup-shell.nix` -1. For a normal PC run: `sudo ./scripts/format-disk.py` on a Raspberry Pi 4 run: `sudo ./scripts/format-sdcard.py` -1. `sudo nixos-install --no-root-passwd --root /mnt --impure --flake .#SYSTEMNAME` +1. For Raspis it's the easiest if you prepare the SD card/disk on another system. For a PC you can just boot the installation ISO directly. +1. For both devices you can format the disk/card with the following script `sudo ./scripts/format-disk.py`. It will walk you through the formatting process and for a Raspi4 it will prepare it for UEFI setup. +1. Next install the system with `sudo nixos-install --no-root-passwd --root /mnt/nixos --impure --flake .#SYSTEMNAME` When everything is finished you can reboot the system and remove the USB stick. You have now a fully encrypted NixOS system. diff --git a/modules/hardware/raspi4/raspi-base.nix b/modules/hardware/raspi4/raspi-base.nix index af5e8ad..9d268c8 100644 --- a/modules/hardware/raspi4/raspi-base.nix +++ b/modules/hardware/raspi4/raspi-base.nix @@ -65,7 +65,7 @@ in { boot.kernelParams = [ "rootflags=atgc" "rw" ]; fileSystems."/" = { - device = "/dev/disk/by-label/NixosSd"; + device = "/dev/disk/by-label/NIXOSSD"; fsType = "f2fs"; options = [ "atgc,gc_merge" @@ -77,7 +77,7 @@ in { ]; }; fileSystems."/boot" = { - device = "/dev/disk/by-label/SdBoot"; + device = "/dev/disk/by-label/BOOT"; fsType = "vfat"; }; diff --git a/scripts/create-uefi.sh b/scripts/create-uefi.sh deleted file mode 100755 index 4d871e1..0000000 --- a/scripts/create-uefi.sh +++ /dev/null @@ -1,19 +0,0 @@ -#! /usr/bin/env nix-shell -#! nix-shell -i bash -p parted unzip curl - -# Create the boot partition -parted --script /dev/mmcblk0 mklabel gpt -parted --script /dev/mmcblk0 mkpart ESP fat32 0% 1GiB -parted --script /dev/mmcblk0 set 1 esp on -mkfs.fat -F32 -n SdBoot /dev/mmcblk0p1 - -# Download and install the UEFI firmware -mkdir -p /tmp/sdcard/boot -mount /dev/mmcblk0p1 /tmp/sdcard/boot -curl -o /tmp/pi4-uefi.zip -L https://github.com/pftf/RPi4/releases/download/v1.35/RPi4_UEFI_Firmware_v1.35.zip -unzip /tmp/pi4-uefi.zip -d /tmp/sdcard/boot -sync - -# Cleanup -umount /tmp/sdcard/boot -rm /tmp/pi4-uefi.zip diff --git a/scripts/format-disk.py b/scripts/format-disk.py index 7a45c2f..011f543 100755 --- a/scripts/format-disk.py +++ b/scripts/format-disk.py @@ -1,10 +1,15 @@ #! /usr/bin/env nix-shell -#! nix-shell -i python3 -p python3 +#! nix-shell -i python3 -p python3 parted import getpass import os -import subprocess import sys +import subprocess +import zipfile + +from time import sleep + +from urllib.request import urlretrieve def _run_command(command, user_input=""): @@ -56,91 +61,135 @@ def get_disk_to_format(): def create_partition_table(disk): print("Create partition table.") _run_command(["parted", "--script", disk, "mklabel", "gpt"]) + sleep(5) def _partition_suffix(disk): - if "nvmne" in disk: + prefixes = ["nvmne", "mmc"] + if any(prefix in disk for prefix in prefixes): return "p" return "" +def _get_uefi(): + filename = "RPi4_UEFI_Firmware_v1.35.zip" + url = f"https://github.com/pftf/RPi4/releases/download/v1.35/{filename}" + retrieved_file, _ = urlretrieve(url, f"/tmp/{filename}") + return retrieved_file + + +def _extract_uefi(path_to_zip, partition): + with zipfile.ZipFile(path_to_zip, "r") as zip_ref: + zip_ref.extractall(partition) + + +def _create_uefi(): + print("Create UEFI partition.") + filename = _get_uefi() + _extract_uefi(filename, "/mnt/nixos/boot") + + def create_boot_partition(disk): boot_partition = "{}{}1".format(disk, _partition_suffix(disk)) print("Create boot partition {}.".format(boot_partition)) - _run_command( - ["parted", "--script", disk, "mkpart", "ESP", "fat32", "1MiB", "512MiB"] - ) + _run_command(["parted", "--script", disk, "mkpart", "ESP", "fat32", "0%", "1GiB"]) _run_command(["parted", "--script", disk, "set", "1", "esp", "on"]) - _run_command(["mkfs.fat", "-F", "32", "-n", "BOOT", boot_partition]) + _run_command(["mkfs.fat", "-F", "32", "-n", "BOOTTOFRMT", boot_partition]) + sleep(5) def create_main_partition(disk): print("Create main partition.") - _run_command(["parted", "--script", disk, "mkpart", "primary", "512MiB", "100%"]) + _run_command(["parted", "--script", disk, "mkpart", "primary", "1GiB", "100%"]) return "{}{}2".format(disk, _partition_suffix(disk)) -def _create_main_filesystem(): - _run_command(["lvcreate", "-l", "100%FREE", "MainGroup", "-n", "root"]) - _run_command(["mkfs.ext4", "-L", "nixos", "/dev/MainGroup/root"]) +def _create_ext4(): + _run_command(["lvcreate", "-l", "100%FREE", "grouptoformat", "-n", "ROOTTOFRMT"]) + _run_command(["mkfs.ext4", "-L", "ROOTTOFRMT", "/dev/grouptoformat/ROOTTOFRMT"]) + + +def _create_f2fs(): + _run_command(["mkfs.f2fs", "-l", "ROOTTOFRMT", "/dev/mapper/crypttoformat"]) def _create_swap(): memory = _get_system_memory() print("Create swap partition of {} GiB in size".format(memory)) - _run_command(["lvcreate", "-L", "{}G".format(memory), "MainGroup", "-n", "swap"]) - _run_command(["mkswap", "-L", "swap", "/dev/MainGroup/swap"]) + _run_command( + ["lvcreate", "-L", "{}G".format(memory), "grouptoformat", "-n", "SWAPTOFRMT"] + ) + _run_command(["mkswap", "-L", "SWAPTOFRMT", "/dev/grouptoformat/SWAPTOFRMT"]) def _encrypt_disk(partition_path): password = getpass.getpass() print("Encrypting disk.") _run_command( - ["cryptsetup", "luksFormat", "-q", "--type", "luks1", partition_path], + ["cryptsetup", "luksFormat", "-q", partition_path], user_input=password, ) _run_command( - ["cryptsetup", "open", partition_path, "cryptlvm"], user_input=password + ["cryptsetup", "open", partition_path, "crypttoformat"], user_input=password ) + return "/dev/mapper/crypttoformat" def _setup_lvm(lvm_target): print("Set up LVM on {}.".format(lvm_target)) _run_command(["pvcreate", lvm_target]) - _run_command(["vgcreate", "MainGroup", lvm_target]) + _run_command(["vgcreate", "grouptoformat", lvm_target]) -def mount_partitions(): +def mount_partitions( + root_src="/dev/disk/by-label/ROOTTOFRMT", + boot_src="/dev/disk/by-label/BOOTTOFRMT", + root_target="/mnt/nixos", + boot_target="/mnt/nixos/boot", +): print("Mounting partitions.") - _run_command(["mount", "/dev/MainGroup/root", "/mnt"]) - os.mkdir("/mnt/boot") - _run_command(["mount", "/dev/disk/by-label/BOOT", "/mnt/boot"]) + sleep(5) + os.makedirs(root_target, exist_ok=True) + _run_command(["mount", root_src, root_target]) + os.makedirs(boot_target, exist_ok=True) + _run_command(["mount", boot_src, boot_target]) -def create_file_systems(partition, swap, encryption): +def create_pc(partition, swap, encryption): print("Creating filesystems.") if encryption: - lvm_target = "/dev/mapper/cryptlvm" + lvm_target = "/dev/mapper/crypttoformat" _encrypt_disk(partition) else: lvm_target = partition _setup_lvm(lvm_target) if swap: _create_swap() - _create_main_filesystem() + _create_ext4() + + +def create_raspi(main_partition): + print("Create filesystems.") + _encrypt_disk(main_partition) + _create_f2fs() + mount_partitions() + _create_uefi() def main(): disks = read_disks() create_menu(disks) disk_to_format = disks[get_disk_to_format()] - swap = _y_n("Do you need swap?") - encryption = _y_n("Do you want to encrypt your data?") + raspi = _y_n("Do you want to setup a Raspi?") create_partition_table(disk_to_format) create_boot_partition(disk_to_format) main_partition = create_main_partition(disk_to_format) - create_file_systems(main_partition, swap, encryption) - mount_partitions() + if raspi: + create_raspi(main_partition) + else: + swap = _y_n("Do you need swap?") + encryption = _y_n("Do you need encryption?") + create_pc(main_partition, swap, encryption) if __name__ == "__main__": diff --git a/scripts/format-sdcard.py b/scripts/format-sdcard.py deleted file mode 100755 index 49630b3..0000000 --- a/scripts/format-sdcard.py +++ /dev/null @@ -1,97 +0,0 @@ -#! /usr/bin/env nix-shell -#! nix-shell -i python3 -p python3 parted - -import getpass -import os -import subprocess - - -def _run_command(command, user_input=""): - if user_input: - result = subprocess.run( - command, capture_output=True, text=True, check=True, input=user_input - ) - else: - result = subprocess.run(command, capture_output=True, text=True, check=True) - return result - - -def _partition_suffix(disk): - if ("nvmne" or "mmc") in disk: - return "p" - return "" - - -def read_disks(): - output = _run_command(["lsblk", "-dpno", "name"]) - disks = [] - for disk in output.stdout.splitlines(): - if "loop" in disk: - continue - disks.append(disk) - return disks - - -def create_menu(disks): - for position, disk in enumerate(disks): - print("{}: {}".format(position, disk)) - - -def get_disk_to_format(): - disk_to_format = input("Which disk dou you want to format?: ") - return int(disk_to_format) - - -def create_main_partition(disk): - print("Create main partition.") - _run_command(["parted", "--script", disk, "mkpart", "primary", "1GiB", "100%"]) - return f"{disk}{_partition_suffix(disk)}2" - - -def _create_main_filesystem(): - _run_command( - [ - "mkfs.f2fs", - "-l", - "NixosSd", - "-O", - "extra_attr,inode_checksum,sb_checksum,compression", - "/dev/mapper/cryptsd", - ] - ) - - -def _encrypt_disk(partition_path): - password = getpass.getpass() - print("Encrypting disk.") - _run_command( - ["cryptsetup", "luksFormat", "-q", partition_path], - user_input=password, - ) - _run_command(["cryptsetup", "open", partition_path, "cryptsd"], user_input=password) - - -def create_file_systems(partition): - print("Creating filesystems.") - _encrypt_disk(partition) - _create_main_filesystem() - - -def mount_partitions(): - print("Mounting partitions.") - _run_command(["mount", "/dev/disk/by-label/NixosSd", "/mnt"]) - os.mkdir("/mnt/boot") - _run_command(["mount", "/dev/disk/by-label/SdBoot", "/mnt/boot"]) - - -def main(): - disks = read_disks() - create_menu(disks) - disk_to_format = disks[get_disk_to_format()] - main_partition = create_main_partition(disk_to_format) - create_file_systems(main_partition) - mount_partitions() - - -if __name__ == "__main__": - main() diff --git a/scripts/rename-partitions.py b/scripts/rename-partitions.py new file mode 100755 index 0000000..560ade2 --- /dev/null +++ b/scripts/rename-partitions.py @@ -0,0 +1,91 @@ +#! /usr/bin/env nix-shell +#! nix-shell -i python3 -p python3 parted + +import subprocess +import sys +from time import sleep + + +def _run_command(command, user_input=""): + if user_input: + result = subprocess.run( + command, capture_output=True, text=True, check=True, input=user_input + ) + else: + result = subprocess.run(command, capture_output=True, text=True, check=True) + return result + + +def _y_n(question): + answer = input("{} (Y/N): ".format(question)) + if answer.lower() == "y": + return True + if answer.lower() == "n": + return False + print("Please only answer with Y or N!") + sys.exit(1) + + +def rename_boot_partition(): + print("Rename boot partition.") + _run_command(["fatlabel", "/dev/disk/by-label/BOOTTOFRMT", "BOOT"]) + + +def _rename_ext4(): + print("Rename ext4 partition.") + _run_command(["e2label", "/dev/MainGroup/roottoformat", "root"]) + + +def _rename_f2fs(): + print("Rename f2fs partition.") + _run_command(["f2fslabel", "/dev/disk/by-label/ROOTTOFRMT", "root"]) + + +def _rename_swap(): + print("Rename swap partition.") + _run_command(["swaplabel", "-L", "swap", "/dev/GroupToFormat/swaptoformat"]) + + +def _rename_lvm(): + print("Rename LVM") + _run_command(["lvrename", "GroupToFormat", "roottoformat", "root"]) + _run_command(["vgrename", "GroupToFormat", "MainGroup"]) + + +def unmount_partitions(): + print("Unmounting partitions.") + _run_command(["umount", "/mnt/nixos/boot"]) + _run_command(["umount", "/mnt/nixos"]) + sleep(3) + + +def close_luks(): + _run_command(["cryptsetup", "close", "crypttoformat"]) + + +def rename_pc(swap): + if swap: + _rename_swap() + _rename_ext4() + _rename_lvm() + + +def rename_raspi(): + _rename_f2fs() + + +def main(): + raspi = _y_n("Do we rename a Raspberry Pi?") + unmount_partitions() + sleep(5) + rename_boot_partition() + if raspi: + rename_raspi() + else: + swap = _y_n("Do you have swap?") + rename_pc(swap) + close_luks() + + +if __name__ == "__main__": + main()