Big update. Folder reorganization. Disk selection logic finished. Improved services selection (not done yet).

This commit is contained in:
Raphael Numbus
2025-12-14 13:58:01 +01:00
parent 0e0ed4d3a3
commit f777e608b8
32 changed files with 435 additions and 261 deletions
+144 -153
View File
@@ -1,5 +1,5 @@
#!/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 xkcdpass openssl sops ssh-to-age age sshpass envsubst pciutils usbutils mosquitto
necessary_credentials() {
#TARGET SETTINGS
@@ -127,148 +127,126 @@ hardware_detection() {
services_selection() {
echo -e "\n\n ➡️ You will now select the services you want installed on your server:"
declare -A SERVICE_MAP
SERVICE_MAP["Pi-Hole: Block ads on all your devices"]="pihole"
SERVICE_MAP["Home Assistant: Manage your smart home or security cameras"]="hass"
SERVICE_MAP["Passbolt: Secure password manager with collaboration features"]="passbolt"
SERVICE_MAP["Frigate [Home Assistant required]: Secure your house with security cameras"]="frigate"
SERVICE_MAP["Nextcloud: No fuss Office 365 replacement"]="nextcloud"
SERVICE_MAP["Immich: Pictures and videos backup with local machine-learning"]="immich"
AVAILABLE_SERVICES=( "frigate" "gitea" "home-assistant" "immich" "it-tools" \
"nextcloud" "passbolt" "pi-hole" )
AVAILABLE_SERVICES_NUMBER=${#AVAILABLE_SERVICES[@]}
mapfile -t SERVICE_DESCRIPTIONS < <(for key in "${!SERVICE_MAP[@]}"; do echo "$key"; done | sort)
SERVICES_DESCRIPTION=( "Pi-Hole : Block ads on all your devices" \
"Immich : Pictures and videos backup with local machine-learning" \
"Nextcloud : No fuss Office 365 replacement" \
"Passbolt: Security-first password manager with collaboration features" \
"Home-Assistant : Manage your smart home and security cameras" \
"Frigate [Home Assistant required] : Secure your house with security cameras" \
"Gitea : Your own git platform" \
"IT-tools : A set of useful tools when doing IT" \
)
SELECTED_DESCRIPTIONS_STRING=$(gum choose --no-limit --header "Homelab services:" "${SERVICE_DESCRIPTIONS[@]}")
SELECTED_SERVICES_DESCRIPTION=$(gum choose --no-limit --header "Homelab services:" "${SERVICES_DESCRIPTION[@]}")
SERVICES=()
if [[ -n "$SELECTED_DESCRIPTIONS_STRING" ]]; then
while IFS= read -r line; do
SERVICES+=("${SERVICE_MAP[$line]}")
done <<< "$SELECTED_DESCRIPTIONS_STRING"
fi
for i in $(seq 0 $((${#AVAILABLE_SERVICES[@]} - 1))); do
if printf '%s' "$SELECTED_SERVICES_DESCRIPTION" | grep -iq "${AVAILABLE_SERVICES[$i]}"; then
SELECTED_SERVICES+=(${AVAILABLE_SERVICES[$i]})
fi
done
}
files_generation() {
echo -e "\n\nGenerating necessary folder tree..."
echo -e "\n ✅ Writing configuration files for the selected homelab services..."
# Traefik
mkdir -p extra-files/mnt/config-storage/traefik/config/conf/
cp ./config-files/docker/compose/traefik.nix ./config-files/docker/compose/traefik.nix
envsubst < config-files/docker/config/traefik/traefik.yaml > extra-files/mnt/config-storage/traefik/config/traefik.yaml
for service in "${SELECTED_SERVICES[@]}"; do
# Frigate
if [[ "$service" == "frigate" ]]; then
echo -e "\n ✅ Adapting the docker configuration to your hardware..."
FRIGATE_DEVICES_BLOCK=""
if [[ "$TARGET_GRAPHICS_RENDERER" == "true" ]]; then
FRIGATE_DEVICES_BLOCK+=" - /dev/dri:/dev/dri\n"
if [[ "$TARGET_USB_CORAL" == "true" ]]; then
FRIGATE_DEVICES_BLOCK+=" - /dev/bus/usb:/dev/bus/usb\n"
if [[ -n "$FRIGATE_DEVICES_BLOCK" ]]; then
REPLACEMENT="devices:\n${FRIGATE_DEVICES_BLOCK%\\n}"
sed -i.bak "s|# --- frigate devices --- #|$REPLACEMENT|" ./config-files/docker/compose/frigate.nix
else
sed -i.bak "/# --- frigate devices --- #/d" ./config-files/docker/compose/frigate.nix
fi
# Home-Assistant
elif [[ "$service" == "home-assistant" ]]; then
if [[ -n "$TARGET_ZIGBEE_DEVICE" ]]; then
REPLACEMENT="devices:\n - /dev/serial/by-id/${TARGET_ZIGBEE_DEVICE}:/dev/ttyUSB0"
sed -i.bak "s|# --- hass devices --- #|$REPLACEMENT|" ./config-files/docker/compose/hass.nix
else
sed -i.bak "/# --- hass devices --- #/d" ./config-files/docker/compose/hass.nix
fi
export HOME_ASSISTANT_MQTT_USER="$(xkcdpass -d "-" -n 2)"
export HOME_ASSISTANT_MQTT_PASSWORD="$(xkcdpass -d "-")"
mkdir -p extra-files/mnt/config-storage/hass/mqtt/config/
mkdir -p extra-files/mnt/config-storage/hass/mqtt/data/
envsubst < config-files/docker/config/hass/mosquitto.conf > extra-files/mnt/config-storage/hass/mqtt/config/mosquitto.conf
touch extra-files/mnt/config-storage/hass/mqtt/config/password.txt
chmod 0700 extra-files/mnt/config-storage/hass/mqtt/config/password.txt
mosquitto_passwd -b extra-files/mnt/config-storage/hass/mqtt/config/password.txt $HOME_ASSISTANT_MQTT_USER $HOME_ASSISTANT_MQTT_PASSWORD
# Passbolt
elif [[ "$service" == "passbolt" ]]; then
export PASSBOLT_DB_NAME="$(xkcdpass -d "-" -n 2)"
export PASSBOLT_DB_USERNAME="$(xkcdpass -d "-" -n 2)"
export PASSBOLT_DB_PASSWORD="$(xkcdpass -d "-")"
envsubst < config-files/docker/config/traefik/headers.yaml > extra-files/mnt/config-storage/traefik/config/conf/headers.yaml
envsubst < config-files/docker/config/traefik/tls.yaml > extra-files/mnt/config-storage/traefik/config/conf/tls.yaml
# Pi-Hole
elif [[ "$service" == "pi-hole" ]]; then
export FTLCONF_WEBSERVER_PASSWORD="$(xkcdpass -d "-")"
# Immich
elif [[ "$service" == "immich" ]]; then
IMMICH_DEVICES_BLOCK=""
if [[ "$TARGET_GRAPHICS_RENDERER" == "true" ]]; then
IMMICH_DEVICES_BLOCK+=" - /dev/dri:/dev/dri\n"
if [[ -n "$IMMICH_DEVICES_BLOCK" ]]; then
REPLACEMENT="devices:\n${IMMICH_DEVICES_BLOCK%\\n}"
sed -i.bak "s|# --- immich devices --- #|$REPLACEMENT|" ./config-files/docker/compose/immich.nix
else
sed -i.bak "/# --- immich devices --- #/d" ./config-files/docker/compose/immich.nix
fi
export IMMICH_DB_NAME="$(xkcdpass -d "-" -n 2)"
export IMMICH_DB_USERNAME="$(xkcdpass -d "-" -n 2)"
export IMMICH_DB_PASSWORD="$(xkcdpass -d "-")"
mkdir -p extra-files/mnt/data-storage/immich/
elif [[ "$service" == "gitea" ]]; then
export GITEA_DB_NAME="$(xkcdpass -d "-" -n 2)"
export GITEA_DB_USERNAME="$(xkcdpass -d "-" -n 2)"
export GITEA_DB_PASSWORD="$(xkcdpass -d "-")"
elif [[ "$service" == "nextcloud" ]]; then
envsubst < config-files/docker/config/traefik/nextcloud.yaml > extra-files/mnt/config-storage/traefik/config/conf/nextcloud.yaml
mkdir -p extra-files/mnt/data-storage/nextcloud/
fi
cp ./config-files/docker/compose/${service}.nix ./config-files/docker/compose/${service}.nix
done
echo -e "\n ✅ Generating sops-nix keys..."
mkdir -p extra-files/etc/secrets/disks/
mkdir -p extra-files/var/lib/sops-nix/
mkdir -p extra-files/etc/nixos/secrets/
mkdir -p extra-files/mnt/config-storage/traefik/config/conf/
mkdir -p extra-files/mnt/config-storage/hass/mqtt/config/
mkdir -p extra-files/mnt/config-storage/hass/mqtt/data/
mkdir -p extra-files/mnt/data-storage/nextcloud/
mkdir -p extra-files/mnt/data-storage/immich/
echo -e "\n ✅ Generating sops-nix keys..."
ssh-to-age -private-key -i extra-files/home/numbus-admin/.ssh/id_ed25519 > extra-files/var/lib/sops-nix/key.txt
export SOPS_PUBLIC_KEY=$(age-keygen -y extra-files/var/lib/sops-nix/key.txt)
echo -e "\n ✅ Generating sops-nix configuration files..."
envsubst < config-files/sops-nix/.sops.yaml > extra-files/etc/nixos/.sops.yaml
echo -e "\n ✅ Generating secure random database passwords..."
export HOME_ASSISTANT_MQTT_USER="$(openssl rand -hex 10)"
export HOME_ASSISTANT_MQTT_PASSWORD="$(openssl rand -base64 32 | tr -d '\=+/')"
export PASSBOLT_MYSQL_DATABASE="$(openssl rand -hex 10)"
export PASSBOLT_MYSQL_USER="$(openssl rand -hex 10)"
export PASSBOLT_MYSQL_PASSWORD="$(openssl rand -base64 32 | tr -d '\=+/')"
export FTLCONF_WEBSERVER_PASSWORD="$(openssl rand -base64 32 | tr -d '\=+/')"
export IMMICH_DB_DATABASE_NAME="$(openssl rand -hex 10)"
export IMMICH_DB_USERNAME="$(openssl rand -hex 10)"
export IMMICH_DB_PASSWORD="$(openssl rand -base64 32 | tr -d '\=+/')"
export CONTENT_DISK_1_KEY="$(openssl rand -base64 10 | tr -d '\=+/')"
export CONTENT_DISK_2_KEY="$(openssl rand -base64 10 | tr -d '\=+/')"
export CONTENT_DISK_3_KEY="$(openssl rand -base64 10 | tr -d '\=+/')"
export CONTENT_DISK_4_KEY="$(openssl rand -base64 10 | tr -d '\=+/')"
export CONTENT_DISK_5_KEY="$(openssl rand -base64 10 | tr -d '\=+/')"
export CONTENT_DISK_6_KEY="$(openssl rand -base64 10 | tr -d '\=+/')"
export PARITY_DISK_1_KEY="$(openssl rand -base64 10 | tr -d '\=+/ ')"
export PARITY_DISK_2_KEY="$(openssl rand -base64 10 | tr -d '\=+/ ')"
export PARITY_DISK_3_KEY="$(openssl rand -base64 10 | tr -d '\=+/ ')"
export BOOT_DISK_1_KEY="$(openssl rand -base64 10 | tr -d '\=+/ ')"
export BOOT_DISK_2_KEY="$(openssl rand -base64 10 | tr -d '\=+/ ')"
echo -e "\n ✅ Generating disk keyfiles in /etc/secrets/disks/..."
for i in {1..6}; do var="CONTENT_DISK_${i}_KEY"; [[ -n "${!var}" ]] && echo -n "${!var}" > "extra-files/etc/secrets/disks/content-disk-$i"; done
for i in {1..3}; do var="PARITY_DISK_${i}_KEY"; [[ -n "${!var}" ]] && echo -n "${!var}" > "extra-files/etc/secrets/disks/parity-disk-$i"; done
for i in {1..2}; do var="BOOT_DISK_${i}_KEY"; [[ -n "${!var}" ]] && echo -n "${!var}" > "extra-files/etc/secrets/disks/boot-disk-$i"; done
echo "$REMOTE_PASS" | ssh_to_host """
sudo -S mkdir -p /etc/secrets/disks/
echo -n $CONTENT_DISK_1_KEY | sudo -S tee /etc/secrets/disks/content-disk-1 > /dev/null
echo -n $CONTENT_DISK_2_KEY | sudo -S tee /etc/secrets/disks/content-disk-2 > /dev/null
echo -n $CONTENT_DISK_3_KEY | sudo -S tee /etc/secrets/disks/content-disk-3 > /dev/null
echo -n $CONTENT_DISK_4_KEY | sudo -S tee /etc/secrets/disks/content-disk-4 > /dev/null
echo -n $CONTENT_DISK_5_KEY | sudo -S tee /etc/secrets/disks/content-disk-5 > /dev/null
echo -n $CONTENT_DISK_6_KEY | sudo -S tee /etc/secrets/disks/content-disk-6 > /dev/null
echo -n $PARITY_DISK_1_KEY | sudo -S tee /etc/secrets/disks/parity-disk-1 > /dev/null
echo -n $PARITY_DISK_2_KEY | sudo -S tee /etc/secrets/disks/parity-disk-2 > /dev/null
echo -n $PARITY_DISK_3_KEY | sudo -S tee /etc/secrets/disks/parity-disk-3 > /dev/null
echo -n $BOOT_DISK_1_KEY | sudo -S tee /etc/secrets/disks/boot-disk-1 > /dev/null
echo -n $BOOT_DISK_2_KEY | sudo -S tee /etc/secrets/disks/boot-disk-2 > /dev/null
"""
echo -e "\n ✅ Encrypting secrets in the correct file..."
envsubst < "config-files/sops-nix/secrets.yaml" | sops encrypt --filename-override secrets.yaml \
--input-type yaml --output-type yaml \
--age $SOPS_PUBLIC_KEY \
--output extra-files/etc/nixos/secrets/secrets.yaml
cp -avu extra-files/etc/nixos/secrets/secrets.yaml ./nix-config/secrets/secrets.yaml
echo -e "\n ✅ Writing correct ips to configuration.nix..."
sed -i s+HOME_SERVER_IP+$HOME_SERVER_IP+g ./nix-config/configuration.nix
sed -i s+HOME_ROUTER_IP+$HOME_ROUTER_IP+g ./nix-config/configuration.nix
sed -i s+HOME_SERVER_IP+$HOME_SERVER_IP+g ./nix-config/misc/networking.nix
sed -i s+HOME_ROUTER_IP+$HOME_ROUTER_IP+g ./nix-config/misc/networking.nix
echo -e "\n ✅ Adapting the docker configuration to your hardware..."
FRIGATE_DEVICES_BLOCK=""
if [[ "$TARGET_GRAPHICS_RENDERER" == "true" ]]; then
FRIGATE_DEVICES_BLOCK+=" - /dev/dri:/dev/dri\n"
fi
if [[ "$TARGET_USB_CORAL" == "true" ]]; then
FRIGATE_DEVICES_BLOCK+=" - /dev/bus/usb:/dev/bus/usb\n"
fi
if [[ -n "$FRIGATE_DEVICES_BLOCK" ]]; then
REPLACEMENT="devices:\n${FRIGATE_DEVICES_BLOCK%\\n}"
sed -i.bak "s|# --- frigate devices --- #|$REPLACEMENT|" docker/frigate.original
else
sed -i.bak "/# --- frigate devices --- #/d" docker/frigate.original
fi
IMMICH_DEVICES_BLOCK=""
if [[ "$TARGET_GRAPHICS_RENDERER" == "true" ]]; then
IMMICH_DEVICES_BLOCK+=" - /dev/dri:/dev/dri\n"
fi
if [[ -n "$IMMICH_DEVICES_BLOCK" ]]; then
REPLACEMENT="devices:\n${IMMICH_DEVICES_BLOCK%\\n}"
sed -i.bak "s|# --- immich devices --- #|$REPLACEMENT|" docker/immich.original
else
sed -i.bak "/# --- immich devices --- #/d" docker/immich.original
fi
if [[ -n "$TARGET_ZIGBEE_DEVICE" ]]; then
REPLACEMENT="devices:\n - /dev/serial/by-id/${TARGET_ZIGBEE_DEVICE}:/dev/ttyUSB0"
sed -i.bak "s|# --- hass devices --- #|$REPLACEMENT|" docker/hass.original
else
sed -i.bak "/# --- hass devices --- #/d" docker/hass.original
fi
echo -e "\n ✅ Copying configuration files for the selected homelab services..."
cp docker/traefik.original docker/traefik.nix
for service in "${SERVICES[@]}"; do
cp docker/${service}.original docker/${service}.nix
done
echo -e "\n ✅ Writing docker configuration files..."
envsubst < config-files/docker/traefik/headers.yaml > extra-files/mnt/config-storage/traefik/config/conf/headers.yaml
envsubst < config-files/docker/traefik/nextcloud.yaml > extra-files/mnt/config-storage/traefik/config/conf/nextcloud.yaml
envsubst < config-files/docker/traefik/tls.yaml > extra-files/mnt/config-storage/traefik/config/conf/tls.yaml
envsubst < config-files/docker/traefik/traefik.yaml > extra-files/mnt/config-storage/traefik/config/traefik.yaml
envsubst < config-files/docker/hass/mosquitto.conf > extra-files/mnt/config-storage/hass/mqtt/config/mosquitto.conf
touch extra-files/mnt/config-storage/hass/mqtt/config/password.txt
chmod 0700 extra-files/mnt/config-storage/hass/mqtt/config/password.txt
mosquitto_passwd -b extra-files/mnt/config-storage/hass/mqtt/config/password.txt $HOME_ASSISTANT_MQTT_USER $HOME_ASSISTANT_MQTT_PASSWORD
echo -e "\n ✅ Copying the configuration to the new machine..."
cp -ravu ./nix-config/* extra-files/etc/nixos/
}
disk_config_generation() {
@@ -284,8 +262,6 @@ disk_config_generation() {
echo -e "\n\n 🔎 Fetching and analyzing disks from target host... (This may take a moment)"
### Disk wiping warning <--
### --> Get disk information
DISK_DETAILS=$(ssh darky "
# Declare arrays and variables
@@ -340,19 +316,17 @@ echo \"\${DISK_SIZE[@]}\"
read -r -a DISK_SIZE <<<"${LINES[5]}"
### Get disk information <--
### --> Disk selection
TOTAL_NUMBER_OF_DISKS=${#DISK_NAME[@]}
if [ "$TOTAL_NUMBER_OF_DISKS" -eq 0 ]; then
if [ "${#DISK_NAME[@]}" -eq 0 ]; then
echo -e "\n\n ❌ No disks found on the target host. Aborting."
exit 1
fi
HEADER=$(printf " %-12s %-12s %-12s %-12s %s" "Device" "Type" "Size" "SMART" "Path")
for i in $(seq 0 $((TOTAL_NUMBER_OF_DISKS-1))); do
for i in $(seq 0 $((${#DISK_NAME[@]} - 1))); do
GUM_PRINTED_ELEMENT=$(printf "%-12s %-12s %-12s %-12s %s" \
"${DISK_NAME[$i]}" "${DISK_TYPE[$i]}" "${DISK_SIZE[$i]}" \
"${DISK_HEALTH[$i]}" "${DISK_DEVPATH[$i]}")
@@ -363,13 +337,11 @@ echo \"\${DISK_SIZE[@]}\"
SELECTED_BOOT_DISK=$(gum choose --limit 2 --header "$HEADER" "${GUM_PRINTED_ELEMENTS[@]}")
j=0
for i in $(seq 0 $((TOTAL_NUMBER_OF_DISKS - 1))); do
for i in $(seq 0 $((${#DISK_NAME[@]} - 1))); do
if printf '%s' "$SELECTED_BOOT_DISK" | grep -iq "${DISK_NAME[$i]}"; then
((j++))
export declare "BOOT_DISK_${j}_ID=${DISK_ID[$i]}"
unset "GUM_PRINTED_ELEMENTS[${i}]"
((NUMBER_OF_BOOT_DISKS++))
export declare "BOOT_DISK_${NUMBER_OF_BOOT_DISKS}_ID=${DISK_ID[$i]}"
unset "GUM_PRINTED_ELEMENTS[${i}]"
fi
done
@@ -387,7 +359,7 @@ echo \"\${DISK_SIZE[@]}\"
SELECTED_DATA_DISK=$(gum choose --limit 9 --header "$HEADER" "${GUM_PRINTED_ELEMENTS[@]}")
for i in $(seq 0 $((TOTAL_NUMBER_OF_DISKS - 1))); do
for i in $(seq 0 $((${#DISK_NAME[@]} - 1))); do
if printf '%s' "$SELECTED_DATA_DISK" | grep -iq "${DISK_NAME[$i]}"; then
((NUMBER_OF_DATA_DISKS++))
fi
@@ -398,23 +370,26 @@ echo \"\${DISK_SIZE[@]}\"
elif [[ "$NUMBER_OF_DATA_DISKS" == "1" ]]; then
echo -e "\n\n ⚠️ One data disk selected, continuing with striped boot disk configuration."
echo -e " Consider using AT LEAST 2 data disks instead to get data protection features on the data disks."
for i in $(seq 0 $((TOTAL_NUMBER_OF_DISKS - 1))); do
for i in $(seq 0 $((${#DISK_NAME[@]} - 1))); do
if printf '%s' "$SELECTED_DATA_DISK" | grep -iq "${DISK_NAME[$i]}"; then
NUMBER_OF_CONTENT_DISKS="1"
NUMBER_OF_PARITY_DISKS="0"
export CONTENT_DISK_1_ID="${DISK_ID[$i]}"
export DISK_1_ID_LIST+=(${CONTENT_DISK_1_ID})
fi
done
elif [[ "$NUMBER_OF_DATA_DISKS" == "2" ]]; then
NUMBER_OF_CONTENT_DISKS="0"
for i in $(seq 0 $((TOTAL_NUMBER_OF_DISKS - 1))); do
for i in $(seq 0 $((${#DISK_NAME[@]} - 1))); do
if printf '%s' "$SELECTED_DATA_DISK" | grep -iq "${DISK_NAME[$i]}"; then
if [[ "$NUMBER_OF_CONTENT_DISKS" == "0" ]]; then
NUMBER_OF_CONTENT_DISKS="1"
export CONTENT_DISK_1_ID="${DISK_ID[$i]}"
export DISK_ID_LIST+=(${CONTENT_DISK_1_ID})
else
NUMBER_OF_PARITY_DISKS="1"
export PARITY_DISK_1_ID="${DISK_ID[$i]}"
export DISK_ID_LIST+=(${PARITY_DISK_1_ID})
fi
fi
done
@@ -425,14 +400,16 @@ echo \"\${DISK_SIZE[@]}\"
k="$NUMBER_OF_CONTENT_DISKS"
l="1"
m="1"
for i in $(seq 0 $((TOTAL_NUMBER_OF_DISKS - 1))); do
for i in $(seq 0 $((${#DISK_NAME[@]} - 1))); do
if printf '%s' "$SELECTED_DATA_DISK" | grep -iq "${DISK_NAME[$i]}"; then
if [[ "$k" -gt 0 ]]; then
declare "CONTENT_DISK_${l}_ID=${DISK_ID[$i]}"
export DISK_ID_LIST+=(${CONTENT_DISK_${l}_ID})
k=$((k - 1))
((l++))
elif [[ "$j" -gt 0 ]]; then
declare "PARITY_DISK_${m}_ID=${DISK_ID[$i]}"
export DISK_ID_LIST+=(${PARITY_DISK_${m}_ID})
j=$((j - 1))
((m++))
fi
@@ -441,8 +418,6 @@ echo \"\${DISK_SIZE[@]}\"
fi
### Disk selection <--
### --> Selection recap
RECAP_CONTENT=$(cat <<EOF
### Disk Configuration Summary
@@ -467,31 +442,31 @@ EOF
gum confirm "Proceed with this disk configuration?" || { echo -e "\n\n ❌ Aborting as requested."; exit 1; }
### Selection recap <--
### --> Config generation
echo -e "\n\n ✅ Generating disko configuration from templates..."
TEMPLATE_FILE="config-files/disks/boot-${NUMBER_OF_BOOT_DISKS}.nix"
TEMPLATE_FILE="config-files/disks/templates/boot-${NUMBER_OF_BOOT_DISKS}.nix"
(envsubst < "$TEMPLATE_FILE") > ./nix-config/disks/disko.nix
echo -e "\n ✅ Generated boot disk configuration."
# Mirror configuration
if [[ "$NUMBER_OF_CONTENT_DISKS" == 1 && "$NUMBER_OF_PARITY_DISKS" == 1 ]]; then
(envsubst < "config-files/disks/mirror.nix") >> ./nix-config/disks/disko.nix
(envsubst < "config-files/disks/templates/mirror.nix") >> ./nix-config/disks/disko.nix
# SnapRAID configuration
elif [[ "$NUMBER_OF_CONTENT_DISKS" -gt 0 ]]; then
(envsubst < "nix-config/disks/snapraid.nix") >> ./nix-config/disks/snapraid.nix
sed -i "s|# ./disks/snapraid.nix| ./disks/snapraid.nix|" ./nix-config/configuration.nix
for i in $(seq 1 $NUMBER_OF_CONTENT_DISKS); do
export i
LOOP_DISK="CONTENT_DISK_${i}_ID"
export CONTENT_DISK_ID=${!LOOP_DISK}
(envsubst < "config-files/disks/content.nix") >> ./nix-config/disks/disko.nix
(envsubst < "config-files/disks/templates/content.nix") >> ./nix-config/disks/disko.nix
done
echo -e "\n ✅ Generated $NUMBER_OF_CONTENT_DISKS data disk configuration(s)."
for i in $(seq 1 $NUMBER_OF_PARITY_DISKS); do
export i
LOOP_DISK="PARITY_DISK_${i}_ID"
export PARITY_DISK_ID=${!LOOP_DISK}
(envsubst < "config-files/disks/parity.nix") >> ./nix-config/disks/disko.nix
(envsubst < "config-files/disks/templates/parity.nix") >> ./nix-config/disks/disko.nix
done
echo -e "\n ✅ Generated $NUMBER_OF_PARITY_DISKS parity disk configuration(s)."
fi
@@ -504,14 +479,12 @@ EOF
echo -e "\n ✅ Final disko configuration created."
### Config generation <--
### --> Generate automatic unlock configuration
if [[ "$NUMBER_OF_CONTENT_DISKS" -gt 1 && "$NUMBER_OF_PARITY_DISKS" -gt 0 ]]; then
echo -e "\n ✅ Generating automatic disk unlocking configuration..."
sed -i '$ d' ./nix-config/disks/snapraid.nix
sed -i '$ d' ./config-files/disks/snapraid.nix
cat <<EOF >> ./nix-config/disks/snapraid.nix
cat <<EOF >> ./config-files/disks/snapraid.nix
# --> Automatic data disks unlock, generated by deploy.sh on $(date)
boot.initrd.luks.devices = {
EOF
@@ -519,7 +492,7 @@ EOF
if [[ "$NUMBER_OF_CONTENT_DISKS" -gt 0 ]]; then
for i in $(seq 1 $NUMBER_OF_CONTENT_DISKS); do
LOOP_DISK="CONTENT_DISK_$i"
cat <<EOF >> ./nix-config/disks/snapraid.nix
cat <<EOF >> ./config-files/disks/snapraid.nix
"crypted-content-disk-${i}" = {
device = "${!LOOP_DISK}";
keyFile = "/etc/secrets/disks/content-disk-${i}";
@@ -531,7 +504,7 @@ EOF
if [[ "$NUMBER_OF_PARITY_DISKS" -gt 0 ]]; then
for i in $(seq 1 $NUMBER_OF_PARITY_DISKS); do
LOOP_DISK="PARITY_DISK_$i"
cat <<EOF >> ./nix-config/disks/snapraid.nix
cat <<EOF >> ./config-files/disks/snapraid.nix
"crypted-parity-disk-${i}" = {
device = "${!LOOP_DISK}";
keyFile = "/etc/secrets/disks/parity-disk-${i}";
@@ -540,13 +513,27 @@ EOF
done
fi
cat <<'EOF' >> ./nix-config/disks/snapraid.nix
cat <<'EOF' >> ./config-files/disks/snapraid.nix
# Automatic data disks unlock <--
};
}
EOF
fi
cp -avu ./config-files/disks/snapraid.nix ./nixos-config/disks/
### Generate automatic unlock configuration <--
### --> Generate unlock keys
for i in $NUMBER_OF_BOOT_DISKS; do
declare "/etc/secrets/disks/boot-disk-${i}=$(xkcdpass -d "-")"
done
for i in $NUMBER_OF_CONTENT_DISKS; do
declare "/etc/secrets/disks/content-disk-${i}=$(xkcdpass -d "-")"
done
for i in $NUMBER_OF_PARITY_DISKS; do
declare "/etc/secrets/disks/parity-disk-${i}=$(xkcdpass -d "-")"
done
### Generate unlock keys <--
}
deploy() {
@@ -555,7 +542,7 @@ deploy() {
--generate-hardware-config nixos-generate-config ./nix-config/hardware-configuration.nix \
--flake ./nix-config#numbus-server \
--extra-files extra-files \
--chown "/home/numbus-admin/" 1000:1000 \
--chown "/home/numbusing a us-admin/" 1000:1000 \
--target-host nixos@$TARGET_HOST
echo -e "\n\n ✅ Installation successfull !"
@@ -590,7 +577,12 @@ EOF
}
postrun_action() {
echo ""
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."
gum spin --spinner dot --title "Rebooting the remote..." -- sleep 60
ssh
# Add TPM2 boot disk decryption
# Add pcr-check.nix
}
@@ -663,8 +655,7 @@ elif [[ "$ACTION_ANSWER" == "[2] 💽 Deploy NixOS on a remote machine with a fi
elif [[ "$ACTION_ANSWER" == "[3] 🛠️ Update a NixOS remote machine" ]]; then
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
to update is up-and-running, accessible with SSH.
"
to update is up-and-running, accessible with SSH."
gum confirm "Do you understand and wish to proceed?" || { echo " ❌ Aborting as requested."; exit 1; }
nixos_update
else