├── LICENSE ├── README.md ├── hosts └── vm-example │ ├── configuration.sh │ └── default.nix ├── themelios └── themelios_usage.png /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Adam Schaefers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Themelios - NixOS on a rock-solid ZFS foundation. 2 | Bootstrap a zfs-on-root NixOS configuration in one command. 3 | 4 | ![Themelios NixOS Screenshot](https://github.com/a-schaefers/themelios/raw/master/themelios_usage.png) 5 | 6 | ## From any NixOS live disk, Themelios 7 | - Automatically installs zfs and git to the livedisk if needed. 8 | - Clones your git repo, optionally using a non-master branch. 9 | - Finds your configuration.sh file automatically. 10 | - Configures a basic ZFS system according to your configuration.sh file specification: 11 | * Use sgdisk and/or wipefs, or dd to clear your disks. 12 | * Create a single/mirror/raidz1/raidz2/raidz3 zpool. 13 | * Install a bootloader to each disk in the pool. 14 | * Creates generate and import /etc/nixos/zfs-configuration.nix which includes sensible settings for zfs-on-root. 15 | * Optionally enable "zfs-extra" for further zfs-support options. 16 | - Generates an /etc/nixos/configuration.nix which imports your top-level-nixfile from your repo-- (and thereby nixos-install's the rest of your operating system.) 17 | - Aims to fail gracefully with continue and retry options. 18 | - **Legacy** *and* **UEFI** are now both supported. 19 | - **ZFS native-encryption is now an option in configuration.sh** 20 | 21 | ## NEWS 22 | ### Themelios 2.0 Features: 23 | - 300 lines of code removed [cleaned / simplified] with fewer configuration variables... 24 | 25 | - Native ZFS encryption is an official option. 26 | 27 | To use zfs encryption, you will need a nixos installation ISO that includes ZFS version 0.8 or higher. There is information how to build such an ISO at the bottom of this README.md page. 28 | 29 | - Identical GRUB and partioning schemes are now used for both UEFI and LEGACY. 30 | 31 | - For legacy users, /boot is kept in sync across multiple disks. For this reason, legacy BIOS is still recommended [for computers that support it] > UEFI. Simply put: legacy is more robust than UEFI. 32 | 33 | ## Try it in it a VM right now! 34 | - From a NixOS LiveDisk VM, 35 | ```bash 36 | [root@nixos:~] bash <(curl https://raw.githubusercontent.com/a-schaefers/themelios/master/themelios) vm-example a-schaefers/themelios 37 | ``` 38 | This command executes the script with curl and bash, which in turn downloads the a-schaefers/themelios repo from github, finds the "vm-example" directory with a configuration.sh file and begins the bootstrap process. 39 | 40 | ## "configuration.sh" [so-called] 41 | Configuration.sh may actually be named anything you want and located anywhere in your project, Themelios will search for $1 by filename first and find it automatically, provided it is a uniquely named file. 42 | 43 | If the filename isn't found, then Themelios will search for directories by the same name. So if you prefer using a standard naming convention, put a literal "configuration.sh" file inside of a uniquely named directory and feed Themelios the unique directory name. 44 | The example "Try it init a VM right now!" command of this repository uses this method: 45 | ```bash 46 | # vm-example is not a file inside this repo, but is a directory-- so this finds the dir hosts/vm-example/ and loads thel literal "configuration.sh" file. 47 | [root@nixos:~] themelios vm-example a-schaefers/themelios 48 | ``` 49 | 50 | If none of this works for you, just tell themelios where the file is relative to project root: 51 | ```bash 52 | [root@nixos:~] themelios ./hosts/vm-example/configuration.sh https://github.com/a-schaefers/themelios.git master 53 | ``` 54 | 55 | _NOTE: The username/repo-name shortcut only works for Github repos. Non-Github repos must provide the full remote._ 56 | 57 | **TL;DR. Feed Themelios a git repository url that contains a [configuration.sh](https://github.com/a-schaefers/themelios/blob/testing/example_configuration.sh) file:** 58 | 59 | ## [non-]Issues 60 | 61 | ### fetchTarball currently does not work ... 62 | While Themelios aims to fail gracefully, if the initial bootstrap fails and if there is not an error in your nix files, one commonly known cause of failure is use of fetchTarball. Using fetchTarball does not work during new NixOS installations. This is not Themelios' fault! Here's the NixOS bug that is already reported: https://github.com/NixOS/nix/issues/2405 63 | 64 | ### home-manager: a common source of bootstrap fails 65 | At present, if the bootstrap fails due to home-manager, I comment out home-manager section of my configuration in /mnt during the initial bootstrap. Once rebooted, (and so out of the chroot), then I uncomment it and nixos-rebuild switch again. 66 | 67 | ## Tips & Tricks 68 | 69 | ### Build Themelios into a custom NixOS rescue iso 70 | Save the following somewhere on an already existing NixOS install as iso.nix: 71 | 72 | ```nix 73 | {config, pkgs, ...}: 74 | let 75 | themelios = pkgs.writeScriptBin "themelios" '' 76 | bash <(curl https://raw.githubusercontent.com/a-schaefers/themelios/master/themelios) $@ 77 | ''; 78 | in { 79 | imports = [ 80 | 81 | 82 | ]; 83 | networking = { 84 | networkmanager.enable = true; 85 | wireless.enable = false; #networkmanager.enable handles this 86 | }; 87 | boot.supportedFilesystems = [ "zfs" ]; 88 | environment.systemPackages = with pkgs; [ git themelios ]; 89 | 90 | # uncomment below if you need 0.8 encryption 91 | # boot.zfs.enableUnstable = true; 92 | } 93 | ``` 94 | And build it! 95 | ```bash 96 | nix-build '' -A config.system.build.isoImage -I nixos-config=iso.nix 97 | ``` 98 | -------------------------------------------------------------------------------- /hosts/vm-example/configuration.sh: -------------------------------------------------------------------------------- 1 | # Themelios configuration.sh example 2 | 3 | use_sgdisk_clear="true" # use sgdisk --clear 4 | use_wipefs_all="true" # use wipefs --all 5 | use_zero_disks="false" # use dd if=/dev/zero ... 6 | install_arguments="" # any extra arguments to nixos-install, like --no-root-passwd 7 | zfs_pool_name="rpool" 8 | zfs_pool_disks=("/dev/sda") # Note: using /dev/disk/by-id is also preferable. 9 | zfs_pool_type="" # use "" for single, or "mirror", "raidz1", etc. 10 | zfs_encrypt_home="false" # only set to true if you are using a nixos ISO with ZFS 0.8 or higher. 11 | zfs_auto_snapshot=("$zfs_pool_name/HOME" "$zfs_pool_name/ROOT") # datasets to be set with com.sun:auto-snapshot=true 12 | nix_top_level_configuration="hosts/vm-example" # Your top-level nix file to be bootstrapped 13 | nix_zfs_configuration_extra_enabled="false" # uncomment below if set to true 14 | # nix_zfs_extra_auto_scrub="true" 15 | # nix_zfs_extra_auto_snapshot_enabled="true" # Enable the ZFS auto-snapshotting service 16 | # nix_zfs_extra_auto_snapshot_frequent="8" 17 | # nix_zfs_extra_auto_snapshot_hourly="24" 18 | # nix_zfs_extra_auto_snapshot_daily="0" 19 | # nix_zfs_extra_auto_snapshot_weekly="0" 20 | # nix_zfs_extra_auto_snapshot_monthly="0" 21 | # nix_zfs_extra_auto_optimise_store="true" 22 | # nix_zfs_extra_gc_automatic="true" 23 | # nix_zfs_extra_gc_dates="weekly" 24 | # nix_zfs_extra_gc_options="--delete-older-than 7d" 25 | # nix_zfs_extra_clean_tmp_dir="true" 26 | -------------------------------------------------------------------------------- /hosts/vm-example/default.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, ... }: 2 | # just an example top-level "configuration.nix" file within the themelios scheme 3 | { 4 | imports = []; 5 | 6 | i18n = { 7 | consoleFont = "Lat2-Terminus16"; 8 | consoleKeyMap = "us"; 9 | defaultLocale = "en_US.UTF-8"; 10 | }; 11 | 12 | time.timeZone = "America/Los_Angeles"; 13 | 14 | programs.mtr.enable = true; 15 | programs.bash.enableCompletion = true; 16 | 17 | networking.hostName = "themelios-vm"; 18 | } 19 | -------------------------------------------------------------------------------- /themelios: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # MIT License 3 | 4 | # Copyright 2018 Adam Schaefers paxchristi888@gmail.com 5 | 6 | # Permission is hereby granted, free of charge, to any person obtaining a copy 7 | # of this software and associated documentation files (the "Software"), to deal 8 | # in the Software without restriction, including without limitation the rights 9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | # copies of the Software, and to permit persons to whom the Software is 11 | # furnished to do so, subject to the following conditions: 12 | 13 | # The above copyright notice and this permission notice shall be included in all 14 | # copies or substantial portions of the Software. 15 | 16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | # SOFTWARE. 23 | 24 | usage() { 25 | cat << EOF 26 | usage: 27 | themelios configuration.sh git-remote [branch] 28 | 29 | for detailed examples and instructions please visit the github page: 30 | 31 | https://github.com/a-schaefers/themelios 32 | 33 | EOF 34 | exit 35 | } 36 | 37 | die() { 38 | [ $# -gt 0 ] && printf -- "%s\n" "$*" 39 | exit 1 40 | } 41 | 42 | initial_warning() { 43 | echo "WARNING: The following script intends to replace all of your disk(s) \ 44 | contents with a zfs-on-root NixOS installation and bootstrap your configuration.nix." 45 | 46 | read -p "Ready? (Y or N) " -n 1 -r 47 | [[ ! $REPLY =~ ^[Yy]$ ]] && die "Aborted." 48 | } 49 | 50 | uefi_or_legacy() { 51 | [[ -d "/sys/firmware/efi/efivars" ]] && uefi_install="1" 52 | } 53 | 54 | bootstrap_zfs() { 55 | sed -i '/imports/a boot.supportedFilesystems = [ \"zfs\" ];' \ 56 | /etc/nixos/configuration.nix 57 | nixos-rebuild switch 58 | } 59 | 60 | bootstrap_git() { 61 | sed -i '/imports/a environment.systemPackages = with pkgs; [ git ];' \ 62 | /etc/nixos/configuration.nix 63 | nixos-rebuild switch 64 | } 65 | 66 | get_custom_nixcfg() { 67 | # clone the declared repo from git_remote ($2) 68 | # optional git_branch ($3) may be used additionally for all users who need to build from a non-master branch. 69 | # github users' https remote will be switched to ssh remote automatically after initial clone. 70 | # github users also may use the "shorthand" username/repo-name 71 | github_shorthand="$(echo "$git_remote" | grep -v ".git")" 72 | github_url="$(echo "$git_remote" | grep "github.com")" 73 | 74 | checkout_branch() { 75 | echo "checking out $github_sshremote" 76 | cd /tmp/cloned_remote || die 77 | git checkout "$git_branch" 78 | } 79 | 80 | switch_github_remotes() { 81 | echo "switching remote from https to $github_sshremote for user convenience..." 82 | cd /tmp/cloned_remote || die 83 | git remote set-url origin "$github_sshremote" 84 | } 85 | 86 | github_clone_and_switch() { 87 | echo "cloning repo via $github_httpsremote" 88 | github_httpsremote="https://github.com/$github_user/$github_repo" 89 | github_sshremote="git@github.com:$github_user/$github_repo" 90 | git clone "$github_httpsremote" /tmp/cloned_remote || die "1 git_clone_and_switch git clone failed" 91 | switch_github_remotes 92 | [[ $git_branch ]] && checkout_branch 93 | } 94 | 95 | if [[ $github_url ]] 96 | then 97 | github_user="$(echo "$git_remote" | grep github | cut -d '/' -f 4)" 98 | github_repo="$(echo "$git_remote" | grep github | cut -d '/' -f 5)" 99 | github_clone_and_switch 100 | 101 | elif [[ $github_shorthand ]] 102 | then 103 | github_user="$(echo "$git_remote" | cut -d '/' -f 1)" 104 | github_repo="$(echo "$git_remote" | cut -d '/' -f 2)" 105 | github_clone_and_switch 106 | 107 | else 108 | echo "cloning repo via $git_remote" 109 | git clone "$git_remote" /tmp/cloned_remote || die "2 git_clone_and_switch git clone failed" 110 | [[ $git_branch ]] && checkout_branch 111 | fi 112 | 113 | find_configuration_sh() { 114 | # first we simply use "./the/path/to/$1" if the user provides it. 115 | # second if $1 has no slashes, then we search for $1 guessing it maybe a unique filename in the project. 116 | # third we search again for a unique dirname, but only if the filename search turns up nothing, 117 | # then we append the literal "/configuration.sh" convention to the unique dirname, making assumption it must be this. 118 | cd /tmp/cloned_remote || die 119 | find . -type f -name "$config_dot_sh" | grep "." && \ 120 | config_dot_sh="$(find . -type f -name "$config_dot_sh")" && \ 121 | [ ! -e "$config_dot_sh" ] && die "themelios cannot figure out which $config_dot_sh to use." 122 | find . -type d -name "$config_dot_sh" | grep "." && \ 123 | config_dot_sh="$(find . -type d -name "$config_dot_sh")/configuration.sh" 124 | } 125 | echo "$config_dot_sh" | grep "/" || find_configuration_sh 126 | 127 | source "$config_dot_sh" || die "$config_dot_sh file not found." 128 | } 129 | 130 | disk_prep() { 131 | # some initial translation for whether or not the script was provided disks with sd* or /dev/disk/by-id/*, etc. 132 | echo "${zfs_pool_disks[0]}" | grep -q "/dev/sd" && use_sdX="1" 133 | echo "${zfs_pool_disks[0]}" | grep -q "/dev/nvme" && use_nvme="1" 134 | if [[ $use_sdX ]] 135 | then 136 | boot_part="2" 137 | zpool_partition="3" 138 | elif [[ $use_nvme ]] # fixes https://github.com/a-schaefers/themelios/issues/2 139 | then 140 | boot_part="p2" 141 | zpool_partition="p3" 142 | else 143 | boot_part="-part2" 144 | zpool_partition="-part3" 145 | fi 146 | 147 | sgdisk_clear() { 148 | for disk_id in "${zfs_pool_disks[@]}" 149 | do 150 | echo "clearing disk with sgdisk..." 151 | sgdisk --zap-all "$disk_id" || die "sgdisk_clear failed" 152 | done 153 | } 154 | [[ $use_sgdisk_clear == "true" ]] && sgdisk_clear 155 | 156 | wipefs_all() { 157 | for disk_id in "${zfs_pool_disks[@]}" 158 | do 159 | echo "wiping disk signatures with wipefs..." 160 | wipefs -fa "$disk_id" || die "wipefs_all failed" 161 | done 162 | } 163 | [[ $use_wipefs_all == "true" ]] && wipefs_all 164 | 165 | dd_zero() { 166 | for disk_id in "${zfs_pool_disks[@]}" 167 | do 168 | echo "writing zeros to ${disk_id}..." 169 | dd if=/dev/zero of="$disk_id" bs=1M oflag=direct status=progress & 170 | done 171 | wait 172 | } 173 | [[ $use_zero_disks == "true" ]] && dd_zero 174 | } 175 | 176 | zpool_create() { 177 | echo "creating zpool..." 178 | 179 | cat << EOF 180 | zpool create -f \ 181 | -o ashift=12 \ 182 | -O compression=lz4 \ 183 | -O atime=on \ 184 | -O relatime=on \ 185 | -O normalization=formD \ 186 | -O xattr=sa \ 187 | -m none \ 188 | -R /mnt \ 189 | $zfs_pool_name \ 190 | $zfs_pool_type \ 191 | ${zfs_pool_disks[@]/%/$zpool_partition} || die "zpool_create failed" 192 | EOF 193 | zpool create -f \ 194 | -o ashift=12 \ 195 | -O compression=lz4 \ 196 | -O atime=on \ 197 | -O relatime=on \ 198 | -O normalization=formD \ 199 | -O xattr=sa \ 200 | -m none \ 201 | -R /mnt \ 202 | $zfs_pool_name \ 203 | $zfs_pool_type \ 204 | ${zfs_pool_disks[@]/%/$zpool_partition} || die "zpool_create failed" 205 | 206 | # https://github.com/NixOS/nixpkgs/issues/16954 207 | zfs set acltype=posixacl "$zfs_pool_name" 208 | } 209 | 210 | disk_part() { 211 | for disk_id in "${zfs_pool_disks[@]}" 212 | do 213 | sgdisk -og "$disk_id" 214 | echo "making bios boot partition..." 215 | sgdisk -a 1 -n 1:48:2047 -t 1:ef02 -c 1:"BIOS Boot Partition" "$disk_id" || die "disk_part failed" 216 | partx -u "$disk_id" 217 | echo "making 1G /boot fat32 ESP..." 218 | sgdisk -n 2:4096:2101247 -c 2:"Fat32 ESP Partition" -t 2:ef00 "$disk_id" || die "disk_part failed" 219 | partx -u "$disk_id" 220 | echo "making zpool partition with remainder of space..." 221 | sgdisk -n 3:2101248:"$(sgdisk -E "$disk_id")" -c 3:"ZPOOL Partition" -t 3:8300 "$disk_id" || die "disk_part failed" 222 | sgdisk -p "$disk_id" || die "disk_part failed" 223 | partx -u "$disk_id" 224 | sleep 5 # workaround weird issue where Linux still needs some time after partx to resolve disk path 225 | done 226 | sleep 10 # workaround weird issue where Linux still needs some time after partx to resolve disk path 227 | } 228 | 229 | mount_boots() { 230 | sleep 10 # workaround weird issue where Linux needs some time after partioning and before mkfs.vfat 231 | bootnum="" 232 | for disk_id in "${zfs_pool_disks[@]}" 233 | do 234 | mkfs.vfat -F32 "${disk_id}${boot_part}" || die "mount_boots mkfs.vfat failed" 235 | mkdir -p "/mnt/boot${bootnum}" 236 | mount "${disk_id}${boot_part}" "/mnt/boot${bootnum}" 237 | ((bootnum++)) 238 | done 239 | } 240 | 241 | mount_create_datasets() { 242 | echo "Creating and mounting datasets in /mnt..." 243 | # / (root) datasets 244 | zfs create -o mountpoint=none -o canmount=off "$zfs_pool_name/ROOT" 245 | zfs create -o mountpoint=legacy -o canmount=on "$zfs_pool_name/ROOT/nixos" 246 | mount -t zfs "$zfs_pool_name/ROOT/nixos" /mnt 247 | zpool set bootfs="$zfs_pool_name/ROOT/nixos" "$zfs_pool_name" 248 | 249 | # 1G fat32 /boot(X) ESP 250 | mount_boots 251 | 252 | # mount /nix outside of the root dataset 253 | zfs create -o mountpoint=none -o canmount=off "$zfs_pool_name/NIX" 254 | zfs create -o mountpoint=legacy -o canmount=on "$zfs_pool_name/NIX/nix" 255 | mkdir /mnt/nix 256 | mount -t zfs "$zfs_pool_name/NIX/nix" /mnt/nix 257 | 258 | mkdir -p /mnt/{home,tmp} 259 | 260 | # /home datasets 261 | zfs create -o mountpoint=none -o canmount=off "$zfs_pool_name/HOME" 262 | if [ "$zfs_encrypt_home" = "true" ]; then 263 | crypthome() { 264 | zfs create -o mountpoint=legacy -o encryption=on -o keyformat=passphrase "$zfs_pool_name/HOME/home" || crypthome 265 | } 266 | crypthome 267 | else 268 | zfs create -o mountpoint=legacy -o canmount=on "$zfs_pool_name/HOME/home" 269 | fi 270 | mount -t zfs "$zfs_pool_name/HOME/home" /mnt/home 271 | 272 | # /tmp datasets 273 | zfs create -o mountpoint=none -o canmount=off "$zfs_pool_name/TMP" 274 | zfs create -o mountpoint=legacy -o canmount=on -o sync=disabled "$zfs_pool_name/TMP/tmp" 275 | mount -t zfs "$zfs_pool_name/TMP/tmp" /mnt/tmp 276 | chmod 1777 /mnt/tmp 277 | 278 | zfs_auto_snapshot() { 279 | for dataset in "${zfs_auto_snapshot[@]}" 280 | do 281 | echo "Setting property com.sun:auto-snapshot=true to ${dataset}..." 282 | zfs set com.sun:auto-snapshot=true "$dataset" 283 | done 284 | } 285 | zfs_auto_snapshot 286 | } 287 | 288 | bootstrap_nixcfg() { 289 | echo "moving repo from /tmp to /mnt/nix-config..." 290 | cp -a /tmp/cloned_remote "/mnt/nix-config" 291 | 292 | # this is for generating our ./hardware-configuration.nix files. 293 | # ./configuration.nix will be overwritten shortly hereafter. 294 | echo "executing nixos-generate-config --root /mnt" 295 | nixos-generate-config --root /mnt || die "nixos-generate-config --root /mnt failed" 296 | 297 | echo "generating random hostid..." 298 | zfs_host_id="$(head -c4 /dev/urandom | od -A none -t x4 | cut -d ' ' -f 2)" 299 | echo "$zfs_host_id" 300 | 301 | # strip potential prefixed './' 302 | nix_top_level_configuration="$(echo "$nix_top_level_configuration" | sed 's|^./||')" 303 | # strip potential trailing '/' 304 | nix_top_level_configuration="${nix_top_level_configuration%/}" 305 | 306 | # create /mnt/etc/nixos/configuration.nix and import user's top_level_nixfile. 307 | cat << EOF > /mnt/etc/nixos/configuration.nix 308 | { ... }: 309 | { imports = [ 310 | ../../nix-config/$nix_top_level_configuration 311 | ./hardware-configuration.nix 312 | ./zfs-configuration.nix 313 | ]; 314 | } 315 | EOF 316 | 317 | # create /mnt/etc/nixos/zfs-configuration.nix 318 | cat << EOF > /mnt/etc/nixos/zfs-configuration.nix 319 | { ... }: 320 | { imports = []; 321 | boot.supportedFilesystems = [ "zfs" ]; 322 | boot.loader = { 323 | 324 | $(if [[ $uefi_install ]]; then # reinstall in legacy mode, it's better. :P 325 | cat <<- UEFI 326 | efi = { 327 | canTouchEfiVariables = true; 328 | efiSysMountPoint = "/boot"; # use the same mount point here. 329 | }; 330 | UEFI 331 | fi) 332 | 333 | grub = { 334 | enable = true; 335 | version = 2; 336 | copyKernels = true; 337 | 338 | $(if [[ $uefi_install ]]; then 339 | cat <<- UEFI 340 | efiSupport = true; 341 | UEFI 342 | fi) 343 | 344 | $(if [ ${#zfs_pool_disks[@]} -gt 1 ] 345 | then 346 | cat <<- MIRROREDBOOTS 347 | mirroredBoots = [ 348 | $(bootnum="" 349 | for disk_id in "${zfs_pool_disks[@]}" 350 | do 351 | echo "{devices = [ \"${disk_id}\" ]; path = \"/boot${bootnum}\";}" 352 | ((bootnum++)) 353 | done) 354 | ]; 355 | MIRROREDBOOTS 356 | 357 | else 358 | 359 | cat <<- SINGLEBOOT 360 | devices = [ 361 | $(for disk_id in "${zfs_pool_disks[@]}" 362 | do 363 | echo "\"$disk_id\"" 364 | done) 365 | ]; 366 | SINGLEBOOT 367 | fi) 368 | 369 | }; 370 | }; 371 | 372 | # The 32-bit host id of the machine, formatted as 8 hexadecimal characters. 373 | # You should try to make this id unique among your machines. 374 | networking.hostId = "$zfs_host_id"; 375 | 376 | # noop, the recommended elevator with zfs. 377 | # shell_on_fail allows to force import manually in the case of zfs import failure. 378 | boot.kernelParams = [ "elevator=noop" "boot.shell_on_fail" ]; 379 | 380 | # Uncomment [on a working system] to ensure extra safeguards are active that zfs uses to protect zfs pools: 381 | #boot.zfs.forceImportAll = false; 382 | #boot.zfs.forceImportRoot = false; 383 | 384 | $([[ $zfs_encrypt_home == "true" ]] && cat <<- HOMECRYPT 385 | boot.zfs.enableUnstable = true; 386 | boot.zfs.requestEncryptionCredentials = true; 387 | HOMECRYPT 388 | ) 389 | 390 | $([[ $nix_zfs_configuration_extra_enabled == "true" ]] && cat <<- EXTRA 391 | # Enables periodic scrubbing of ZFS pools. 392 | services.zfs.autoScrub.enable = $nix_zfs_extra_auto_scrub; 393 | 394 | # Enable the (OpenSolaris-compatible) ZFS auto-snapshotting service. 395 | services.zfs.autoSnapshot = { 396 | enable = $nix_zfs_extra_auto_snapshot_enabled; 397 | frequent = $nix_zfs_extra_auto_snapshot_frequent; 398 | hourly = $nix_zfs_extra_auto_snapshot_hourly; 399 | daily = $nix_zfs_extra_auto_snapshot_daily; 400 | weekly = $nix_zfs_extra_auto_snapshot_weekly; 401 | monthly = $nix_zfs_extra_auto_snapshot_monthly; 402 | }; 403 | 404 | # Use gc.automatic to keep disk space under control. 405 | nix.autoOptimiseStore = $nix_zfs_extra_auto_optimise_store; 406 | nix.gc.automatic = $nix_zfs_extra_gc_automatic; 407 | nix.gc.dates = "$nix_zfs_extra_gc_dates"; 408 | nix.gc.options = "$nix_zfs_extra_gc_options"; 409 | 410 | # Clean /tmp automatically on boot. 411 | boot.cleanTmpDir = $nix_zfs_extra_clean_tmp_dir; 412 | EXTRA 413 | ) 414 | } 415 | EOF 416 | 417 | # give user a retry option with --show-trace to have a chance to fix imports on another tty. :) 418 | nixos-install-show-trace() { 419 | nixos-install $install_arguments --show-trace || nixos-install_fail_retry 420 | } 421 | 422 | nixos-install_fail_retry() { 423 | echo "themelios hint: check /mnt/etc/nixos/configuration.nix and your other files in /mnt/nix-config before trying again." 424 | echo "themelios hint: make sure you are using relative path imports for all of your .nix files." 425 | read -p "nixos-install failed, retry? will add --show-trace (y or n) " -n 1 -r 426 | if [[ $REPLY =~ ^[Yy]$ ]] 427 | then 428 | nixos-install-show-trace 429 | else 430 | die "the only steps remaining after nixos-install should be unmounting /mnt and exporting the pool :) good luck." 431 | fi 432 | } 433 | 434 | install() { 435 | echo "executing nixos-install" 436 | nixos-install $install_arguments || nixos-install_fail_retry 437 | } 438 | 439 | install 440 | } 441 | 442 | installation_complete() { 443 | cat << EOF 444 | nnnnnnnn nnnnnnnniiiiiiiiiixxxxxxx xxxxxxx 445 | n:::::::n n::::::ni::::::::ix:::::x x:::::x 446 | n::::::::n n::::::ni::::::::ix:::::x x:::::x 447 | n:::::::::n n::::::nii::::::iix::::::x x::::::x 448 | n::::::::::n n::::::n i::::i xxx:::::x x:::::xxx 449 | n:::::::::::n n::::::n i::::i x:::::x x:::::x 450 | n:::::::n::::n n::::::n i::::i x:::::x:::::x 451 | n::::::n n::::n n::::::n i::::i x:::::::::x 452 | n::::::n n::::n:::::::n i::::i x:::::::::x 453 | n::::::n n:::::::::::n i::::i x:::::x:::::x 454 | n::::::n n::::::::::n i::::i x:::::x x:::::x 455 | n::::::n n:::::::::n i::::i xxx:::::x x:::::xxx 456 | n::::::n n::::::::nii::::::iix::::::x x::::::x 457 | n::::::n n:::::::ni::::::::ix:::::x x:::::x 458 | n::::::n n::::::ni::::::::ix:::::x x:::::x 459 | nnnnnnnn nnnnnnniiiiiiiiiixxxxxxx xxxxxxx 460 | EOF 461 | 462 | echo "unmounting /mnt" 463 | umount -lR /mnt 464 | 465 | echo "exporting $zfs_pool_name" 466 | zpool export "$zfs_pool_name" 467 | 468 | read -p "finished. reboot now? (y or n) " -n 1 -r 469 | [[ $REPLY =~ ^[Yy]$ ]] && reboot 470 | } 471 | 472 | # start executing code ! 473 | 474 | [ $# -lt 2 ] && usage 475 | [ $# -gt 3 ] && usage 476 | config_dot_sh=$1 477 | git_remote=$2 478 | git_branch=$3 479 | 480 | initial_warning 481 | command -v zfs || bootstrap_zfs 482 | command -v git || bootstrap_git 483 | get_custom_nixcfg 484 | uefi_or_legacy 485 | disk_prep 486 | disk_part 487 | zpool_create 488 | mount_create_datasets 489 | bootstrap_nixcfg 490 | installation_complete 491 | -------------------------------------------------------------------------------- /themelios_usage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a-schaefers/themelios/98cd169d324e94da0225916bd9e84bc528465283/themelios_usage.png --------------------------------------------------------------------------------