Add install script

Signed-off-by: Nikolaos Karaolidis <nick@karaolidis.com>
This commit is contained in:
2025-01-12 14:13:35 +00:00
parent 8e18ca20a9
commit e9a55eed52
17 changed files with 323 additions and 185 deletions

View File

@@ -24,7 +24,6 @@ NixOS dotfiles and configuration for various hosts and users.
- [`remove-host.sh`](./lib/scripts/remove-host.sh): Remove references to a host.
- [`update-keys.sh`](./lib/scripts/update-keys.sh): Update the encryption keys in all relevant files using `sops.yaml` configurations.
- [`update.sh`](./lib/scripts/update.sh): Update flake and all git submodules.
- [`install.sh`](./lib/scripts/install.sh): Install or repair a selected NixOS host.
- [`submodules/`](./submodules): Flake forks used in the repository, such as [`nixpkgs`](https://github.com/NixOS/nixpkgs) and [`home-manager`](https://github.com/nix-community/home-manager).

View File

@@ -1,7 +1,7 @@
_backup_completion() {
local options=(
'-m[specify partition to mount for backup]:partition:($(_partitions))'
'-b[specify backup directory]:backup directory:_files -/'
'-m[Partition to mount for backup]:partition:($(_partitions))'
'-b[Backup directory]:backup directory:_files -/'
)
local curcontext="$curcontext" state line
typeset -A opt_args

View File

@@ -10,7 +10,7 @@ usage() {
cleanup() {
if [ -d "/persist.bak" ]; then btrfs -q subvolume delete "/persist.bak"; fi
if [ -n "${backup_location}" ] && [ -f "${backup_location}.tmp" ]; then rm "${backup_location}.tmp"; fi
if [ -n "${backup_location}" ]; then rm -f "${backup_location}.tmp"; fi
if [ -n "${mount_location}" ]; then
if mount | grep -q "${mount_location}"; then umount "${mount_location}"; fi

View File

@@ -0,0 +1,22 @@
{ pkgs, inputs, ... }:
{
environment.systemPackages = [
(pkgs.writeShellApplication {
name = "nix-install";
runtimeInputs = with pkgs; [
coreutils
iputils
jq
nix
inputs.disko.packages.${system}.disko
];
text = builtins.readFile ./install.sh;
})
];
home-manager.sharedModules = [
{
programs.zsh.initExtra = builtins.readFile ./install.completion.zsh;
}
];
}

View File

@@ -0,0 +1,30 @@
_nix-install_completion() {
local -a options
options=(
'1:flake:_directories'
'-m[Mode: 'install' or 'repair']:mode:(install repair)'
'-h[Host to configure]:host:($(_list_hosts))'
'-k[Key file to copy to user config]:key:($(_list_keys))'
'-p[LUKS password file to use for encryption]:password_file:_files'
'-c[Copy configuration to target]'
'-r[Reboot after completion]'
)
_list_hosts() {
flake="$(realpath ${words[2]})"
if [[ -f "${flake}/flake.nix" ]]; then
nix flake show --quiet --json "${flake}" 2>/dev/null | jq -r '.nixosConfigurations | keys[]'
fi
}
_list_keys() {
flake="$(realpath ${words[2]})"
if [[ -d "${flake}/secrets" ]]; then
find "${flake}/secrets" -type f -name 'key.txt' | sed -E 's|^.*/secrets/([^/]+)/key.txt$|\1|' | sort -u
fi
}
_arguments -s $options
}
compdef _nix-install_completion nix-install

View File

@@ -0,0 +1,173 @@
usage() {
echo "Usage: $0 flake -m install|repair -h host [-k key] [-p password_file] [-c] [-r]"
echo
echo "Options:"
echo " flake Directory containing the flake.nix file."
echo " -m mode Mode: 'install' or 'repair'."
echo " -h host Host to configure."
echo " -k key Key file to copy to user config."
echo " -p password_file LUKS password file to use for encryption."
echo " -c Copy configuration to target."
echo " -r Reboot after completion."
exit 1
}
check_root() {
if [[ "${EUID}" -ne 0 ]]; then
echo "Please run the script as root."
exit 1
fi
}
check_network() {
if ! ping -c 1 google.com &>/dev/null; then
echo "Connect to a network before proceeding."
exit 1
fi
}
check_flake() {
if [[ ! -f "${flake}/flake.nix" ]]; then
echo "flake.nix not found in ${flake}."
exit 1
fi
}
check_host() {
if ! nix flake show --quiet --json "${flake}" 2>/dev/null | jq -e ".nixosConfigurations[\"${host}\"]" &>/dev/null; then
echo "Host '${host}' not found in flake."
exit 1
fi
}
check_key() {
if [[ -n "${key}" ]] && [[ ! -f "${flake}/secrets/${key}/key.txt" ]]; then
echo "Key '${key}' not found."
exit 1
fi
}
set_password_file() {
if [[ -n "${password_file}" ]]; then
if [[ ! -f "${password_file}" ]]; then
echo "LUKS key file '${password_file}' not found."
exit 1
fi
ln -sf "${password_file}" /tmp/installer.key
else
echo "Enter password for LUKS encryption:"
IFS= read -r -s password
echo "Enter password again to confirm: "
IFS= read -r -s password_check
[ "${password}" != "${password_check}" ]
echo -n "${password}" > /tmp/installer.key
unset password password_check
fi
}
prepare_disk() {
local disko_mode="$1"
root=$(mktemp -d /mnt/install.XXXXXX)
disko -m "${disko_mode}" --yes-wipe-all-disks --root-mountpoint "${root}" "${flake}/hosts/${host}/format.nix" --arg device "\"${device}\""
}
copy_keys() {
mkdir -p "${root}/persist/etc/ssh"
cp "${flake}/hosts/${host}/secrets/ssh_host_ed25519_key" "${root}/persist/etc/ssh/ssh_host_ed25519_key"
for path in "${flake}/hosts/${host}/users"/*; do
if [[ -z "${key}" ]]; then
continue
fi
user=$(basename "${path}")
mkdir -p "${root}/persist/home/${user}/.config/sops-nix"
cp "${flake}/secrets/${key}/key.txt" "${root}/persist/home/${user}/.config/sops-nix/key.txt"
uid=$(cat "${flake}/hosts/${host}/users/${user}/uid")
gid=100
chown -R "${uid}:${gid}" "${root}/persist/home/${user}"
done
}
install() {
nixos-install --root "${root}" --flake "${flake}#${host}" --no-root-passwd
}
copy_config() {
echo "Copying configuration..."
rm -rf "${root}/persist/etc/nixos"
cp -r "${flake}" "${root}/persist/etc/nixos"
}
finish() {
echo "Rebooting system..."
trap - EXIT
cleanup
reboot
}
cleanup() {
rm -f /tmp/installer.key
if [[ -n "${host}" && -n "${device}" ]]; then disko -m "unmount" "${flake}/hosts/${host}/format.nix" --arg device "\"${device}\""; fi
if [[ -d "${root}" ]]; then rmdir "${root}"; fi
}
check_root
check_network
if [[ "$#" -lt 1 ]]; then
usage
fi
flake="$(realpath "$1")"
check_flake
shift
mode=""
host=""
key=""
password_file=""
copy_config_flag="false"
reboot_flag="false"
while getopts "m:h:k:p:cr" opt; do
case "${opt}" in
m) mode="${OPTARG}" ;;
h) host="${OPTARG}" ;;
k) key="${OPTARG}" ;;
p) password_file="${OPTARG}" ;;
c) copy_config_flag="true" ;;
r) reboot_flag="true" ;;
*) usage ;;
esac
done
if [[ -z "${mode}" || -z "${host}" ]]; then
usage
fi
check_host
check_key
until set_password_file; do echo "Passwords did not match, please try again."; done
device=$(grep -oP '(?<=device = ")[^"]+' "${flake}/hosts/${host}/default.nix")
case "${mode}" in
install)
prepare_disk "destroy,format,mount"
copy_keys
install
if [[ "${copy_config_flag}" == "true" ]]; then copy_config; fi
if [[ "${reboot_flag}" == "true" ]]; then finish; fi
;;
repair)
prepare_disk "mount"
install
if [[ "${reboot_flag}" == "true" ]]; then finish; fi
;;
*)
echo "Invalid mode: ${mode}"
usage
;;
esac

View File

@@ -1,7 +1,7 @@
_theme_completion() {
local options=(
'-m[set mode: light, dark, or toggle]:mode:(light dark toggle)'
'-w[set wallpaper: specify file path]:file:_files'
'-m[Set mode: 'light', 'dark', or 'toggle']:mode:(light dark toggle)'
'-w[Set wallpaper file]:file:_files'
)
local curcontext="$curcontext" state line
typeset -A opt_args

View File

@@ -1,9 +1,9 @@
WALLPAPER=""
MODE=""
wallpaper=""
mode=""
set_wallpaper() {
if [[ -f "$1" ]]; then
WALLPAPER="$1"
wallpaper="$1"
else
echo "Invalid wallpaper path: $1"
exit 1
@@ -12,9 +12,9 @@ set_wallpaper() {
toggle_mode() {
if [[ "$(cat "${CONFIG}"/mode)" = "light" ]]; then
MODE="dark"
mode="dark"
else
MODE="light"
mode="light"
fi
}
@@ -24,8 +24,8 @@ usage() {
}
finish() {
[[ -n "${WALLPAPER}" ]] && ln -sf "${WALLPAPER}" "${CONFIG}"/wallpaper
[[ -n "${MODE}" ]] && echo "${MODE}" > "${CONFIG}"/mode
[[ -n "${wallpaper}" ]] && ln -sf "${wallpaper}" "${CONFIG}"/wallpaper
[[ -n "${mode}" ]] && echo "${mode}" > "${CONFIG}"/mode
"${INIT}" > /dev/null
"${RELOAD}" > /dev/null
@@ -37,7 +37,7 @@ while getopts "m:w:" opt; do
m)
case "$OPTARG" in
light|dark)
MODE="$OPTARG"
mode="$OPTARG"
;;
toggle)
toggle_mode

View File

@@ -23,6 +23,7 @@
../common/configs/system/networking
../common/configs/system/nix
../common/configs/system/nix-cleanup
../common/configs/system/nix-install
../common/configs/system/nix-ld
../common/configs/system/nixpkgs
../common/configs/system/ntp

View File

@@ -40,6 +40,7 @@
content = {
name = "main";
type = "luks";
passwordFile = "/tmp/installer.key";
settings = {
allowDiscards = true;
};

View File

@@ -27,6 +27,7 @@
../common/configs/system/networking
../common/configs/system/nix
../common/configs/system/nix-cleanup
../common/configs/system/nix-install
../common/configs/system/nix-ld
../common/configs/system/nixpkgs
../common/configs/system/ntp

View File

@@ -40,6 +40,7 @@
content = {
name = "usb";
type = "luks";
passwordFile = "/tmp/installer.key";
settings = {
allowDiscards = true;
};

View File

@@ -3,11 +3,83 @@
I have automated myself out of a job. How to use:
1. Boot into installer
2. Unlock luks partition
3. Run the following commands:
2. Unlock luks partition
3. Connect to the internet with `nmcli`
- Scan for available networks:
```bash
nmcli device wifi list
```
- For an open network:
```bash
nmcli device wifi connect "<SSID>"
```
- For a secured network:
```bash
nmcli device wifi connect "<SSID>" password "<password>"
```
4. Run `sudo nix-install /etc/nixos -m install|repair -h host [-k key] [-c] [-r]"`
## Reinstalling the Installer
1. Download a Minimal Live Nix ISO
- Visit the official NixOS website: [https://nixos.org/download.html](https://nixos.org/download.html).
- Download the "Minimal ISO image".
2. Burn the ISO
- On Windows, use [Rufus](https://rufus.ie) to burn the ISO to a USB drive.
- On Linux, use the `dd` command:
```bash
sudo dd if=<path-to-iso> of=/dev/sdX bs=4M status=progress
```
3. Boot into USB
4. Connect to the Internet with `wpa_supplicant`
- Identify your network interface:
```bash
ip link show | grep -E '^[0-9]+:' | awk '{print $2}' | tr -d ':'
```
- For an open network:
```bash
wpa_supplicant -i "${interface}" -c <(wpa_passphrase "${ssid}") -B
```
- For a secured network:
```bash
config=$(mktemp)
wpa_passphrase "${ssid}" "${passphrase}" > "${config}"
wpa_supplicant -i "${interface}" -c "${config}" -B
rm "${config}"
```
- Obtain an IP address:
```bash
dhcpcd
```
5. Clone the flake repository
```bash
git clone git.karaolidis.com/karaolidis/nix
cd nix
```
cd /etc/nixos
direnv allow
sudo ./lib/scripts/install.sh
```
6. I really hope you had a backup of the keys, because you must copy them to the repository before the next step.
7. Run `nix --experimental-features "nix-command flakes" shell nixpkgs#disko nixpkgs#jq -c bash hosts/common/configs/system/nix-install/install.sh nix -m install -h installer -k personal -c`

View File

@@ -19,6 +19,7 @@
../common/configs/system/networking
../common/configs/system/nix
../common/configs/system/nix-cleanup
../common/configs/system/nix-install
../common/configs/system/nix-ld
../common/configs/system/nixpkgs
../common/configs/system/ntp

View File

@@ -32,6 +32,7 @@
content = {
name = "usb";
type = "luks";
passwordFile = "/tmp/installer.key";
settings = {
allowDiscards = true;
};

View File

@@ -28,6 +28,5 @@ sed -i "/userKnownHostsFile = lib.strings.concatStringsSep \" \" \[/a\ ..
"$(dirname "$0")/update-keys.sh" "$2"
echo "Host ${HOST} has been successfully added."
echo "Please generate SSH key pairs for any users that need to connect to user@host."
echo "Use the following command:"
echo "You can generate SSH key pairs for any users that need to connect to user@host using the following command:"
echo "ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_${HOST}_<user>"

View File

@@ -1,163 +0,0 @@
#!/usr/bin/env bash
set -o errexit
set -o nounset
set -o pipefail
check_root() {
if [[ "${EUID}" -ne 0 ]]; then
echo "Please run the script as root."
exit 1
fi
}
check_network() {
rfkill unblock all
if ping -c 1 google.com &>/dev/null; then
echo "Network connection detected, skipping Wi-Fi setup."
return
fi
echo "No network connection detected."
echo "Would you like to connect to a Wi-Fi network? [y/N]"
read -r connect_wifi
if ! [[ "${connect_wifi}" =~ ^([yY][eE][sS]|[yY])$ ]]; then
echo "Connect to a network before proceeding."
exit 1
fi
setup_wifi
}
setup_wifi() {
echo "Available Wi-Fi interfaces:"
nmcli device status | awk '$2 == "wifi" {print $1}'
echo "Enter the Wi-Fi interface you want to use:"
read -r interface
echo "Scanning for Wi-Fi networks..."
nmcli device wifi rescan
echo "Available Wi-Fi networks:"
nmcli device wifi list
echo "Enter the SSID of the network:"
read -r ssid
echo "Is this network open? [y/N]"
read -r open_network
if [[ "${open_network}" =~ ^([yY][eE][sS]|[yY])$ ]]; then
nmcli device wifi connect "${ssid}" ifname "${interface}"
else
echo "Enter the passphrase:"
read -rs passphrase
nmcli device wifi connect "${ssid}" password "${passphrase}" ifname "${interface}"
fi
echo "Waiting for a network connection..."
for _ in {1..10}; do
if ping -c 1 google.com &>/dev/null; then
echo "Connected to the network successfully."
return
fi
sleep 1
done
echo "Failed to establish a connection within the timeout period."
exit 1
}
select_host() {
echo "Available hosts:"
hosts=$(nix --experimental-features "nix-command flakes" flake show --json \
| nix --experimental-features "nix-command flakes" shell nixpkgs#jq --command jq -r '.nixosConfigurations | keys[]')
echo "${hosts}"
echo "Enter host:"
read -r host
}
prepare_disk() {
local mode="$1"
device=$(grep -oP '(?<=device = ")[^"]+' "./hosts/${host}/default.nix")
nix --experimental-features "nix-command flakes" run github:nix-community/disko -- --mode "${mode}" "./hosts/${host}/format.nix" --arg device "\"${device}\""
}
copy_keys() {
mkdir -p /mnt/persist/etc/ssh
cp "./hosts/${host}/secrets/ssh_host_ed25519_key" /mnt/persist/etc/ssh/ssh_host_ed25519_key
for path in "./hosts/${host}/users"/*; do
user=$(basename "${path}")
echo "User detected: ${user}"
echo "Available keys for ${user}:"
ls ./secrets/*/key.txt
echo "Enter the key file to copy (or press Enter to skip this user):"
read -r key
if [[ -z "${key}" ]]; then
echo "Skipping ${user}"
continue
fi
mkdir -p "/mnt/persist/home/${user}/.config/sops-nix"
cp "${key}" "/mnt/persist/home/${user}/.config/sops-nix/key.txt"
uid=$(cat "./hosts/${host}/users/${user}/uid")
gid=100
chown -R "${uid}:${gid}" "/mnt/persist/home/${user}"
done
}
copy_config() {
echo "Would you like to copy the current configuration (including keys) to the target system? [y/N]"
read -r copy_config
if [[ "${copy_config}" =~ ^([yY][eE][sS]|[yY])$ ]]; then
rm -rf /mnt/persist/etc/nixos
cp -r . /mnt/persist/etc/nixos
echo "Configuration copied successfully."
fi
}
install() {
nixos-install --root /mnt --flake ".#${host}"
}
main() {
check_root
check_network
select_host
echo "What would you like to do with ${host}?"
echo "1) Install"
echo "2) Repair"
read -r choice
case ${choice} in
1)
prepare_disk "disko"
copy_keys
install
copy_config
echo "Installation complete. Reboot your system."
;;
2)
prepare_disk "mount"
install
echo "Repair complete. Reboot your system."
;;
*)
echo "Invalid choice."
;;
esac
}
main