Update to logic. Added postrun actions. Have to work on postinstall script.

This commit is contained in:
Raphaël Numbus
2025-12-22 16:45:31 +01:00
parent fb751ca89b
commit 9559b232dc
5 changed files with 99 additions and 26 deletions
-1
View File
@@ -35,7 +35,6 @@ in
'systemctl default' 'systemctl default'
to continue booting to continue booting
''; '';
example = "6214de8c3d861c4b451acc8c4e24294c95d55bcec516bbf15c077ca3bffb6547";
}; };
}; };
boot.initrd.luks.devices = lib.mkOption { boot.initrd.luks.devices = lib.mkOption {
+6
View File
@@ -1,3 +1,9 @@
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i bash -p gum openssl sops ssh-to-age age sshpass envsubst pciutils usbutils mosquitto #!nix-shell -i bash -p gum openssl sops ssh-to-age age sshpass envsubst pciutils usbutils mosquitto
gum confirm "Welcome to the Numbus-Server administration interface. Would you like to change a setting ?" \
|| { echo " ❌ Aborting as requested."; exit 1; }
ACTIONS_LIST=("Update networking settings" "Update backup settings" "Add/Remove services" \
"Add/Remove/Replace boot disk" "Add/Remove/Replace data disk(s)" "Add/Remove devices (i.e. coral TPUs)" \
"Test email notifications" "Check disk(s) health" "Export current configuration to a git server")
Executable → Regular
+90 -22
View File
@@ -1,5 +1,12 @@
#!/usr/bin/env nix-shell #!/usr/bin/env nix-shell
#!nix-shell -i bash -p gum xkcdpass openssl sops ssh-to-age age sshpass envsubst pciutils usbutils mosquitto rsync #!nix-shell -i bash -p gum xkcdpass sops ssh-to-age age sshpass envsubst pciutils usbutils mosquitto
NECESSARY_VARIABLES_LIST=("TARGET_HOST" "SSH_PUBLIC_KEY" "DOMAIN_NAME" "EMAIL_ADDRESS" \
"CF_DNS_API_TOKEN" "SENDER_EMAIL_ADDRESS" "SENDER_EMAIL_ADDRESS_PASSWORD" \
"SENDER_EMAIL_DOMAIN" "SENDER_EMAIL_PORT" "HOME_ROUTER_SUBNET" "HOME_ROUTER_IP" \
"HOME_SERVER_IP")
INSTALLED_REMOTE_PASS="changeMe!"
necessary_credentials() { necessary_credentials() {
#TARGET SETTINGS #TARGET SETTINGS
@@ -40,9 +47,8 @@ necessary_credentials_with_config() {
CONFIG_PATH="$(gum file)" CONFIG_PATH="$(gum file)"
source "$CONFIG_PATH" source "$CONFIG_PATH"
REQUIRED_VARS=(TARGET_HOST SSH_PUBLIC_KEY DOMAIN_NAME EMAIL_ADDRESS CF_DNS_API_TOKEN SENDER_EMAIL_ADDRESS SENDER_EMAIL_ADDRESS_PASSWORD SENDER_EMAIL_DOMAIN SENDER_EMAIL_PORT HOME_ROUTER_SUBNET HOME_ROUTER_IP HOME_SERVER_IP)
MISSING=0 MISSING=0
for VAR in "${REQUIRED_VARS[@]}"; do for VAR in "${NECESSARY_VARIABLES_LIST[@]}"; do
if [[ -v $VAR && -n ${!VAR} ]]; then if [[ -v $VAR && -n ${!VAR} ]]; then
echo -e "\n ✅ $VAR imported successfully from the config file" echo -e "\n ✅ $VAR imported successfully from the config file"
export $VAR export $VAR
@@ -63,29 +69,34 @@ setup_ssh() {
chmod 700 extra-files/home/numbus-admin/.ssh/ chmod 700 extra-files/home/numbus-admin/.ssh/
ssh-keygen -t "ed25519" -C "numbus-admin@numbus-server" -f "extra-files/home/numbus-admin/.ssh/id_ed25519" -N "" -q ssh-keygen -t "ed25519" -C "numbus-admin@numbus-server" -f "extra-files/home/numbus-admin/.ssh/id_ed25519" -N "" -q
REMOTE_PASS=$(gum input --password --placeholder "Enter password for 'nixos' on '$TARGET_HOST'") LIVE_REMOTE_PASS=$(gum input --password --placeholder "Enter password for 'nixos@$TARGET_HOST'")
if [ -z "$REMOTE_PASS" ]; then if [ -z "$LIVE_REMOTE_PASS" ]; then
echo " ❌ Password is required to proceed. Aborting." echo " ❌ Password is required to proceed. Aborting."
exit 1 exit 1
fi fi
echo -e "\n\n ➡️ Copying SSH key to target host 'nixos@$TARGET_HOST'..." echo -e "\n\n ➡️ Copying SSH key to target host 'nixos@$TARGET_HOST'..."
if sshpass -p "$REMOTE_PASS" ssh-copy-id -o StrictHostKeyChecking=no -i "extra-files/home/numbus-admin/.ssh/id_ed25519" "nixos@$TARGET_HOST"; then if sshpass -p "$LIVE_REMOTE_PASS" ssh-copy-id -o StrictHostKeyChecking=no -i "extra-files/home/numbus-admin/.ssh/id_ed25519" "nixos@$TARGET_HOST"; then
echo " ✅ SSH key copied successfully." echo " ✅ SSH key copied successfully."
else else
echo " ❌ Failed to copy SSH key. Please check the host IP and password." echo " ❌ Failed to copy SSH key. Please check the host IP and password."
exit 1 exit 1
fi fi
export REMOTE_PASS export LIVE_REMOTE_PASS
} }
ssh_to_host() { ssh_to_live_host() {
ARG="$1" ARG="$1"
ssh -i "extra-files/home/numbus-admin/.ssh/id_ed25519" "nixos@$TARGET_HOST" $ARG ssh -i "extra-files/home/numbus-admin/.ssh/id_ed25519" "nixos@$TARGET_HOST" $ARG
} }
ssh_to_installed_host() {
ARG="$1"
ssh -i "extra-files/home/numbus-admin/.ssh/id_ed25519" "numbus-admin@$TARGET_HOST" $ARG
}
hardware_detection() { hardware_detection() {
echo -e "\n\n 🔎 Detecting graphics card on target host..." echo -e "\n\n 🔎 Detecting graphics card on target host..."
VGA_INFO=$(ssh_to_host "lspci -nn | grep -i 'vga'") VGA_INFO=$(ssh_to_live_host "lspci -nn | grep -i 'vga'")
if echo "$VGA_INFO" | grep -iq "intel" 2>/dev/null; then if echo "$VGA_INFO" | grep -iq "intel" 2>/dev/null; then
echo -e " ✅ Intel graphics card detected." echo -e " ✅ Intel graphics card detected."
export TARGET_GRAPHICS="true" export TARGET_GRAPHICS="true"
@@ -100,7 +111,7 @@ hardware_detection() {
export TARGET_GRAPHICS="false" export TARGET_GRAPHICS="false"
fi fi
echo -e "\n\n 🔎 Detecting transconding acceleration on target host..." echo -e "\n\n 🔎 Detecting transconding acceleration on target host..."
if ssh_to_host "ls /dev/dri/ | grep -iq 'renderD128'" 2>/dev/null; then if ssh_to_live_host "ls /dev/dri/ | grep -iq 'renderD128'" 2>/dev/null; then
echo -e " ✅ Transcoding capable card detected." echo -e " ✅ Transcoding capable card detected."
TARGET_GRAPHICS_RENDERER="true" TARGET_GRAPHICS_RENDERER="true"
else else
@@ -108,7 +119,7 @@ hardware_detection() {
TARGET_GRAPHICS_RENDERER="false" TARGET_GRAPHICS_RENDERER="false"
fi fi
echo -e "\n\n 🔎 Detecting USB Google Coral TPU on target host..." echo -e "\n\n 🔎 Detecting USB Google Coral TPU on target host..."
if ssh_to_host "lsusb | grep -iq 'google'" 2>/dev/null; then if ssh_to_live_host "lsusb | grep -iq 'google'" 2>/dev/null; then
echo -e " ✅ USB Google Coral TPU detected." echo -e " ✅ USB Google Coral TPU detected."
TARGET_USB_CORAL="true" TARGET_USB_CORAL="true"
else else
@@ -116,9 +127,9 @@ hardware_detection() {
TARGET_USB_CORAL="false" TARGET_USB_CORAL="false"
fi fi
echo -e "\n\n 🔎 Detecting Zigbee coordinator on target host..." echo -e "\n\n 🔎 Detecting Zigbee coordinator on target host..."
if ssh_to_host "ls /dev/serial/by-id/ | grep -i 'zigbee'" 2>/dev/null; then if ssh_to_live_host "ls /dev/serial/by-id/ | grep -i 'zigbee'" 2>/dev/null; then
echo -e " ✅ Zigbee device found in /dev/serial/by-id/." echo -e " ✅ Zigbee device found in /dev/serial/by-id/."
TARGET_ZIGBEE_DEVICE=$(ssh_to_host "ls /dev/serial/by-id/ | grep -i 'zigbee'") TARGET_ZIGBEE_DEVICE=$(ssh_to_live_host "ls /dev/serial/by-id/ | grep -i 'zigbee'")
else else
echo -e " ⚠️ No Zigbee device found." echo -e " ⚠️ No Zigbee device found."
TARGET_ZIGBEE_DEVICE="" TARGET_ZIGBEE_DEVICE=""
@@ -268,7 +279,7 @@ disk_config_generation() {
TMPFILE="/tmp/nixos-deployment-temp-file" TMPFILE="/tmp/nixos-deployment-temp-file"
### --> Get disk information ### --> Get disk information
DISK_DETAILS=$(ssh_to_host 'bash -s' <<EOF DISK_DETAILS=$(ssh_to_live_host 'bash -s' <<EOF
HDD=1 HDD=1
DISK_DEVPATH=() DISK_DEVPATH=()
@@ -292,7 +303,7 @@ for DISK in \$(lsblk -x SIZE -d -n -e 7,11 -o NAME); do
else DISK_TYPE+=("Other") else DISK_TYPE+=("Other")
fi fi
# Disk health # Disk health
if [[ \$(echo "$REMOTE_PASS" | sudo -S smartctl -H /dev/\$DISK 2>/dev/null | grep 'self-assessment' | awk '{print \$6}') -eq "PASSED" ]]; then if [[ \$(echo "$LIVE_REMOTE_PASS" | sudo -S smartctl -H /dev/\$DISK 2>/dev/null | grep 'self-assessment' | awk '{print \$6}') -eq "PASSED" ]]; then
DISK_HEALTH+=("PASSED") DISK_HEALTH+=("PASSED")
else else
DISK_HEALTH+=("N/A") DISK_HEALTH+=("N/A")
@@ -345,16 +356,19 @@ EOF
fi fi
done done
echo "Boot ; ${BOOT_DISKS_ID[@]}, ${#BOOT_DISKS_ID[@]}"
if [[ "${#BOOT_DISKS_ID[@]}" -eq 0 ]]; then if [[ "${#BOOT_DISKS_ID[@]}" -eq 0 ]]; then
echo -e "\n\n ❌ No boot disk selected. Aborting." echo -e "\n\n ❌ No boot disk selected. Aborting."
exit 1 exit 1
elif [[ "${#BOOT_DISKS_ID[@]}" -eq 1 ]]; then elif [[ "${#BOOT_DISKS_ID[@]}" -eq 1 ]]; then
echo -e "\n\n ⚠️ One boot disk selected, continuing with striped boot disk configuration." echo -e "\n\n ⚠️ One boot disk selected, continuing with striped boot disk configuration."
echo -e " Consider using 2 boot disks instead to get data protection features on the boot disks." echo -e " Consider using 2 boot disks instead to get data protection features on the boot disks."
export BOOT_DISK_1_ID=${BOOT_DISKS_ID[0]}
elif [[ "${#BOOT_DISKS_ID[@]}" -eq 2 ]]; then elif [[ "${#BOOT_DISKS_ID[@]}" -eq 2 ]]; then
echo -e "\n\n ✅ Two boot disks selected, continuing with mirrored boot disks configuration." echo -e "\n\n ✅ Two boot disks selected, continuing with mirrored boot disks configuration."
echo -e "\n\n ⚠️ If the two disks are different sizes, the resulting usable space size will be \
the one of the smallest disk."
export BOOT_DISK_1_ID=${BOOT_DISKS_ID[0]}
export BOOT_DISK_2_ID=${BOOT_DISKS_ID[1]}
else else
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting." echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
exit 1 exit 1
@@ -491,7 +505,7 @@ EOF
### Config generation <-- ### Config generation <--
### --> Generate unlock keys ### --> Generate unlock keys
for i in ${!BOOT_DISKS_ID[@]}; do for i in ${#BOOT_DISKS_ID[@]}; do
declare "/etc/secrets/disks/boot-disk-${i}=$(xkcdpass -d "-")" declare "/etc/secrets/disks/boot-disk-${i}=$(xkcdpass -d "-")"
done done
for i in $CONTENT_DISK_NUMBER; do for i in $CONTENT_DISK_NUMBER; do
@@ -547,11 +561,63 @@ postrun_action() {
echo -e "\n\n Now the remote machine will reboot. You will need to input the boot disk(s) passphrase. echo -e "\n\n Now the remote machine will reboot. You will need to input the boot disk(s) passphrase.
This will be the only time you will have to do so, it will be automatic in the future." This will be the only time you will have to do so, it will be automatic in the future."
gum spin --spinner dot --title "Rebooting the remote..." -- sleep 60 gum spin --spinner dot --title "Rebooting the remote..." -- sleep 120
ssh gum confirm " ➡️ Select 'yes' once the machine rebooted and you unlocked the disks." || { echo -e "\n\n ❌ Aborting as requested."; exit 1; }
# Add TPM2 boot disk decryption
# Add pcr-check.nix gum spin --spinner dot --title "\n\n 🔄 Waiting for the server to boot up..." --auto <<EOF
while FOUND="false"; do
if ping -c1 -W1 $HOME_SERVER_IP >/dev/null 2>&1; then
FOUND="true"
exit 0
(i++)
if [[ "\${i}" -gt 150 ]]; then
echo -e "\n\n ❌ Could not connect to the server after 150 retries. \
This is most likely due to a networking issue. Please double check your network settings. Aborting."
exit 1
fi
fi
done
EOF
ssh_to_installed_host 'bash -s' <<EOF
sed -i "s|# ./disks/pcr-check.nix| ./disks/pcr-check.nix|" /etc/nixos/configuration.nix
if [[ ${#BOOT_DISKS_ID[@]} -eq 1 ]]; then
echo $INSTALLED_REMOTE_PASS | sudo -S systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/mapper/crypted-boot-1
elif [[ ${#BOOT_DISKS_ID[@]} -eq 2 ]]; then
echo $INSTALLED_REMOTE_PASS | sudo -S systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/mapper/crypted-boot-1
echo $INSTALLED_REMOTE_PASS | sudo -S systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/mapper/crypted-boot-2
fi
PCR_HASH=\$(echo $INSTALLED_REMOTE_PASS | sudo -S systemd-analyze pcrs 15 --json=short)
sed -i "s|# systemIdentity.enable = true;| systemIdentity.enable = true;|" /etc/nixos/configuration.nix
sed -i "s|# systemIdentity.pcr15 = "PCR_HASH";| systemIdentity.pcr15 = "PCR_HASH";|" /etc/nixos/configuration.nix
sed -i "s|PCR_HASH|\${PCR_HASH}|" /etc/nixos/configuration.nix
EOF
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "
⚠️ $(gum style --foreground 212 'WARNING:') You will now set the password of the numbus-admin user. \
You will almost never user it. Consider using a very strong password : you can write it down \
securely on a hidden sheet of paper or add it to your password manager (local with Passbolt \
any other online password manager provider.)."
gum confirm " ➡️ I understand, 'yes' to proceed." || { echo -e "\n\n ❌ Aborting as requested."; exit 1; }
echo $INSTALLED_REMOTE_PASS | sudo -S passwd numbus-admin
}
congrats() {
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "
⚠️ $(gum style --foreground 212 'CONGRATULATIONS !!:') You now have a working home server. \
Data stored on there will be fully yours and protected. Keep in my mind this comes with the \
responsability of managing it and keeping it secure. Now, you have to log in the webpages of \
the services you installed. Create an admin account for all of them and configure them (or keep \
it simple and use defaults) and take care to note down all the passwords. Change all default passwords \
and create user accounts for your family or friends that will use the server.
Cheers !!"
} }
nixos_update() { nixos_update() {
@@ -605,6 +671,7 @@ if [[ "$ACTION_ANSWER" -eq "[1] 🌐 Deploy NixOS on a remote machine" ]]; then
disk_config_generation disk_config_generation
deploy deploy
postrun_action postrun_action
congrats
elif [[ "$ACTION_ANSWER" -eq "[2] 💽 Deploy NixOS on a remote machine with a file configuration" ]]; then elif [[ "$ACTION_ANSWER" -eq "[2] 💽 Deploy NixOS on a remote machine with a file configuration" ]]; then
echo -e "\n ➡️ Proceeding with deployment using a config file…" echo -e "\n ➡️ Proceeding with deployment using a config file…"
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "➡️ On the target host : start the computer and boot into the NixOS iso. gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "➡️ On the target host : start the computer and boot into the NixOS iso.
@@ -619,6 +686,7 @@ elif [[ "$ACTION_ANSWER" -eq "[2] 💽 Deploy NixOS on a remote machine with a f
deploy deploy
sum_up sum_up
postrun_action postrun_action
congrats
elif [[ "$ACTION_ANSWER" -eq "[3] 🛠️ Update a NixOS remote machine" ]]; then elif [[ "$ACTION_ANSWER" -eq "[3] 🛠️ Update a NixOS remote machine" ]]; then
echo -e "\n ➡️ Proceeding with update…" echo -e "\n ➡️ Proceeding with update…"
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "➡️ On the target host : make sure the NixOS installation you want gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "➡️ On the target host : make sure the NixOS installation you want
+2 -2
View File
@@ -38,7 +38,7 @@
# TPM2 PCR check # TPM2 PCR check
# systemIdentity.enable = true; # systemIdentity.enable = true;
# systemIdentity.pcr15 = null; # systemIdentity.pcr15 = "PCR_HASH";
# Timezone # Timezone
time.timeZone = "Europe/Paris"; time.timeZone = "Europe/Paris";
@@ -116,7 +116,7 @@
description = "Numbus Admin"; description = "Numbus Admin";
extraGroups = [ "networkmanager" "wheel" "docker" ]; extraGroups = [ "networkmanager" "wheel" "docker" ];
uid = 1000; uid = 1000;
initialPassword = "nixos-at-numbus"; initialPassword = "changeMe!";
}; };
# Login message # Login message
+1 -1
View File
@@ -55,7 +55,7 @@ in
### --> SMART disk heath ### --> SMART disk heath
services.smartd = { services.smartd = {
enable = true; enable = true;
defaults.autodetected = "-a -o on -S on -s (S/../.././02|L/../../6/03) -n standby,q"; defaults.autodetected = "-a -o on -S on -s (S/../.././00|L/../../6/01) -n standby,q";
notifications = { notifications = {
wall = { wall = {
enable = true; enable = true;