Huge update. Reorganized folders. Added post-install logic. Have to do testing to check if everything works.
This commit is contained in:
+2
-3
@@ -1,5 +1,4 @@
|
||||
agents/
|
||||
ai-production/
|
||||
extra-files/
|
||||
test*
|
||||
deploy.conf
|
||||
final-nix-config/
|
||||
test*
|
||||
@@ -1,16 +0,0 @@
|
||||
#TARGET SETTINGS
|
||||
TARGET_HOST="192.168.1.10"
|
||||
SSH_PUBLIC_KEY="ssh-ed25519 AAAAoefzefpoipoeCEZJCPEACPAcjapjcpajepcjAPJECJPEJAPJAZ yours@yourdomain.com"
|
||||
# TRAEFIK SETTINGS
|
||||
DOMAIN_NAME="yourdomain.com"
|
||||
EMAIL_ADDRESS="your-mail@yourdomain.com"
|
||||
CF_DNS_API_TOKEN="yourToken"
|
||||
#SMTP SETTINGS
|
||||
SENDER_EMAIL_ADDRESS="youraddress@gmail.com"
|
||||
SENDER_EMAIL_ADDRESS_PASSWORD="emrp raps vzoi vnoe"
|
||||
SENDER_EMAIL_DOMAIN="smtp.yourdomain.com"
|
||||
SENDER_EMAIL_PORT="587"
|
||||
#NETWORK SETTINGS
|
||||
HOME_ROUTER_SUBNET="192.168.1.0/24"
|
||||
HOME_ROUTER_IP="192.168.1.1"
|
||||
HOME_SERVER_IP="192.168.1.5"
|
||||
@@ -1,9 +0,0 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!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")
|
||||
@@ -1,66 +0,0 @@
|
||||
ssh_public_keys: $SSH_PUBLIC_KEY
|
||||
sender_email_address_password: $SENDER_EMAIL_ADDRESS_PASSWORD
|
||||
|
||||
docker:
|
||||
nextcloud: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
NEXTCLOUD_ENABLE_DRI_DEVICE=$TARGET_GRAPHICS
|
||||
frigate: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
FRIGATE_MQTT_USER=$HOME_ASSISTANT_MQTT_USER
|
||||
FRIGATE_MQTT_PASSWORD=$HOME_ASSISTANT_MQTT_PASSWORD
|
||||
traefik: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
CF_DNS_API_TOKEN=$CF_DNS_API_TOKEN
|
||||
hass: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
HOME_ASSISTANT_MQTT_USER=$HOME_ASSISTANT_MQTT_USER
|
||||
HOME_ASSISTANT_MQTT_PASSWORD=$HOME_ASSISTANT_MQTT_PASSWORD
|
||||
passbolt: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
TZ=Europe/Paris
|
||||
PASSBOLT_MYSQL_DATABASE=$PASSBOLT_DB_NAME
|
||||
PASSBOLT_MYSQL_USER=$PASSBOLT_DB_USERNAME
|
||||
PASSBOLT_MYSQL_PASSWORD=$PASSBOLT_DB_PASSWORD
|
||||
SENDER_EMAIL_ADDRESS=$SENDER_EMAIL_ADDRESS
|
||||
SENDER_EMAIL_ADDRESS_PASSWORD=$SENDER_EMAIL_ADDRESS_PASSWORD
|
||||
SENDER_EMAIL_DOMAIN=$SENDER_EMAIL_DOMAIN
|
||||
SENDER_EMAIL_PORT=$SENDER_EMAIL_PORT
|
||||
EMAIL_ADDRESS=$EMAIL_ADDRESS
|
||||
pihole: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
TZ=Europe/Paris
|
||||
HOME_ROUTER_SUBNET=$HOME_ROUTER_SUBNET
|
||||
HOME_ROUTER_IP=$HOME_ROUTER_IP
|
||||
HOME_SERVER_IP=$HOME_SERVER_IP
|
||||
FTLCONF_webserver_api_password=$FTLCONF_WEBSERVER_PASSWORD
|
||||
immich: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
TZ=Europe/Paris
|
||||
UPLOAD_LOCATION=/mnt/data-storage/docker-data/immich
|
||||
IMMICH_VERSION=release
|
||||
IMMICH_TRUSTED_PROXIES=172.16.50.253
|
||||
REDIS_HOSTNAME=immich-redis
|
||||
DB_HOSTNAME=immich-database
|
||||
DB_DATABASE_NAME=$IMMICH_DB_NAME
|
||||
DB_USERNAME=$IMMICH_DB_USERNAME
|
||||
DB_PASSWORD=$IMMICH_DB_PASSWORD
|
||||
DB_DATA_LOCATION=/mnt/config-storage/docker-data/immich/database
|
||||
gitea: |
|
||||
DOMAIN_NAME=$DOMAIN_NAME
|
||||
POSTGRES_HOST=gitea-database
|
||||
POSTGRES_PORT=5432
|
||||
DB_NAME=$GITEA_DB_NAME
|
||||
DB_USERNAME=$GITEA_DB_USERNAME
|
||||
DB_PASSWORD=$GITEA_DB_PASSWORD
|
||||
|
||||
disks:
|
||||
content-disk-1: $CONTENT_DISK_1_KEY
|
||||
content-disk-2: $CONTENT_DISK_2_KEY
|
||||
content-disk-3: $CONTENT_DISK_3_KEY
|
||||
content-disk-4: $CONTENT_DISK_4_KEY
|
||||
content-disk-5: $CONTENT_DISK_5_KEY
|
||||
content-disk-6: $CONTENT_DISK_6_KEY
|
||||
parity-disk-1: $PARITY_DISK_1_KEY
|
||||
parity-disk-2: $PARITY_DISK_2_KEY
|
||||
parity-disk-3: $PARITY_DISK_3_KEY
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
#TARGET SETTINGS
|
||||
TARGET_HOST="192.168.1.10"
|
||||
TARGET_SSH_PUBLIC_KEY="ssh-ed25519 AAAAoefzefpoipoeCEZJCPEACPAcjapjcpajepcjAPJECJPEJAPJAZ yours@yourdomain.com"
|
||||
# TRAEFIK SETTINGS
|
||||
DOMAIN_NAME="yourdomain.com"
|
||||
DOMAIN_EMAIL_ADDRESS="your-mail@yourdomain.com"
|
||||
DOMAIN_CF_DNS_API_TOKEN="yourToken"
|
||||
#SMTP SETTINGS
|
||||
SENDER_EMAIL_ADDRESS="youraddress@gmail.com"
|
||||
SENDER_EMAIL_ADDRESS_PASSWORD="emrp raps vzoi vnoe"
|
||||
SENDER_EMAIL_DOMAIN="smtp.yourdomain.com"
|
||||
SENDER_EMAIL_PORT="587"
|
||||
#NETWORK SETTINGS
|
||||
NETWORK_HOME_ROUTER_SUBNET="192.168.1.0/24"
|
||||
NETWORK_HOME_ROUTER_IP="192.168.1.1"
|
||||
NETWORK_HOME_SERVER_IP="192.168.1.5"
|
||||
@@ -1,266 +1,321 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gum xkcdpass sops ssh-to-age age sshpass envsubst pciutils usbutils mosquitto
|
||||
#!nix-shell -i bash -p gum fastfetch 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" \
|
||||
|
||||
|
||||
### --> Default settings
|
||||
export GUM_SPIN_SPINNER="minidot"
|
||||
export GUM_SPIN_SPINNER_BOLD=true
|
||||
export GUM_SPIN_SHOW_ERROR=true
|
||||
export GUM_SPIN_TITLE_BOLD=true
|
||||
|
||||
NECESSARY_VARIABLES_LIST=("TARGET_HOST" "REMOTE_PASS" "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")
|
||||
### Default settings <--
|
||||
|
||||
INSTALLED_REMOTE_PASS="changeMe!"
|
||||
|
||||
necessary_credentials() {
|
||||
#TARGET SETTINGS
|
||||
echo -e "\n\n ➡️ Please provide the IP address of the target host :"
|
||||
export TARGET_HOST="$(gum input --placeholder "192.168.1.100")"
|
||||
echo -e "\n\n ➡️ Please provide the public SSH key of an authorized device :"
|
||||
export SSH_PUBLIC_KEY="$(gum input --placeholder "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGhcYDmjMo5YApLkk/3P3HZCnOSzm0uYewNAbxL8Fci8 user@your-pc")"
|
||||
|
||||
# TRAEFIK SETTINGS
|
||||
echo -e "\n\n ➡️ Please provide the domain name (FQDN) your home server will use :"
|
||||
export DOMAIN_NAME="$(gum input --placeholder "yourdomain.com")"
|
||||
echo -e "\n\n ➡️ Please provide a valid email address (will be used for ACME, and your services) :"
|
||||
export EMAIL_ADDRESS="$(gum input --placeholder "myemail@gmail.com")"
|
||||
echo -e "\n\n ➡️ Please provide a cloudflare API token with DNS zone permission :"
|
||||
export CF_DNS_API_TOKEN="$(gum input --placeholder "bA7hdvCOuXGytlNKohi3ZGtlVpf5CHpLuCMiJrE")"
|
||||
user_input() {
|
||||
local VAR_NAME="${1}"
|
||||
local HEADER="${2}"
|
||||
local PLACEHOLDER="${3}"
|
||||
local REGEX="${4}"
|
||||
local ERROR_MSG="${5}"
|
||||
local SENSITIVE="${6:-false}"
|
||||
|
||||
# SMTP SETTINGS
|
||||
echo -e "\n\n ➡️ Some services will be able to send you emails. For that you need an email that supports sending emails.\n Please provide a valid sender email address :"
|
||||
export SENDER_EMAIL_ADDRESS="$(gum input --placeholder "myemail@gmail.com")"
|
||||
echo -e "\n\n ➡️ Please provide the password of this email address :"
|
||||
export SENDER_EMAIL_ADDRESS_PASSWORD="$(gum input --placeholder "abcd efgh ijkl mnop")"
|
||||
echo -e "\n\n ➡️ Please provide the SMTP server endpoint :"
|
||||
export SENDER_EMAIL_DOMAIN="$(gum input --placeholder "smtp.gmail.com")"
|
||||
echo -e "\n\n ➡️ Please provide the smtp TLS port (for gmail : 587) :"
|
||||
export SENDER_EMAIL_PORT="$(gum input --placeholder "587")"
|
||||
while true; do
|
||||
[[ "$SENSITIVE" -eq "true" ]] && INPUT_VALUE=$(gum input --placeholder "${PLACEHOLDER}" --header "${HEADER}")
|
||||
[[ "$SENSITIVE" -eq "false" ]] && INPUT_VALUE=$(gum input --password --placeholder "${PLACEHOLDER}" --header "${HEADER}")
|
||||
|
||||
# NETWORK SETTINGS
|
||||
echo -e "\n\n ➡️ Please provide your home network subnet :"
|
||||
export HOME_ROUTER_SUBNET="$(gum input --placeholder "192.168.1.1/24")"
|
||||
echo -e "\n\n ➡️ Please provide the ip address of your router :"
|
||||
export HOME_ROUTER_IP="$(gum input --placeholder "192.168.1.1")"
|
||||
echo -e "\n\n ➡️ Please choose the ip address that your server will use (i.e. any address in the 192.168.1.1/24 range that is not in use.) :"
|
||||
export HOME_SERVER_IP="$(gum input --placeholder "192.168.1.5")"
|
||||
if [[ -z "${INPUT_VALUE}" ]]; then
|
||||
echo "❌ Error: Input cannot be empty. Please provide the necessary information."
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ -n "${REGEX}" ]]; then
|
||||
if [[ ! "${INPUT_VALUE}" =~ ${REGEX} ]]; then
|
||||
echo "❌ Error: ${ERROR_MSG}"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
export "${VAR_NAME}"="${INPUT_VALUE}"
|
||||
break
|
||||
done
|
||||
}
|
||||
|
||||
necessary_credentials_with_config() {
|
||||
echo -e "\n\n ➡️ Please choose your configuration file :"
|
||||
CONFIG_PATH="$(gum file)"
|
||||
|
||||
source "$CONFIG_PATH"
|
||||
MISSING=0
|
||||
|
||||
necessary_credentials() {
|
||||
# Regex Definitions
|
||||
local IP_REGEX='^([0-9]{1,3}\.){3}[0-9]{1,3}$'
|
||||
local SUBNET_REGEX='^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$'
|
||||
local DOMAIN_REGEX='^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$'
|
||||
local EMAIL_REGEX='^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
|
||||
local PORT_REGEX='^[0-9]{1,5}$'
|
||||
local SSH_KEY_REGEX='^ssh-[a-z0-9]+ [A-Za-z0-9+/]+.*'
|
||||
|
||||
#TARGET SETTINGS
|
||||
user_input "TARGET_HOST" "➡️ Please provide the IP address of the target host :" "192.168.1.100" "${IP_REGEX}" "Invalid IP address format."
|
||||
user_input "REMOTE_PASS" "➡️ Please enter the password for '${TARGET_USER}@${TARGET_HOST}' :" "${TARGET_HOST}'s password" "" "" "true"
|
||||
user_input "SSH_PUBLIC_KEY" "➡️ Please provide the public SSH key of an authorized device :" "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGhcYDmjMo5YApLkk/3P3HZCnOSzm0uYewNAbxL8Fci8 user@your-pc" "${SSH_KEY_REGEX}" "Invalid SSH key format (must start with ssh-...)."
|
||||
|
||||
# TRAEFIK SETTINGS
|
||||
user_input "DOMAIN_NAME" "➡️ Please provide the domain name (FQDN) your home server will use :" "yourdomain.com" "${DOMAIN_REGEX}" "Invalid domain name format."
|
||||
user_input "EMAIL_ADDRESS" "➡️ Please provide a valid email address (will be used for ACME, and your services) :" "myemail@gmail.com" "${EMAIL_REGEX}" "Invalid email address format."
|
||||
user_input "CF_DNS_API_TOKEN" "➡️ Please provide a cloudflare API token with DNS zone permission :" "bA7hdvCOuXGytlNKohi3ZGtlVpf5CHpLuCMiJrE" "" ""
|
||||
|
||||
# SMTP SETTINGS
|
||||
echo -e "\n\n➡️ Some services will be able to send you emails. For that you need an email that supports sending emails (like Gmail for example)."
|
||||
user_input "SENDER_EMAIL_ADDRESS" "➡️ Please provide a valid sender email address :" "myemail@gmail.com" "${EMAIL_REGEX}" "Invalid email address format."
|
||||
user_input "SENDER_EMAIL_ADDRESS_PASSWORD" "➡️ Please provide the password of this email address :" "abcd efgh ijkl mnop" "" ""
|
||||
user_input "SENDER_EMAIL_DOMAIN" "➡️ Please provide the SMTP server endpoint :" "smtp.gmail.com" "${DOMAIN_REGEX}" "Invalid domain name format."
|
||||
user_input "SENDER_EMAIL_PORT" "➡️ Please provide the smtp TLS port (for gmail : 587) :" "587" "${PORT_REGEX}" "Invalid port number."
|
||||
|
||||
# NETWORK SETTINGS
|
||||
user_input "HOME_ROUTER_SUBNET" "➡️ Please provide your home network subnet :" "192.168.1.1/24" "${SUBNET_REGEX}" "Invalid subnet format (e.g. 192.168.1.1/24)."
|
||||
user_input "HOME_ROUTER_IP" "➡️ Please provide the ip address of your router :" "192.168.1.1" "${IP_REGEX}" "Invalid IP address format."
|
||||
user_input "HOME_SERVER_IP" "➡️ Please choose the ip address that your server will use (i.e. any address in the 192.168.1.1/24 range that is not in use.) :" "192.168.1.5" "${IP_REGEX}" "Invalid IP address format."
|
||||
}
|
||||
|
||||
|
||||
|
||||
necessary_credentials_with_config() {
|
||||
echo -e "\n\n➡️ Please choose your configuration file :"
|
||||
local CONFIG_PATH="$(gum file)"
|
||||
|
||||
source "${CONFIG_PATH}"
|
||||
local MISSING=0
|
||||
for VAR in "${NECESSARY_VARIABLES_LIST[@]}"; do
|
||||
if [[ -v $VAR && -n ${!VAR} ]]; then
|
||||
echo -e "\n ✅ $VAR imported successfully from the config file"
|
||||
export $VAR
|
||||
if [[ -v "${VAR}" && -n "${!VAR}" ]]; then
|
||||
gum spin --title "✅ "${VAR}" imported successfully from the config file" -- sleep 0.5
|
||||
else
|
||||
echo "\n ❌ $VAR is missing or empty"
|
||||
gum spin --title "❌ "${VAR}" is missing or empty" -- sleep 0.5
|
||||
MISSING=1
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ "$MISSING" -eq "1" ]]; then
|
||||
if [[ "${MISSING}" -eq "1" ]]; then
|
||||
echo -e "\n❌ Please check your configuration file to include all necessary variables"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
|
||||
generate_folder_tree() {
|
||||
mkdir -p final-nix-config/
|
||||
mkdir -p final-nix-config/home/
|
||||
mkdir -p final-nix-config/home/numbus-admin/
|
||||
mkdir -p final-nix-config/home/numbus-admin/.ssh/
|
||||
|
||||
mkdir -p final-nix-config/mnt/
|
||||
mkdir -p final-nix-config/mnt/config/
|
||||
mkdir -p final-nix-config/mnt/data/
|
||||
|
||||
mkdir -p final-nix-config/mnt/config/traefik/
|
||||
mkdir -p final-nix-config/mnt/config/traefik/rules/
|
||||
mkdir -p final-nix-config/mnt/config/traefik/certs/
|
||||
|
||||
mkdir -p final-nix-config/etc/
|
||||
mkdir -p final-nix-config/etc/nixos/
|
||||
mkdir -p final-nix-config/etc/secrets/
|
||||
mkdir -p final-nix-config/etc/numbus-server/
|
||||
mkdir -p final-nix-config/etc/nixos/misc/
|
||||
mkdir -p final-nix-config/etc/nixos/pcie-coral/
|
||||
mkdir -p final-nix-config/etc/nixos/podman/
|
||||
mkdir -p final-nix-config/etc/nixos/secrets/
|
||||
|
||||
mkdir -p final-nix-config/var/
|
||||
mkdir -p final-nix-config/var/lib/
|
||||
mkdir -p final-nix-config/var/lib/sops-nix
|
||||
}
|
||||
|
||||
|
||||
|
||||
setup_ssh() {
|
||||
echo -e "\n\n ✅ Generating new SSH for numbus-admin..."
|
||||
mkdir -p 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
|
||||
echo -e "\n\n✅ Generating new SSH key for numbus-admin..."
|
||||
chmod 700 final-nix-config/home/numbus-admin/.ssh/
|
||||
ssh-keygen -t "ed25519" -C "numbus-admin@numbus-server" -f "final-nix-config/home/numbus-admin/.ssh/id_ed25519" -N "" -q
|
||||
|
||||
LIVE_REMOTE_PASS=$(gum input --password --placeholder "Enter password for 'nixos@$TARGET_HOST'")
|
||||
if [ -z "$LIVE_REMOTE_PASS" ]; then
|
||||
echo " ❌ Password is required to proceed. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
echo -e "\n\n ➡️ Copying SSH key to target host 'nixos@$TARGET_HOST'..."
|
||||
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 -e "\n\n➡️ Copying SSH key to target host '${TARGET_USER}@${TARGET_HOST}'..."
|
||||
if sshpass -p "${REMOTE_PASS}" ssh-copy-id -o StrictHostKeyChecking=no -i "final-nix-config/home/numbus-admin/.ssh/id_ed25519" "${TARGET_USER}@${TARGET_HOST}"; then
|
||||
echo "✅ SSH key copied successfully."
|
||||
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
|
||||
fi
|
||||
export LIVE_REMOTE_PASS
|
||||
}
|
||||
|
||||
ssh_to_live_host() {
|
||||
ARG="$1"
|
||||
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
|
||||
|
||||
ssh_to_host() {
|
||||
local COMMAND="${1}"
|
||||
ssh -i "final-nix-config/home/numbus-admin/.ssh/id_ed25519" "${TARGET_USER}@${TARGET_HOST}" "${COMMAND}"
|
||||
}
|
||||
|
||||
hardware_detection() {
|
||||
echo -e "\n\n 🔎 Detecting graphics card on target host..."
|
||||
VGA_INFO=$(ssh_to_live_host "lspci -nn | grep -i 'vga'")
|
||||
if echo "$VGA_INFO" | grep -iq "intel" 2>/dev/null; then
|
||||
echo -e " ✅ Intel graphics card detected."
|
||||
export TARGET_GRAPHICS="true"
|
||||
elif echo "$VGA_INFO" | grep -iq "amd" 2>/dev/null; then
|
||||
echo -e " ✅ AMD graphics card detected."
|
||||
export TARGET_GRAPHICS="true"
|
||||
elif echo "$VGA_INFO" | grep -iq "nvidia" 2>/dev/null; then
|
||||
echo -e " ✅ NVIDIA graphics card detected."
|
||||
export TARGET_GRAPHICS="true"
|
||||
### --> Get hardware information
|
||||
local TMPFILE="/tmp/nixos-installation-hardware-detection-temp-file"
|
||||
|
||||
ssh_to_host 'bash -s' << SSHEND
|
||||
for brand in Intel AMD NVIDIA; do
|
||||
if [[ lspci -nn | grep -i "vga" | grep -iq "\${brand}" ]]; then
|
||||
TARGET_GRAPHICS="true"
|
||||
TARGET_GRAPHICS_BRAND+=("\${brand}")
|
||||
else
|
||||
echo -e " ⚠️ No dedicated graphics card detected."
|
||||
export TARGET_GRAPHICS="false"
|
||||
TARGET_GRAPHICS="false"
|
||||
fi
|
||||
echo -e "\n\n 🔎 Detecting transconding acceleration on target host..."
|
||||
if ssh_to_live_host "ls /dev/dri/ | grep -iq 'renderD128'" 2>/dev/null; then
|
||||
echo -e " ✅ Transcoding capable card detected."
|
||||
TARGET_GRAPHICS_RENDERER="true"
|
||||
done
|
||||
|
||||
[[ ls /dev/dri/ | grep -iq "renderD128" ]] && TARGET_GRAPHICS_RENDERER="true" || TARGET_GRAPHICS_RENDERER="false"
|
||||
[[ lsusb | grep -iq "google" ]] && TARGET_USB_CORAL="true" || TARGET_USB_CORAL="false"
|
||||
[[ lspci -nn | grep -iq "089a" ]] && TARGET_PCIE_CORAL="true" || TARGET_PCIE_CORAL="false"
|
||||
[[ ls /dev/serial/by-id/ | grep -i "zigbee" ]] && TARGET_ZIGBEE_DEVICE=\$(ls /dev/serial/by-id/ | grep -i "zigbee" | head -n 1) || TARGET_ZIGBEE_DEVICE=""
|
||||
|
||||
for var in TARGET_GRAPHICS TARGET_GRAPHICS_BRAND TARGET_GRAPHICS_RENDERER TARGET_USB_CORAL TARGET_PCIE_CORAL TARGET_ZIGBEE_DEVICE; do
|
||||
echo "export \${var}=\${!var}" >> "${TMPFILE}"
|
||||
done
|
||||
SSHEND
|
||||
### Get hardware information <--
|
||||
|
||||
scp -i "final-nix-config/home/numbus-admin/.ssh/id_ed25519" "${TARGET_USER}@${TARGET_HOST}":"${TMPFILE}" "${TMPFILE}" &> /dev/null
|
||||
source "${TMPFILE}" && rm "${TMPFILE}"
|
||||
|
||||
### --> Generate hardware-configuration.nix
|
||||
echo -e "\n\n 🔎 Generating hardware-configuration.nix from target host..."
|
||||
if ssh_to_host "sudo nixos-generate-config --no-filesystems --show-hardware-config" > final-nix-config/etc/nixos/hardware-configuration.nix; then
|
||||
echo -e "✅ Hardware configuration generated"
|
||||
else
|
||||
echo -e " ⚠️ No transcoding capable card detected."
|
||||
TARGET_GRAPHICS_RENDERER="false"
|
||||
fi
|
||||
echo -e "\n\n 🔎 Detecting USB Google Coral TPU on target host..."
|
||||
if ssh_to_live_host "lsusb | grep -iq 'google'" 2>/dev/null; then
|
||||
echo -e " ✅ USB Google Coral TPU detected."
|
||||
TARGET_USB_CORAL="true"
|
||||
else
|
||||
echo -e " ⚠️ No USB Google Coral TPU detected."
|
||||
TARGET_USB_CORAL="false"
|
||||
fi
|
||||
echo -e "\n\n 🔎 Detecting Zigbee coordinator on target host..."
|
||||
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/."
|
||||
TARGET_ZIGBEE_DEVICE=$(ssh_to_live_host "ls /dev/serial/by-id/ | grep -i 'zigbee'")
|
||||
else
|
||||
echo -e " ⚠️ No Zigbee device found."
|
||||
TARGET_ZIGBEE_DEVICE=""
|
||||
echo -e "❌ Failed to generate hardware configuration"
|
||||
exit 1
|
||||
fi
|
||||
### Generate hardware-configuration.nix <--
|
||||
}
|
||||
|
||||
services_selection() {
|
||||
echo -e "\n\n ➡️ You will now select the services you want installed on your server:"
|
||||
echo -e "\n\n➡️ You will now select the services you want installed on your server:"
|
||||
|
||||
AVAILABLE_SERVICES=( "frigate" "gitea" "home-assistant" "immich" "it-tools" \
|
||||
local AVAILABLE_SERVICES=( "frigate" "gitea" "home-assistant" "immich" "it-tools" \
|
||||
"nextcloud" "passbolt" "pi-hole" )
|
||||
AVAILABLE_SERVICES_NUMBER=${#AVAILABLE_SERVICES[@]}
|
||||
|
||||
SERVICES_DESCRIPTION=( "Pi-Hole : Block ads on all your devices" \
|
||||
local 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" \
|
||||
)
|
||||
"IT-tools : A set of useful tools when doing IT"
|
||||
)
|
||||
|
||||
SELECTED_SERVICES_DESCRIPTION=$(gum choose --no-limit --header "Homelab services:" "${SERVICES_DESCRIPTION[@]}")
|
||||
local SELECTED_SERVICES_DESCRIPTION=$(gum choose --no-limit --header "Homelab services:" "${SERVICES_DESCRIPTION[@]}")
|
||||
|
||||
for i in $(seq 0 $((${#AVAILABLE_SERVICES[@]} - 1))); do
|
||||
for i in ${!AVAILABLE_SERVICES[@]}; do
|
||||
if printf '%s' "$SELECTED_SERVICES_DESCRIPTION" | grep -iq "${AVAILABLE_SERVICES[$i]}"; then
|
||||
SELECTED_SERVICES+=(${AVAILABLE_SERVICES[$i]})
|
||||
export SELECTED_SERVICES+=(${AVAILABLE_SERVICES[$i]})
|
||||
fi
|
||||
done
|
||||
|
||||
for service in ${SELECTED_SERVICES[@]}; do
|
||||
mkdir -p final-nix-config/mnt/config/"${service}"
|
||||
mkdir -p final-nix-config/mnt/data/"${service}"
|
||||
done
|
||||
}
|
||||
|
||||
files_generation() {
|
||||
echo -e "\n ✅ Writing configuration files for the selected homelab services..."
|
||||
# Traefik
|
||||
mkdir -p extra-files/mnt/config-storage/traefik/config/conf/
|
||||
envsubst < config-files/docker/config/traefik/traefik.yaml > extra-files/mnt/config-storage/traefik/config/traefik.yaml
|
||||
# Helper to generate standard DB credentials
|
||||
generate_db_creds() {
|
||||
local SERVICE_UPPER="${1}"
|
||||
export "${SERVICE_UPPER}_DB_NAME"="$(xkcdpass -d "-" -n 2)"
|
||||
export "${SERVICE_UPPER}_DB_USERNAME"="$(xkcdpass -d "-" -n 2)"
|
||||
export "${SERVICE_UPPER}_DB_PASSWORD"="$(xkcdpass -d "-")"
|
||||
}
|
||||
|
||||
for service in "${SELECTED_SERVICES[@]}"; do
|
||||
# Frigate
|
||||
if [[ "$service" -eq "frigate" ]]; then
|
||||
echo -e "\n ✅ Adapting the docker configuration to your hardware..."
|
||||
FRIGATE_DEVICES_BLOCK=""
|
||||
if [[ "$TARGET_GRAPHICS_RENDERER" -eq "true" ]]; then
|
||||
FRIGATE_DEVICES_BLOCK+=" - /dev/dri:/dev/dri\n"
|
||||
fi
|
||||
if [[ "$TARGET_USB_CORAL" -eq "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|" ./config-files/docker/compose/frigate.nix
|
||||
else
|
||||
sed -i.bak "/# --- frigate devices --- #/d" ./config-files/docker/compose/frigate.nix
|
||||
fi
|
||||
# Home-Assistant
|
||||
elif [[ "$service" -eq "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/home-assistant.nix
|
||||
else
|
||||
sed -i.bak "/# --- hass devices --- #/d" ./config-files/docker/compose/home-assistant.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" -eq "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" -eq "pi-hole" ]]; then
|
||||
export FTLCONF_WEBSERVER_PASSWORD="$(xkcdpass -d "-")"
|
||||
# Immich
|
||||
elif [[ "$service" -eq "immich" ]]; then
|
||||
IMMICH_DEVICES_BLOCK=""
|
||||
if [[ "$TARGET_GRAPHICS_RENDERER" -eq "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|" ./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" -eq "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" -eq "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 ./nix-config/docker/${service}.nix
|
||||
done
|
||||
echo -e "\n✅ Copying the configuration to the new machine..."
|
||||
cp -avu templates/final-nix-config/etc/nixos/configuration.nix final-nix-config/etc/nixos/
|
||||
cp -avu templates/nix-config/flake.nix final-nix-config/etc/nixos/
|
||||
|
||||
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/
|
||||
echo -e "\n✅ Generating sops-nix keys..."
|
||||
ssh-to-age -private-key -i final-nix-config/home/numbus-admin/.ssh/id_ed25519 > final-nix-config/var/lib/sops-nix/key.txt
|
||||
export SOPS_PUBLIC_KEY=$(age-keygen -y final-nix-config/var/lib/sops-nix/key.txt)
|
||||
|
||||
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 < templates/nix-config/sops-nix/.sops.yaml > final-nix-config/etc/nixos/.sops.yaml
|
||||
|
||||
echo -e "\n ✅ Generating sops-nix configuration files..."
|
||||
envsubst < config-files/sops-nix/.sops.yaml > extra-files/etc/nixos/.sops.yaml
|
||||
|
||||
echo -e "\n ✅ Encrypting secrets in the correct file..."
|
||||
envsubst < "config-files/sops-nix/secrets.yaml" | sops encrypt --filename-override secrets.yaml \
|
||||
echo -e "\n✅ Encrypting secrets in the correct file..."
|
||||
envsubst < "templates/nix-config/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
|
||||
--output final-nix-config/etc/nixos/secrets/secrets.yaml
|
||||
|
||||
echo -e "\n ✅ Writing correct ips to 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✅ Writing correct ips to configuration.nix..."
|
||||
sed -i "s|HOME_SERVER_IP|${HOME_SERVER_IP}|g" final-nix-config/etc/nixos/misc/networking.nix
|
||||
sed -i "s|HOME_ROUTER_IP|${HOME_ROUTER_IP}|g" final-nix-config/etc/nixos/misc/networking.nix
|
||||
|
||||
echo -e "\n ✅ Copying the configuration to the new machine..."
|
||||
cp -ravu ./nix-config/* extra-files/etc/nixos/
|
||||
echo -e "\n✅ Writing configuration files for the selected homelab services..."
|
||||
envsubst < templates/podman-config/traefik/traefik.yaml > final-nix-config/mnt/config/traefik/traefik.yaml
|
||||
|
||||
for service in "${SELECTED_SERVICES[@]}"; do
|
||||
cp templates/nix-config/podman/${service}.nix final-nix-config/etc/nixos/podman/${service}.nix
|
||||
case "${service}" in
|
||||
frigate)
|
||||
local FRIGATE_DEVICES_BLOCK=""
|
||||
[[ "$TARGET_GRAPHICS_RENDERER" -eq "true" ]] && local FRIGATE_DEVICES_BLOCK+=" - /dev/dri:/dev/dri\n"
|
||||
[[ "$TARGET_USB_CORAL" -eq "true" ]] && local FRIGATE_DEVICES_BLOCK+=" - /dev/bus/usb:/dev/bus/usb\n"
|
||||
if [[ "$TARGET_PCIE_CORAL" -eq "true" ]]; then
|
||||
local FRIGATE_DEVICES_BLOCK+=" - /dev/apex_0:/dev/apex_0\n"
|
||||
sed -i "s|# ./pcie-coral/coral.nix| ./pcie-coral/coral.nix|" final-nix-config/etc/nixos/configuration.nix
|
||||
cp -avu templates/nix-config/pcie-coral/* final-nix-config/etc/nixos/pcie-coral/
|
||||
fi
|
||||
if [[ -n "$FRIGATE_DEVICES_BLOCK" ]]; then
|
||||
local REPLACEMENT="devices:\n${FRIGATE_DEVICES_BLOCK%\\n}"
|
||||
sed -i "s|# --- frigate devices --- #|$REPLACEMENT|" final-nix-config/etc/nixos/podman/frigate.nix
|
||||
fi
|
||||
;;
|
||||
home-assistant)
|
||||
if [[ -n "$TARGET_ZIGBEE_DEVICE" ]]; then
|
||||
local REPLACEMENT="devices:\n - /dev/serial/by-id/${TARGET_ZIGBEE_DEVICE}:/dev/ttyUSB0"
|
||||
sed -i "s|# --- hass devices --- #|$REPLACEMENT|" final-nix-config/etc/nixos/podman/home-assistant.nix
|
||||
fi
|
||||
export HOME_ASSISTANT_MQTT_USER="$(xkcdpass -d "-" -n 2)"
|
||||
export HOME_ASSISTANT_MQTT_PASSWORD="$(xkcdpass -d "-")"
|
||||
mkdir -p final-nix-config/mnt/config/mqtt/
|
||||
envsubst < templates/podman-config/hass/mosquitto.conf > final-nix-config/mnt/config/mqtt/mosquitto.conf
|
||||
touch final-nix-config/mnt/config/mqtt/password.txt
|
||||
chmod 0700 final-nix-config/mnt/config/mqtt/password.txt
|
||||
mosquitto_passwd -b final-nix-config/mnt/config/mqtt/password.txt "$HOME_ASSISTANT_MQTT_USER" "$HOME_ASSISTANT_MQTT_PASSWORD"
|
||||
;;
|
||||
passbolt)
|
||||
generate_db_creds "PASSBOLT"
|
||||
envsubst < templates/podman-config/traefik/headers.yaml > final-nix-config/mnt/config/traefik/rules/headers.yaml
|
||||
envsubst < templates/podman-config/traefik/tls.yaml > final-nix-config/mnt/config/traefik/rules/tls.yaml
|
||||
;;
|
||||
pi-hole)
|
||||
export FTLCONF_WEBSERVER_PASSWORD="$(xkcdpass -d "-")"
|
||||
;;
|
||||
immich)
|
||||
local IMMICH_DEVICES_BLOCK=""
|
||||
if [[ "$TARGET_GRAPHICS_RENDERER" -eq "true" ]]; then
|
||||
local IMMICH_DEVICES_BLOCK+=" - /dev/dri:/dev/dri\n"
|
||||
fi
|
||||
if [[ -n "$IMMICH_DEVICES_BLOCK" ]]; then
|
||||
local REPLACEMENT="devices:\n${IMMICH_DEVICES_BLOCK%\\n}"
|
||||
sed -i "s|# --- immich devices --- #|$REPLACEMENT|" final-nix-config/etc/nixos/podman/immich.nix
|
||||
fi
|
||||
generate_db_creds "IMMICH"
|
||||
;;
|
||||
gitea)
|
||||
generate_db_creds "GITEA"
|
||||
;;
|
||||
nextcloud)
|
||||
envsubst < templates/podman-config/traefik/nextcloud.yaml > final-nix-config/mnt/config/traefik/rules/nextcloud.yaml
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
disk_config_generation() {
|
||||
@@ -271,15 +326,15 @@ disk_config_generation() {
|
||||
!! ALL DATA WILL BE WIPED ON THE DISKS YOU CHOOSE !!
|
||||
Please press CTRL+C to abort.
|
||||
"
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo -e "\n\n ❌ Aborting as requested."; exit 1; }
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo -e "\n\n❌ Aborting as requested."; exit 1; }
|
||||
|
||||
echo -e "\n\n 🔎 Fetching and analyzing disks from target host... (This may take a moment)"
|
||||
### Disk wiping warning <--
|
||||
|
||||
TMPFILE="/tmp/nixos-deployment-temp-file"
|
||||
|
||||
### --> Get disk information
|
||||
DISK_DETAILS=$(ssh_to_live_host 'bash -s' <<EOF
|
||||
local TMPFILE="/tmp/nixos-installation-disk-detection-temp-file"
|
||||
|
||||
ssh_to_host 'bash -s' << EOF
|
||||
HDD=1
|
||||
|
||||
DISK_DEVPATH=()
|
||||
@@ -303,7 +358,7 @@ for DISK in \$(lsblk -x SIZE -d -n -e 7,11 -o NAME); do
|
||||
else DISK_TYPE+=("Other")
|
||||
fi
|
||||
# Disk health
|
||||
if [[ \$(echo "$LIVE_REMOTE_PASS" | sudo -S smartctl -H /dev/\$DISK 2>/dev/null | grep 'self-assessment' | awk '{print \$6}') -eq "PASSED" ]]; then
|
||||
if [[ \$(echo "$REMOTE_PASS" | sudo -S smartctl -H /dev/\$DISK 2>/dev/null | grep 'self-assessment' | awk '{print \$6}') -eq "PASSED" ]]; then
|
||||
DISK_HEALTH+=("PASSED")
|
||||
else
|
||||
DISK_HEALTH+=("N/A")
|
||||
@@ -314,79 +369,69 @@ for DISK in \$(lsblk -x SIZE -d -n -e 7,11 -o NAME); do
|
||||
DISK_SIZE+=("\$(lsblk -x SIZE -d -n -e 7,11 -o SIZE /dev/\$DISK)")
|
||||
done
|
||||
|
||||
echo "DISK_DEVPATH=(\${DISK_DEVPATH[@]})" > $TMPFILE
|
||||
echo "DISK_NAME=(\${DISK_NAME[@]})" >> $TMPFILE
|
||||
echo "DISK_TYPE=(\${DISK_TYPE[@]})" >> $TMPFILE
|
||||
echo "DISK_HEALTH=(\${DISK_HEALTH[@]})" >> $TMPFILE
|
||||
echo "DISK_ID=(\${DISK_ID[@]})" >> $TMPFILE
|
||||
echo "DISK_SIZE=(\${DISK_SIZE[@]})" >> $TMPFILE
|
||||
echo "DISK_DEVPATH=(\${DISK_DEVPATH[@]})" > "${TMPFILE}"
|
||||
echo "DISK_NAME=(\${DISK_NAME[@]})" >> "${TMPFILE}"
|
||||
echo "DISK_TYPE=(\${DISK_TYPE[@]})" >> "${TMPFILE}"
|
||||
echo "DISK_HEALTH=(\${DISK_HEALTH[@]})" >> "${TMPFILE}"
|
||||
echo "DISK_ID=(\${DISK_ID[@]})" >> "${TMPFILE}"
|
||||
echo "DISK_SIZE=(\${DISK_SIZE[@]})" >> "${TMPFILE}"
|
||||
EOF
|
||||
)
|
||||
|
||||
scp -i "extra-files/home/numbus-admin/.ssh/id_ed25519" nixos@$TARGET_HOST:$TMPFILE $TMPFILE &> /dev/null
|
||||
source $TMPFILE && rm $TMPFILE
|
||||
scp -i "final-nix-config/home/numbus-admin/.ssh/id_ed25519" "${TARGET_USER}@${TARGET_HOST}":"${TMPFILE}" "${TMPFILE}" &> /dev/null
|
||||
source "${TMPFILE}" && rm "${TMPFILE}"
|
||||
|
||||
### --> Disk selection
|
||||
if [[ "${#DISK_NAME[@]}" -eq 0 ]]; then
|
||||
echo -e "\n\n ❌ No disks found on the target host. Aborting."
|
||||
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")
|
||||
local HEADER=$(printf " %-12s %-12s %-12s %-12s %s" "Device" "Type" "Size" "SMART" "Path")
|
||||
|
||||
for i in ${!DISK_NAME[@]}; do
|
||||
GUM_PRINTED_ELEMENT=$(printf "%-12s %-12s %-12s %-12s %s" \
|
||||
local GUM_PRINTED_ELEMENT=$(printf "%-12s %-12s %-12s %-12s %s" \
|
||||
"${DISK_NAME[${i}]}" "${DISK_TYPE[${i}]}" "${DISK_SIZE[${i}]}" \
|
||||
"${DISK_HEALTH[${i}]}" "${DISK_DEVPATH[${i}]}")
|
||||
GUM_PRINTED_ELEMENTS+=("$GUM_PRINTED_ELEMENT")
|
||||
local GUM_PRINTED_ELEMENTS+=("$GUM_PRINTED_ELEMENT")
|
||||
done
|
||||
|
||||
gum style --foreground 212 " ➡️ Please choose one (stripe) or two (mirror) disks for your NixOS boot installation :"
|
||||
gum style --foreground 212 "➡️ Please choose one (stripe) or two (mirror) disks for your NixOS boot installation :"
|
||||
|
||||
SELECTED_BOOT_DISK=$(gum choose --limit 2 --header "$HEADER" "${GUM_PRINTED_ELEMENTS[@]}")
|
||||
local SELECTED_BOOT_DISK=$(gum choose --limit 2 --header "$HEADER" "${GUM_PRINTED_ELEMENTS[@]}")
|
||||
|
||||
for i in ${!DISK_NAME[@]}; do
|
||||
if printf '%s' "$SELECTED_BOOT_DISK" | grep -iqw "${DISK_NAME[${i}]}"; then
|
||||
if [[ -n "${DISK_ID[${i}]}" ]]; then
|
||||
export BOOT_DISKS_ID+=("${DISK_NAME[${i}]}")
|
||||
else
|
||||
export BOOT_DISKS_ID+=("${DISK_ID[${i}]}")
|
||||
fi
|
||||
export BOOT_DISKS_ID+=("${DISK_ID[${i}]:-${DISK_DEVPATH[${i}]}}")
|
||||
unset "GUM_PRINTED_ELEMENTS[${i}]"
|
||||
fi
|
||||
done
|
||||
|
||||
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
|
||||
elif [[ "${#BOOT_DISKS_ID[@]}" -eq 1 ]]; then
|
||||
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."
|
||||
export BOOT_DISK_1_ID=${BOOT_DISKS_ID[0]}
|
||||
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
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
echo -e "\n\n❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
gum style --foreground 212 " ➡️ Please choose data and parity disks (up to 9 total) :"
|
||||
gum style --foreground 212 "➡️ Please choose data and parity disks (up to 9 total) :"
|
||||
|
||||
SELECTED_DATA_DISK=$(gum choose --limit 9 --header "$HEADER" "${GUM_PRINTED_ELEMENTS[@]}")
|
||||
local SELECTED_DATA_DISK=$(gum choose --limit 9 --header "$HEADER" "${GUM_PRINTED_ELEMENTS[@]}")
|
||||
|
||||
for i in ${!DISK_NAME[@]}; do
|
||||
if printf '%s' "$SELECTED_DATA_DISK" | grep -iq "${DISK_NAME[${i}]}"; then
|
||||
if [[ -n ${DISK_ID[${i}]} ]]; then
|
||||
export DATA_DISKS_ID+=("${DISK_NAME[${i}]}")
|
||||
export DATA_DISKS_TYPE+=("${DISK_TYPE[${i}]}")
|
||||
else
|
||||
export DATA_DISKS_ID+=("${DISK_ID[${i}]}")
|
||||
export DATA_DISKS_TYPE+=("${DISK_TYPE[${i}]}")
|
||||
fi
|
||||
export DATA_DISKS_ID+=("${DISK_ID[${i}]:-${DISK_DEVPATH[${i}]}}")
|
||||
export DATA_DISKS_TYPE+=("${DISK_TYPE[${i}]}")
|
||||
fi
|
||||
done
|
||||
|
||||
@@ -395,7 +440,7 @@ the one of the smallest disk."
|
||||
### Disk selection <--
|
||||
|
||||
### --> Selection recap
|
||||
RECAP_CONTENT=$(cat <<EOF
|
||||
RECAP_CONTENT=$(cat << EOF
|
||||
### Disk Configuration Summary
|
||||
|
||||
Please review the selected disk layout before proceeding.
|
||||
@@ -415,80 +460,77 @@ EOF
|
||||
)
|
||||
|
||||
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "$(gum format <<< "$RECAP_CONTENT")"
|
||||
gum confirm "Proceed with this disk configuration?" || { echo -e "\n\n ❌ Aborting as requested."; exit 1; }
|
||||
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/templates/boot-${#BOOT_DISKS_ID[@]}.nix"
|
||||
(envsubst < "$TEMPLATE_FILE") > ./nix-config/disks/disko.nix
|
||||
echo -e "\n ✅ Generated boot disk configuration."
|
||||
echo -e "\n\n✅ Generating disko configuration from templates..."
|
||||
local TEMPLATE_FILE="templates/nix-config/disks/boot-${#BOOT_DISKS_ID[@]}.nix"
|
||||
(envsubst < "$TEMPLATE_FILE") > final-nix-config/etc/nixos/disks/disko.nix
|
||||
|
||||
# Striped configuration
|
||||
if [[ "$CONTENT_DISK_NUMBER" -eq 1 && "$PARITY_DISK_NUMBER" -eq 0 ]]; then
|
||||
export j="1"
|
||||
export CONTENT_DISK_ID="${DATA_DISKS_ID[0]}"
|
||||
(envsubst < "config-files/disks/templates/content.nix") >> ./nix-config/disks/disko.nix
|
||||
sed -i "s|/mnt/content-1|/mnt/data-storage|" ./nix-config/disks/disko.nix
|
||||
(envsubst < "templates/nix-config/disks/content.nix") >> final-nix-config/etc/nixos/disks/disko.nix
|
||||
sed -i "s|/mnt/content-1|/mnt/data-storage|" final-nix-config/etc/nixos/disks/disko.nix
|
||||
# Mirror configuration
|
||||
elif [[ "$CONTENT_DISK_NUMBER" -eq 1 && "$PARITY_DISK_NUMBER" -eq 1 ]]; then
|
||||
export CONTENT_DISK_ID="${DATA_DISKS_ID[0]}"
|
||||
export PARITY_DISK_ID="${DATA_DISKS_ID[1]}"
|
||||
(envsubst < "config-files/disks/templates/mirror.nix") >> ./nix-config/disks/disko.nix
|
||||
(envsubst < "templates/nix-config/disks/mirror.nix") >> final-nix-config/etc/nixos/disks/disko.nix
|
||||
# SnapRAID configuration
|
||||
elif [[ "$CONTENT_DISK_NUMBER" -gt 1 ]]; then
|
||||
# Enable SnapRAID
|
||||
sed -i "s|# ./disks/snapraid.nix| ./disks/snapraid.nix|" ./nix-config/configuration.nix
|
||||
sed -i '$ d' ./config-files/disks/snapraid.nix
|
||||
cat <<EOF >> ./config-files/disks/snapraid.nix
|
||||
cp -avu templates/nix-config/disks/snapraid.nix final-nix-config/etc/nixos/disks/
|
||||
cp -avu templates/nix-config/disks/pcr-check.nix final-nix-config/etc/nixos/disks/
|
||||
sed -i "s|# ./disks/snapraid.nix| ./disks/snapraid.nix|" final-nix-config/etc/nixos/configuration.nix
|
||||
sed -i '$ d' final-nix-config/etc/nixos/disks/snapraid.nix
|
||||
cat << EOF >> final-nix-config/etc/nixos/disks/snapraid.nix
|
||||
# --> Automatic data disks unlock, generated by deploy.sh on $(date)
|
||||
boot.initrd.luks.devices = {
|
||||
EOF
|
||||
j=0
|
||||
for i in $(seq 0 $(($CONTENT_DISK_NUMBER - 1))); do
|
||||
export ((j++))
|
||||
LOOP_DISK="${DATA_DISKS_ID[${i}]}"
|
||||
export CONTENT_DISK_ID=${!LOOP_DISK}
|
||||
(envsubst < "config-files/disks/templates/content.nix") >> ./nix-config/disks/disko.nix
|
||||
cat <<EOF >> ./config-files/disks/snapraid.nix
|
||||
export CONTENT_DISK_ID="${DATA_DISKS_ID[${i}]}"
|
||||
(envsubst < "templates/nix-config/disks/content.nix") >> final-nix-config/etc/nixos/disks/disko.nix
|
||||
cat << EOF >> final-nix-config/etc/nixos/disks/snapraid.nix
|
||||
"crypted-content-disk-${j}" = {
|
||||
device = "${!LOOP_DISK}";
|
||||
device = "${CONTENT_DISK_ID}";
|
||||
keyFile = "/etc/secrets/disks/content-disk-${j}";
|
||||
};
|
||||
EOF
|
||||
done
|
||||
echo -e "\n ✅ Generated $CONTENT_DISK_NUMBER data disk configuration(s)."
|
||||
echo -e "\n✅ Generated $CONTENT_DISK_NUMBER data disk configuration(s)."
|
||||
j=0
|
||||
for i in $(seq $PARITY_DISK_NUMBER $((${#DATA_DISKS_ID[@]} - 1))); do
|
||||
export ((j++))
|
||||
LOOP_DISK="${DATA_DISKS_ID[${i}]}"
|
||||
export PARITY_DISK_ID=${!LOOP_DISK}
|
||||
(envsubst < "config-files/disks/templates/parity.nix") >> ./nix-config/disks/disko.nix
|
||||
cat <<EOF >> ./config-files/disks/snapraid.nix
|
||||
export PARITY_DISK_ID="${DATA_DISKS_ID[${i}]}"
|
||||
(envsubst < "templates/nix-config/disks/parity.nix") >> final-nix-config/etc/nixos/disks/disko.nix
|
||||
cat << EOF >> final-nix-config/etc/nixos/disks/snapraid.nix
|
||||
"crypted-parity-disk-${j}" = {
|
||||
device = "${!LOOP_DISK}";
|
||||
device = "${PARITY_DISK_ID}";
|
||||
keyFile = "/etc/secrets/disks/parity-disk-${j}}";
|
||||
};
|
||||
EOF
|
||||
done
|
||||
echo -e "\n ✅ Generated $PARITY_DISK_NUMBER parity disk configuration(s)."
|
||||
echo -e "\n✅ Generated $PARITY_DISK_NUMBER parity disk configuration(s)."
|
||||
# Close the snapraid.nix block
|
||||
cat <<'EOF' >> ./config-files/disks/snapraid.nix
|
||||
cat <<'EOF' >> final-nix-config/etc/nixos/disks/snapraid.nix
|
||||
# Automatic data disks unlock <--
|
||||
};
|
||||
}
|
||||
EOF
|
||||
cp -avu ./config-files/disks/snapraid.nix ./nix-config/disks/
|
||||
fi
|
||||
|
||||
# Close the disko.nix block
|
||||
cat <<'EOF' >> ./nix-config/disks/disko.nix
|
||||
cat <<'EOF' >> final-nix-config/etc/nixos/disks/disko.nix
|
||||
};
|
||||
};
|
||||
}
|
||||
EOF
|
||||
|
||||
echo -e "\n ✅ Final disko configuration created."
|
||||
echo -e "\n✅ Final disko configuration created."
|
||||
|
||||
if [[ -n "${DATA_DISKS_ID[@]}" ]]; then
|
||||
for i in ${!DATA_DISKS_ID[@]}; do
|
||||
@@ -497,41 +539,56 @@ EOF
|
||||
fi
|
||||
done
|
||||
if [[ -n "${DISK_ID_LIST[@]}" ]]; then
|
||||
sed -i "s|DISK_ID_LIST|${DISK_ID_LIST[@]}|" ./config-files/disks/spindown.nix
|
||||
cp -avu ./config-files/disks/spindown.nix ./nix-config/disks/spindown.nix
|
||||
echo -e "\n ✅ Disk spindown configuration created."
|
||||
cp -avu templates/nix-config/disks/spindown.nix final-nix-config/etc/nixos/disks/
|
||||
sed -i "s|DISK_ID_LIST|${DISK_ID_LIST[@]}|" final-nix-config/etc/nixos/disks/spindown.nix
|
||||
echo -e "\n✅ Disk spindown configuration created."
|
||||
fi
|
||||
fi
|
||||
### Config generation <--
|
||||
|
||||
### --> Generate unlock keys
|
||||
for i in ${#BOOT_DISKS_ID[@]}; do
|
||||
declare "/etc/secrets/disks/boot-disk-${i}=$(xkcdpass -d "-")"
|
||||
done
|
||||
for i in $CONTENT_DISK_NUMBER; do
|
||||
declare "/etc/secrets/disks/content-disk-${i}=$(xkcdpass -d "-")"
|
||||
done
|
||||
for i in $PARITY_DISK_NUMBER; do
|
||||
declare "/etc/secrets/disks/parity-disk-${i}=$(xkcdpass -d "-")"
|
||||
for i in $(seq 1 "${#BOOT_DISKS_ID[@]}"); do
|
||||
PASS="$(xkcdpass -d "-")"
|
||||
echo -n "$PASS" > "final-nix-config/etc/secrets/disks/boot-disk-${i}"
|
||||
chmod 600 "final-nix-config/etc/secrets/disks/boot-disk-${i}"
|
||||
done
|
||||
if [[ "$CONTENT_DISK_NUMBER" -gt 0 ]]; then
|
||||
for i in $(seq 1 "$CONTENT_DISK_NUMBER"); do
|
||||
PASS="$(xkcdpass -d "-")"
|
||||
echo -n "$PASS" > "final-nix-config/etc/secrets/disks/content-disk-${i}"
|
||||
chmod 600 "final-nix-config/etc/secrets/disks/content-disk-${i}"
|
||||
done
|
||||
fi
|
||||
if [[ "$PARITY_DISK_NUMBER" -gt 0 ]]; then
|
||||
for i in $(seq 1 "$PARITY_DISK_NUMBER"); do
|
||||
PASS="$(xkcdpass -d "-")"
|
||||
echo -n "$PASS" > "final-nix-config/etc/secrets/disks/parity-disk-${i}"
|
||||
chmod 600 "final-nix-config/etc/secrets/disks/parity-disk-${i}"
|
||||
done
|
||||
fi
|
||||
### Generate unlock keys <--
|
||||
}
|
||||
|
||||
deploy() {
|
||||
echo -e "\n\n 🔄 Deploying to the remote server..."
|
||||
nix run github:nix-community/nixos-anywhere -- \
|
||||
--generate-hardware-config nixos-generate-config ./nix-config/hardware-configuration.nix \
|
||||
--flake ./nix-config#numbus-server \
|
||||
--extra-files extra-files \
|
||||
--chown "/home/numbusing a us-admin/" 1000:1000 \
|
||||
--target-host nixos@$TARGET_HOST
|
||||
export_configuration() {
|
||||
cp deploy.conf final-nix-config/etc/numbus-server/numbus-server.conf
|
||||
|
||||
echo -e "\n\n ✅ Installation successfull !"
|
||||
sleep 1
|
||||
local CONFIG_EXPORT_DIR="final-nix-config/etc/numbus-server/"
|
||||
local CONFIG_EXPORT_FILE="${CONFIG_EXPORT_DIR}/numbus-server.conf"
|
||||
|
||||
cp -ravu templates/post-install/numbus-server.sh "$CONFIG_EXPORT_DIR"
|
||||
|
||||
echo "# SERVICE SETTINGS" >> $CONFIG_EXPORT_FILE
|
||||
echo "SELECTED_SERVICES=(${SELECTED_SERVICES[@]})" >> $CONFIG_EXPORT_FILE
|
||||
echo "# DISK SETTINGS" >> $CONFIG_EXPORT_FILE
|
||||
echo "BOOT_DISK_ID_LIST=(${BOOT_DISKS_ID[@]})" >> $CONFIG_EXPORT_FILE
|
||||
echo "DATA_DISKS_ID_LIST=(${DATA_DISKS_ID[@]})" >> $CONFIG_EXPORT_FILE
|
||||
echo "SPINDOWN_DISKS_ID_LIST=(${DISK_ID_LIST[@]})" >> $CONFIG_EXPORT_FILE
|
||||
echo "CONTENT_DISK_NUMBER=$CONTENT_DISK_NUMBER" >> $CONFIG_EXPORT_FILE
|
||||
echo "PARITY_DISK_NUMBER=$PARITY_DISK_NUMBER" >> $CONFIG_EXPORT_FILE
|
||||
}
|
||||
|
||||
sum_up() {
|
||||
RECAP_CONTENT=$(cat <<EOF
|
||||
RECAP_CONTENT=$(cat << EOF
|
||||
### Generated Secrets Summary
|
||||
|
||||
Please save these secrets in a secure location (e.g., a password manager).
|
||||
@@ -548,31 +605,49 @@ Please save these secrets in a secure location (e.g., a password manager).
|
||||
* **Immich DB Password:** \`$IMMICH_DB_PASSWORD\`
|
||||
|
||||
**Disk Encryption Keys:**
|
||||
$(for i in {1..2}; do key_var="BOOT_DISK_${i}_KEY"; [[ -n "${!key_var}" ]] && echo "* **Boot Disk $i Key:** \`${!key_var}\`"; done)
|
||||
$(for i in {1..6}; do key_var="CONTENT_DISK_${i}_KEY"; [[ -n "${!key_var}" ]] && echo "* **Content Disk $i Key:** \`${!key_var}\`"; done)
|
||||
$(for i in {1..3}; do key_var="PARITY_DISK_${i}_KEY"; [[ -n "${!key_var}" ]] && echo "* **Parity Disk $i Key:** \`${!key_var}\`"; done)
|
||||
$(for i in $(seq 1 "${#BOOT_DISKS_ID[@]}"); do f="final-nix-config/etc/secrets/disks/boot-disk-${i}"; [[ -f "$f" ]] && echo "* **Boot Disk $i Key:** \`$(cat "$f")\`"; done)
|
||||
$(if [[ "$CONTENT_DISK_NUMBER" -gt 0 ]]; then for i in $(seq 1 "$CONTENT_DISK_NUMBER"); do f="final-nix-config/etc/secrets/disks/content-disk-${i}"; [[ -f "$f" ]] && echo "* **Content Disk $i Key:** \`$(cat "$f")\`"; done; fi)
|
||||
$(if [[ "$PARITY_DISK_NUMBER" -gt 0 ]]; then for i in $(seq 1 "$PARITY_DISK_NUMBER"); do f="final-nix-config/etc/secrets/disks/parity-disk-${i}"; [[ -f "$f" ]] && echo "* **Parity Disk $i Key:** \`$(cat "$f")\`"; done; fi)
|
||||
EOF
|
||||
)
|
||||
|
||||
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "$(gum format <<< "$RECAP_CONTENT")"
|
||||
|
||||
gum confirm "Do you want to deploy NixOS on the target host?" || { echo -e "\n\n❌ Aborting as requested"; exit 1; }
|
||||
}
|
||||
|
||||
|
||||
|
||||
deploy() {
|
||||
echo -e "\n\n🔄 Deploying to the remote server..."
|
||||
nix run github:nix-community/nixos-anywhere -- \
|
||||
--flake ./final-nix-config/etc/nixos#numbus-server \
|
||||
--extra-files final-nix-config \
|
||||
--chown "/home/numbus-admin/" 1000:1000 \
|
||||
--target-host ${TARGET_USER}@${TARGET_HOST}
|
||||
|
||||
echo -e "\n\n✅ Installation successfull !"
|
||||
sleep 1
|
||||
}
|
||||
|
||||
|
||||
|
||||
postrun_action() {
|
||||
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 120
|
||||
gum spin --title "Rebooting the remote..." -- sleep 120
|
||||
|
||||
gum confirm " ➡️ Select 'yes' once the machine rebooted and you unlocked the disks." || { echo -e "\n\n ❌ Aborting as requested."; exit 1; }
|
||||
gum confirm "➡️ Select 'yes' once the machine rebooted and you unlocked the disks." || { echo -e "\n\n❌ Aborting as requested."; exit 1; }
|
||||
|
||||
gum spin --spinner dot --title "\n\n 🔄 Waiting for the server to boot up..." --auto <<EOF
|
||||
gum spin --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. \
|
||||
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
|
||||
@@ -580,17 +655,17 @@ This is most likely due to a networking issue. Please double check your network
|
||||
done
|
||||
EOF
|
||||
|
||||
ssh_to_installed_host 'bash -s' <<EOF
|
||||
ssh_to_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
|
||||
echo $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
|
||||
echo $REMOTE_PASS | sudo -S systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=0+7 /dev/mapper/crypted-boot-1
|
||||
echo $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)
|
||||
PCR_HASH=\$(echo $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
|
||||
@@ -603,11 +678,13 @@ You will almost never user it. Consider using a very strong password : you can w
|
||||
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; }
|
||||
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
|
||||
echo $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. \
|
||||
@@ -621,79 +698,87 @@ it simple and use defaults) and take care to note down all the passwords. Change
|
||||
}
|
||||
|
||||
nixos_update() {
|
||||
echo -e "\n\n 🔄 Updating NixOS on the remote server..."
|
||||
echo -e "\n\n🔄 Updating NixOS on the remote server..."
|
||||
echo "coming soon !"
|
||||
}
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
cat <<EOF
|
||||
██████ █████ ███ ███████ █████████
|
||||
░░██████ ░░███ ░░░ ███░░░░░███ ███░░░░░███
|
||||
░███░███ ░███ ████ █████ █████ ███ ░░███░███ ░░░
|
||||
░███░░███░███ ░░███ ░░███ ░░███ ░███ ░███░░█████████
|
||||
░███ ░░██████ ░███ ░░░█████░ ░███ ░███ ░░░░░░░░███
|
||||
░███ ░░█████ ░███ ███░░░███ ░░███ ███ ███ ░███
|
||||
█████ ░░█████ █████ █████ █████ ░░░███████░ ░░█████████
|
||||
░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░ ░░░░░░░ ░░░░░░░░░
|
||||
fastfetch --logo nixos --structure ''
|
||||
|
||||
cat << EOF
|
||||
|
||||
██████ █████ █████
|
||||
▒▒██████ ▒▒███ ▒▒███
|
||||
▒███▒███ ▒███ █████ ████ █████████████ ▒███████ █████ ████ █████
|
||||
▒███▒▒███▒███ ▒▒███ ▒███ ▒▒███▒▒███▒▒███ ▒███▒▒███▒▒███ ▒███ ███▒▒
|
||||
▒███ ▒▒██████ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒▒█████
|
||||
▒███ ▒▒█████ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒▒▒▒███
|
||||
█████ ▒▒█████ ▒▒████████ █████▒███ █████ ████████ ▒▒████████ ██████
|
||||
▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒
|
||||
|
||||
█████████
|
||||
███▒▒▒▒▒███
|
||||
▒███ ▒▒▒ ██████ ████████ █████ █████ ██████ ████████
|
||||
▒▒█████████ ███▒▒███▒▒███▒▒███▒▒███ ▒▒███ ███▒▒███▒▒███▒▒███
|
||||
▒▒▒▒▒▒▒▒███▒███████ ▒███ ▒▒▒ ▒███ ▒███ ▒███████ ▒███ ▒▒▒
|
||||
███ ▒███▒███▒▒▒ ▒███ ▒▒███ ███ ▒███▒▒▒ ▒███
|
||||
▒▒█████████ ▒▒██████ █████ ▒▒█████ ▒▒██████ █████
|
||||
▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒
|
||||
|
||||
█████████ █████
|
||||
███░░░░░███ ░░███
|
||||
░███ ░███ ████████ █████ ████ █████ ███ █████ ░███████ ██████ ████████ ██████
|
||||
░███████████ ░░███░░███ ░░███ ░███ ░░███ ░███░░███ ░███░░███ ███░░███░░███░░███ ███░░███
|
||||
░███░░░░░███ ░███ ░███ ░███ ░███ ░███ ░███ ░███ ░███ ░███ ░███████ ░███ ░░░ ░███████
|
||||
░███ ░███ ░███ ░███ ░███ ░███ ░░███████████ ░███ ░███ ░███░░░ ░███ ░███░░░
|
||||
█████ █████ ████ █████ ░░███████ ░░████░████ ████ █████░░██████ █████ ░░██████
|
||||
░░░░░ ░░░░░ ░░░░ ░░░░░ ░░░░░███ ░░░░ ░░░░ ░░░░ ░░░░░ ░░░░░░ ░░░░░ ░░░░░░
|
||||
███ ░███
|
||||
░░██████
|
||||
░░░░░░
|
||||
EOF
|
||||
|
||||
sleep 1
|
||||
|
||||
# Choose the action
|
||||
ACTION_ANSWER=$(gum choose "[1] 🌐 Deploy NixOS on a remote machine" "[2] 💽 Deploy NixOS on a remote machine with a file configuration" "[3] 🛠️ Update a NixOS remote machine")
|
||||
echo $ACTION_ANSWER
|
||||
|
||||
TARGET_USER="nixos"
|
||||
|
||||
if [[ "$ACTION_ANSWER" -eq "[1] 🌐 Deploy NixOS on a remote machine" ]]; then
|
||||
echo -e "\n ➡️ Proceeding with deployment…"
|
||||
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.
|
||||
Launch a console and set up a new user password."
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo " ❌ Aborting as requested."; exit 1; }
|
||||
echo -e "\n➡️ Proceeding with deployment…"
|
||||
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.
|
||||
Launch a console and set up a new user password"
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo "❌ Aborting as requested"; exit 1; }
|
||||
necessary_credentials
|
||||
setup_ssh
|
||||
hardware_detection
|
||||
services_selection
|
||||
files_generation
|
||||
disk_config_generation
|
||||
export_configuration
|
||||
sum_up
|
||||
deploy
|
||||
TARGET_USER="numbus-admin"
|
||||
REMOTE_PASS="changeMe!"
|
||||
postrun_action
|
||||
congrats
|
||||
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…"
|
||||
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.
|
||||
Launch a console and set up a new user password."
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo " ❌ Aborting as requested."; exit 1; }
|
||||
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.
|
||||
Launch a console and set up a new user password"
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo "❌ Aborting as requested"; exit 1; }
|
||||
necessary_credentials_with_config
|
||||
setup_ssh
|
||||
gum spin --title "Generating folder tree..." -- generate_folder_tree
|
||||
hardware_detection
|
||||
services_selection
|
||||
files_generation
|
||||
disk_config_generation
|
||||
deploy
|
||||
export_configuration
|
||||
sum_up
|
||||
deploy
|
||||
TARGET_USER="numbus-admin"
|
||||
REMOTE_PASS="changeMe!"
|
||||
postrun_action
|
||||
congrats
|
||||
elif [[ "$ACTION_ANSWER" -eq "[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."
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo " ❌ Aborting as requested."; exit 1; }
|
||||
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"
|
||||
gum confirm "Do you understand and wish to proceed?" || { echo "❌ Aborting as requested."; exit 1; }
|
||||
nixos_update
|
||||
else
|
||||
echo "Aborting - you did not type '1, 2 or 3'."
|
||||
echo "Aborting - you did not type '1, 2 or 3'"
|
||||
exit 1
|
||||
fi
|
||||
Vendored
BIN
Binary file not shown.
@@ -8,6 +8,7 @@
|
||||
./disks/disko.nix
|
||||
# ./disks/snapraid.nix
|
||||
# ./disks/pcr-check.nix
|
||||
# ./pcie-coral/coral.nix
|
||||
];
|
||||
|
||||
# Hardware settings
|
||||
@@ -22,13 +23,15 @@
|
||||
sops.age.generateKey = true;
|
||||
sops.secrets."ssh_public_keys" = { owner = "numbus-admin"; path = "/etc/ssh/authorized_keys.d/numbus-admin"; };
|
||||
sops.secrets."sender_email_address_password" = {};
|
||||
sops.secrets."docker/frigate" = { owner = "numbus-admin"; path = "/etc/docker-compose/frigate/.env"; };
|
||||
sops.secrets."docker/traefik" = { owner = "numbus-admin"; path = "/etc/docker-compose/traefik/.env"; };
|
||||
sops.secrets."docker/nextcloud" = { owner = "numbus-admin"; path = "/etc/docker-compose/nextcloud/.env"; };
|
||||
sops.secrets."docker/passbolt" = { owner = "numbus-admin"; path = "/etc/docker-compose/passbolt/.env"; };
|
||||
sops.secrets."docker/hass" = { owner = "numbus-admin"; path = "/etc/docker-compose/hass/.env"; };
|
||||
sops.secrets."docker/pihole" = { owner = "numbus-admin"; path = "/etc/docker-compose/pihole/.env"; };
|
||||
sops.secrets."docker/immich" = { owner = "numbus-admin"; path = "/etc/docker-compose/immich/.env"; };
|
||||
sops.secrets."podman/frigate" = { owner = "numbus-admin"; path = "/etc/podman/frigate/.env"; };
|
||||
sops.secrets."podman/gitea" = { owner = "numbus-admin"; path = "/etc/podman/gitea/.env"; };
|
||||
sops.secrets."podman/home_assistant" = { owner = "numbus-admin"; path = "/etc/podman/home-assistant/.env"; };
|
||||
sops.secrets."podman/immich" = { owner = "numbus-admin"; path = "/etc/podman/immich/.env"; };
|
||||
sops.secrets."podman/it_tools" = { owner = "numbus-admin"; path = "/etc/podman/immich/.env"; };
|
||||
sops.secrets."podman/nextcloud" = { owner = "numbus-admin"; path = "/etc/podman/nextcloud/.env"; };
|
||||
sops.secrets."podman/passbolt" = { owner = "numbus-admin"; path = "/etc/podman/passbolt/.env"; };
|
||||
sops.secrets."podman/pi_hole" = { owner = "numbus-admin"; path = "/etc/podman/pi-hole/.env"; };
|
||||
sops.secrets."podman/traefik" = { owner = "numbus-admin"; path = "/etc/podman/traefik/.env"; };
|
||||
|
||||
# Bootloader options
|
||||
boot.initrd.systemd.enable = true;
|
||||
@@ -65,9 +68,7 @@
|
||||
};
|
||||
|
||||
# Enable SSH
|
||||
services.openssh = {
|
||||
enable = true;
|
||||
};
|
||||
services.openssh.enable = true;
|
||||
|
||||
# Allow unfree packages
|
||||
nixpkgs.config.allowUnfree = true;
|
||||
@@ -87,6 +88,9 @@
|
||||
smartmontools
|
||||
cpufrequtils
|
||||
intel-gpu-tools
|
||||
podman
|
||||
podman-compose
|
||||
podman-tui
|
||||
];
|
||||
|
||||
# Power savings
|
||||
@@ -104,17 +108,15 @@
|
||||
];
|
||||
};
|
||||
|
||||
# Enable docker
|
||||
virtualisation.docker.enable = true;
|
||||
virtualisation.docker.daemon.settings = {
|
||||
data-root = "/mnt/config-storage/docker-volumes/";
|
||||
};
|
||||
# Enable Podman
|
||||
virtualisation.podman.enable = true;
|
||||
virtualisation.podman.defaultNetwork.settings.dns_enabled = true;
|
||||
|
||||
# User account
|
||||
users.users.numbus-admin = {
|
||||
isNormalUser = true;
|
||||
description = "Numbus Admin";
|
||||
extraGroups = [ "networkmanager" "wheel" "docker" ];
|
||||
extraGroups = [ "networkmanager" "wheel" ];
|
||||
uid = 1000;
|
||||
initialPassword = "changeMe!";
|
||||
};
|
||||
@@ -139,8 +141,16 @@
|
||||
randomizedDelaySec = "45min";
|
||||
};
|
||||
|
||||
nix.gc = {
|
||||
automatic = true;
|
||||
dates = "weekly";
|
||||
options = "--delete-older-than 7d";
|
||||
};
|
||||
|
||||
# Enable NixOS flakes
|
||||
nix.settings.experimental-features = [ "nix-command" "flakes" ];
|
||||
# Enable auto nix-store optimization
|
||||
nix.settings.auto-optimise-store = true;
|
||||
|
||||
system.stateVersion = "25.05";
|
||||
}
|
||||
@@ -16,10 +16,19 @@
|
||||
networking.networkmanager.enable = true;
|
||||
networking.nftables.enable = true;
|
||||
networking.firewall.enable = true;
|
||||
# networking.firewall.extraCommands = "
|
||||
# iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
|
||||
# iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 8443
|
||||
# ";
|
||||
|
||||
networking.nftables.tables.nat = {
|
||||
family = "ip";
|
||||
content = ''
|
||||
chain prerouting {
|
||||
type nat hook prerouting priority dstnat; policy accept;
|
||||
tcp dport 80 redirect to :8080
|
||||
tcp dport 443 redirect to :8443
|
||||
tcp dport 53 redirect to :5353
|
||||
udp dport 53 redirect to :5353
|
||||
}
|
||||
'';
|
||||
};
|
||||
|
||||
# Open ports in the firewall
|
||||
networking.firewall.allowPing = true;
|
||||
@@ -0,0 +1,12 @@
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
let
|
||||
libedgetpu = pkgs.callPackage ./libedgetpu.nix {};
|
||||
gasket = config.boot.kernelPackages.callPackage ./gasket.nix {};
|
||||
in
|
||||
|
||||
{
|
||||
services.udev.packages = [ libedgetpu ];
|
||||
users.groups.plugdev = {};
|
||||
boot.extraModulePackages = [ gasket ];
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
{ stdenv, lib, fetchFromGitHub, kernel }:
|
||||
|
||||
stdenv.mkDerivation rec {
|
||||
pname = "gasket";
|
||||
version = "1.0-18";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "google";
|
||||
repo = "gasket-driver";
|
||||
rev = "97aeba584efd18983850c36dcf7384b0185284b3";
|
||||
sha256 = "pJwrrI7jVKFts4+bl2xmPIAD01VKFta2SRuElerQnTo=";
|
||||
};
|
||||
|
||||
makeFlags = [
|
||||
"-C"
|
||||
"${kernel.dev}/lib/modules/${kernel.modDirVersion}/build"
|
||||
"M=$(PWD)"
|
||||
];
|
||||
buildFlags = [ "modules" ];
|
||||
|
||||
installFlags = [ "INSTALL_MOD_PATH=${placeholder "out"}" ];
|
||||
installTargets = [ "modules_install" ];
|
||||
|
||||
sourceRoot = "source/src";
|
||||
hardeningDisable = [ "pic" "format" ];
|
||||
nativeBuildInputs = kernel.moduleBuildDependencies;
|
||||
|
||||
meta = with lib; {
|
||||
description = "The Coral Gasket Driver allows usage of the Coral EdgeTPU on Linux systems.";
|
||||
homepage = "https://github.com/google/gasket-driver";
|
||||
license = licenses.gpl2;
|
||||
maintainers = [ lib.maintainers.kylehendricks ];
|
||||
platforms = platforms.linux;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
{ stdenv, lib, fetchFromGitHub, libusb1, abseil-cpp, flatbuffers, xxd }:
|
||||
|
||||
let
|
||||
flatbuffers_1_12 = flatbuffers.overrideAttrs (oldAttrs: rec {
|
||||
version = "1.12.0";
|
||||
NIX_CFLAGS_COMPILE = "-Wno-error=class-memaccess -Wno-error=maybe-uninitialized";
|
||||
cmakeFlags = (oldAttrs.cmakeFlags or []) ++ ["-DFLATBUFFERS_BUILD_SHAREDLIB=ON"];
|
||||
NIX_CXXSTDLIB_COMPILE = "-std=c++17";
|
||||
configureFlags = (oldAttrs.configureFlags or []) ++ ["--enable-shared"];
|
||||
src = fetchFromGitHub {
|
||||
owner = "google";
|
||||
repo = "flatbuffers";
|
||||
rev = "v${version}";
|
||||
sha256 = "sha256-L1B5Y/c897Jg9fGwT2J3+vaXsZ+lfXnskp8Gto1p/Tg=";
|
||||
};
|
||||
});
|
||||
|
||||
in stdenv.mkDerivation rec {
|
||||
pname = "libedgetpu";
|
||||
version = "grouper";
|
||||
|
||||
src = fetchFromGitHub {
|
||||
owner = "google-coral";
|
||||
repo = pname;
|
||||
rev = "release-${version}";
|
||||
sha256 = "sha256-73hwItimf88Iqnb40lk4ul/PzmCNIfdt6Afi+xjNiBE=";
|
||||
};
|
||||
|
||||
makeFlags = ["-f" "makefile_build/Makefile" "libedgetpu" ];
|
||||
|
||||
buildInputs = [
|
||||
libusb1
|
||||
abseil-cpp
|
||||
flatbuffers_1_12
|
||||
];
|
||||
|
||||
nativeBuildInputs = [
|
||||
xxd
|
||||
];
|
||||
|
||||
NIX_CXXSTDLIB_COMPILE = "-std=c++17";
|
||||
|
||||
TFROOT = "${fetchFromGitHub {
|
||||
owner = "tensorflow";
|
||||
repo = "tensorflow";
|
||||
rev = "v2.7.4";
|
||||
sha256 = "sha256-liDbUAdaVllB0b74aBeqNxkYNu/zPy7k3CevzRF5dk0=";
|
||||
}}";
|
||||
|
||||
enableParallelBuilding = false;
|
||||
|
||||
installPhase = ''
|
||||
mkdir -p $out/lib
|
||||
cp out/direct/k8/libedgetpu.so.1.0 $out/lib
|
||||
ln -s $out/lib/libedgetpu.so.1.0 $out/lib/libedgetpu.so.1
|
||||
mkdir -p $out/lib/udev/rules.d
|
||||
cp debian/edgetpu-accelerator.rules $out/lib/udev/rules.d/99-edgetpu-accelerator.rules
|
||||
'';
|
||||
}
|
||||
@@ -2,14 +2,14 @@
|
||||
|
||||
let
|
||||
container_name = "frigate";
|
||||
compose-dir = "docker-compose/frigate";
|
||||
config-dir = "/mnt/config-storage/docker-data/frigate";
|
||||
data-dir = "/mnt/data-storage/docker-data/frigate";
|
||||
compose_file = "podman/frigate/compose.yaml";
|
||||
config_dir = "/mnt/config/frigate";
|
||||
data_dir = "/mnt/data/frigate";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
@@ -17,16 +17,16 @@ in
|
||||
services:
|
||||
frigate:
|
||||
image: ghcr.io/blakeblackshear/frigate:stable
|
||||
container_name: frigate
|
||||
container_name: ${container_name}
|
||||
shm_size: "512MB"
|
||||
networks:
|
||||
hass_frontend:
|
||||
hass_backend:
|
||||
volumes:
|
||||
- ${config-dir}/config:/config
|
||||
- ${data-dir}/clips:/media/frigate/clips
|
||||
- ${data-dir}/recordings:/media/frigate/recordings
|
||||
- ${data-dir}/exports:/media/frigate/exports
|
||||
- ${config_dir}:/config
|
||||
- ${data_dir}/clips:/media/frigate/clips
|
||||
- ${data_dir}/recordings:/media/frigate/recordings
|
||||
- ${data_dir}/exports:/media/frigate/exports
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- type: tmpfs
|
||||
target: /tmp/cache
|
||||
@@ -41,7 +41,7 @@ in
|
||||
- traefik.http.services.frigate.loadbalancer.server.port=8971
|
||||
- traefik.http.services.frigate.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.frigate-https.entrypoints=websecure
|
||||
- traefik.http.routers.frigate-https.rule=Host(`cctv.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.frigate-https.rule=Host(`${container_name}.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.frigate-https.tls=true
|
||||
- traefik.http.routers.frigate-https.tls.certresolver=cloudflare
|
||||
restart: unless-stopped
|
||||
@@ -54,20 +54,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.frigate = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
@@ -2,26 +2,27 @@
|
||||
|
||||
let
|
||||
container_name = "gitea";
|
||||
compose-dir = "docker-compose/gitea";
|
||||
config-dir = "/mnt/config-storage/docker-data/gitea";
|
||||
compose_file = "podman/gitea/compose.yaml";
|
||||
config_dir = "/mnt/config/gitea";
|
||||
data_dir = "/mnt/data/gitea";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
/*DB_NAM
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
''
|
||||
services:
|
||||
gitea:
|
||||
image: gitea/gitea:latest
|
||||
container_name: gitea
|
||||
container_name: ${container_name}
|
||||
networks:
|
||||
gitea_frontend:
|
||||
gitea_backend:
|
||||
volumes:
|
||||
- ${config_dir}/data:/data
|
||||
- ${data_dir}:/data
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
environment:
|
||||
@@ -39,7 +40,7 @@ in
|
||||
- traefik.http.services.gitea.loadbalancer.server.port=3000
|
||||
- traefik.http.services.gitea.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.gitea-https.entrypoints=websecure
|
||||
- traefik.http.routers.gitea-https.rule=Host(`gitea.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.gitea-https.rule=Host(`${container_name}.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.gitea-https.tls=true
|
||||
- traefik.http.routers.gitea-https.tls.certresolver=cloudflare
|
||||
depends_on:
|
||||
@@ -56,12 +57,9 @@ in
|
||||
networks:
|
||||
gitea_backend:
|
||||
volumes:
|
||||
- gitea-database:/var/lib/postgresql/data
|
||||
- ${config_dir}:/var/lib/postgresql/data
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
gitea-database:
|
||||
|
||||
networks:
|
||||
gitea_frontend:
|
||||
external: true
|
||||
@@ -70,20 +68,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.gitea = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
+16
-15
@@ -2,13 +2,14 @@
|
||||
|
||||
let
|
||||
container_name = "home-assistant";
|
||||
compose-dir = "docker-compose/hass";
|
||||
config-dir = "/mnt/config-storage/docker-data/hass";
|
||||
compose_file = "podman/home-assistant/compose.yaml";
|
||||
config_dir_1 = "/mnt/config/home-assistant";
|
||||
config_dir_2 = "/mnt/config/mqtt";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
@@ -16,12 +17,12 @@ in
|
||||
services:
|
||||
home-assistant:
|
||||
image: ghcr.io/home-assistant/home-assistant:latest
|
||||
container_name: home-assistant
|
||||
container_name: ${container_name}
|
||||
networks:
|
||||
hass_frontend:
|
||||
hass_backend:
|
||||
volumes:
|
||||
- ${config-dir}/config:/config
|
||||
- ${config_dir_1}:/config
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /run/dbus:/run/dbus:ro
|
||||
# --- hass devices --- #
|
||||
@@ -30,19 +31,19 @@ in
|
||||
- traefik.http.services.home-assistant.loadbalancer.server.port=8123
|
||||
- traefik.http.services.home-assistant.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.home-assistant-https.entrypoints=websecure
|
||||
- traefik.http.routers.home-assistant-https.rule=Host(`hass.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.home-assistant-https.rule=Host(`${container_name}.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.home-assistant-https.tls=true
|
||||
- traefik.http.routers.home-assistant-https.tls.certresolver=cloudflare
|
||||
restart: unless-stopped
|
||||
|
||||
frigate-mqtt:
|
||||
image: eclipse-mosquitto
|
||||
container_name: frigate-mqtt
|
||||
container_name: mqtt
|
||||
user: 1000:1000
|
||||
networks:
|
||||
hass_backend:
|
||||
volumes:
|
||||
- ${config-dir}/mqtt:/mosquitto
|
||||
- ${config_dir_2}:/mosquitto
|
||||
restart: unless-stopped
|
||||
|
||||
networks:
|
||||
@@ -53,20 +54,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.hass = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
@@ -2,13 +2,14 @@
|
||||
|
||||
let
|
||||
container_name = "immich";
|
||||
compose-dir = "docker-compose/immich";
|
||||
config-dir = "/mnt/config-storage/docker-data/immich";
|
||||
compose_file = "podman/immich/compose.yaml";
|
||||
config_dir = "/mnt/config/immich";
|
||||
data_dir = "/mnt/data/immich";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
@@ -16,7 +17,7 @@ in
|
||||
services:
|
||||
immich-server:
|
||||
image: ghcr.io/immich-app/immich-server:$IMMICH_VERSION
|
||||
container_name: immich-server
|
||||
container_name: ${container_name}-server
|
||||
networks:
|
||||
immich_frontend:
|
||||
immich_backend:
|
||||
@@ -29,7 +30,7 @@ in
|
||||
- traefik.http.services.immich.loadbalancer.server.port=2283
|
||||
- traefik.http.services.immich.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.immich-https.entrypoints=websecure
|
||||
- traefik.http.routers.immich-https.rule=Host(`immich.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.immich-https.rule=Host(`${container_name}.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.immich-https.tls=true
|
||||
- traefik.http.routers.immich-https.tls.certresolver=cloudflare
|
||||
env_file:
|
||||
@@ -42,12 +43,12 @@ in
|
||||
disable: false
|
||||
|
||||
immich-machine-learning:
|
||||
container_name: immich-machine-learning
|
||||
container_name: ${container_name}-machine-learning
|
||||
image: ghcr.io/immich-app/immich-machine-learning:$IMMICH_VERSION
|
||||
networks:
|
||||
immich_backend:
|
||||
volumes:
|
||||
- ${config-dir}/models:/cache
|
||||
- ${config_dir}/models:/cache
|
||||
env_file:
|
||||
- .env
|
||||
restart: always
|
||||
@@ -55,7 +56,7 @@ in
|
||||
disable: false
|
||||
|
||||
immich-redis:
|
||||
container_name: immich-redis
|
||||
container_name: ${container_name}-redis
|
||||
image: docker.io/valkey/valkey:8-bookworm@sha256:a137a2b60aca1a75130022d6bb96af423fefae4eb55faf395732db3544803280
|
||||
networks:
|
||||
immich_backend:
|
||||
@@ -64,7 +65,7 @@ in
|
||||
restart: always
|
||||
|
||||
immich-database:
|
||||
container_name: immich-database
|
||||
container_name: ${container_name}-database
|
||||
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:32324a2f41df5de9efe1af166b7008c3f55646f8d0e00d9550c16c9822366b4a
|
||||
networks:
|
||||
immich_backend:
|
||||
@@ -89,20 +90,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.immich = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
+11
-11
@@ -2,19 +2,19 @@
|
||||
|
||||
let
|
||||
container_name = "it-tools";
|
||||
compose-dir = "docker-compose/it-tools";
|
||||
compose_file = "podman/it-tools/compose.yaml";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
''
|
||||
services:
|
||||
it-tools:
|
||||
container_name: it-tools
|
||||
container_name: ${container_name}
|
||||
image: corentinth/it-tools
|
||||
networks:
|
||||
it-tools:
|
||||
@@ -23,7 +23,7 @@ in
|
||||
- traefik.http.services.it-tools.loadbalancer.server.port=80
|
||||
- traefik.http.services.it-tools.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.it-tools-https.entrypoints=websecure
|
||||
- traefik.http.routers.it-tools-https.rule=Host(`it-tools.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.it-tools-https.rule=Host(`${container_name}.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.it-tools-https.tls=true
|
||||
- traefik.http.routers.it-tools-https.tls.certresolver=cloudflare
|
||||
restart: unless-stopped
|
||||
@@ -33,20 +33,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.it-tools = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
+13
-13
@@ -2,13 +2,13 @@
|
||||
|
||||
let
|
||||
container_name = "nextcloud";
|
||||
compose-dir = "docker-compose/nextcloud";
|
||||
data-dir = "/mnt/data-storage/docker-data/nextcloud";
|
||||
compose_file = "podman/nextcloud/compose.yaml";
|
||||
data_dir = "/mnt/data/nextcloud";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
@@ -16,7 +16,7 @@ in
|
||||
services:
|
||||
nextcloud-aio-mastercontainer:
|
||||
image: nextcloud/all-in-one:latest
|
||||
container_name: nextcloud-aio-mastercontainer
|
||||
container_name: ${container_name}-aio-mastercontainer
|
||||
networks:
|
||||
nextcloud-aio:
|
||||
volumes:
|
||||
@@ -27,7 +27,7 @@ in
|
||||
NEXTCLOUD_TRUSTED_DOMAINS: nextcloud.$DOMAIN_NAME nextcloud-aio.$DOMAIN_NAME
|
||||
TRUSTED_PROXIES: 172.16.1.253
|
||||
APACHE_IP_BINDING: 127.0.0.1
|
||||
NEXTCLOUD_DATADIR: ${data-dir}
|
||||
NEXTCLOUD_DATADIR: ${data_dir}
|
||||
NEXTCLOUD_ENABLE_DRI_DEVICE: $NEXTCLOUD_ENABLE_DRI_DEVICE
|
||||
NEXTCLOUD_UPLOAD_LIMIT: 16G
|
||||
NEXTCLOUD_MAX_TIME: 3600
|
||||
@@ -40,7 +40,7 @@ in
|
||||
- traefik.http.services.nextcloud-aio.loadbalancer.server.port=8080
|
||||
- traefik.http.services.nextcloud-aio.loadbalancer.server.scheme=https
|
||||
- traefik.http.routers.nextcloud-aio-https.entrypoints=websecure
|
||||
- traefik.http.routers.nextcloud-aio-https.rule=Host(`nextcloud-aio.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.nextcloud-aio-https.rule=Host(`${container_name}-aio.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.nextcloud-aio-https.tls=true
|
||||
- traefik.http.routers.nextcloud-aio-https.tls.certresolver=cloudflare
|
||||
init: true
|
||||
@@ -56,20 +56,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.nextcloud = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
+11
-11
@@ -2,12 +2,12 @@
|
||||
|
||||
let
|
||||
container_name = "passbolt";
|
||||
compose-dir = "docker-compose/passbolt";
|
||||
compose_file = "podman/passbolt/compose.yaml";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
@@ -15,7 +15,7 @@ in
|
||||
services:
|
||||
passbolt:
|
||||
image: passbolt/passbolt:latest-ce-non-root
|
||||
container_name: passbolt
|
||||
container_name: ${container_name}
|
||||
networks:
|
||||
passbolt_frontend:
|
||||
passbolt_backend:
|
||||
@@ -60,7 +60,7 @@ in
|
||||
|
||||
passbolt-database:
|
||||
image: mariadb:11.3
|
||||
container_name: passbolt-database
|
||||
container_name: ${container_name}-database
|
||||
networks:
|
||||
passbolt_backend:
|
||||
volumes:
|
||||
@@ -85,20 +85,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.passbolt = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
let
|
||||
container_name = "pihole";
|
||||
compose-dir = "docker-compose/pihole";
|
||||
config-dir = "/mnt/config-storage/docker-data/pihole";
|
||||
compose_file = "podman/pihole/compose.yaml";
|
||||
config_dir = "/mnt/config/pihole";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
@@ -16,7 +16,7 @@ in
|
||||
services:
|
||||
pihole:
|
||||
image: pihole/pihole:latest
|
||||
container_name: pihole
|
||||
container_name: ${container_name}
|
||||
networks:
|
||||
pihole:
|
||||
ports:
|
||||
@@ -42,7 +42,7 @@ in
|
||||
PIHOLE_UID: 1000
|
||||
PIHOLE_GID: 1000
|
||||
volumes:
|
||||
- ${config-dir}/config:/etc/pihole
|
||||
- ${config_dir}:/etc/pihole
|
||||
cap_add:
|
||||
- SYS_TIME
|
||||
- SYS_NICE
|
||||
@@ -51,7 +51,7 @@ in
|
||||
- traefik.http.services.pihole.loadbalancer.server.port=443
|
||||
- traefik.http.services.pihole.loadbalancer.server.scheme=https
|
||||
- traefik.http.routers.pihole-https.entrypoints=websecure
|
||||
- traefik.http.routers.pihole-https.rule=Host(`dns.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.pihole-https.rule=Host(`${container_name}.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.pihole-https.tls=true
|
||||
- traefik.http.routers.pihole-https.tls.certresolver=cloudflare
|
||||
restart: unless-stopped
|
||||
@@ -62,20 +62,20 @@ in
|
||||
'';
|
||||
|
||||
systemd.services.pihole = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" "traefik.service" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "traefik.service" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = ["multi-user.target"];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
let
|
||||
container_name = "traefik";
|
||||
compose-dir = "docker-compose/traefik";
|
||||
config-dir = "/mnt/config-storage/docker-data/traefik";
|
||||
compose_file = "podman/traefik/compose.yaml";
|
||||
config_dir = "/mnt/config/traefik";
|
||||
in
|
||||
|
||||
{
|
||||
config = {
|
||||
environment.etc."${compose-dir}/compose.yaml".text =
|
||||
environment.etc."${compose_file}".text =
|
||||
/*
|
||||
yaml
|
||||
*/
|
||||
@@ -16,7 +16,7 @@ in
|
||||
services:
|
||||
traefik:
|
||||
image: docker.io/library/traefik:latest
|
||||
container_name: traefik
|
||||
container_name: ${container_name}
|
||||
networks:
|
||||
nextcloud-aio:
|
||||
ipv4_address: 172.16.1.253
|
||||
@@ -28,14 +28,18 @@ in
|
||||
ipv4_address: 172.16.40.253
|
||||
immich_frontend:
|
||||
ipv4_address: 172.16.50.253
|
||||
gitea_frontend:
|
||||
ipv4_address: 172.16.60.253
|
||||
it-tools:
|
||||
ipv4_address: 172.16.7.253
|
||||
ports:
|
||||
- 80:80
|
||||
- 443:443
|
||||
volumes:
|
||||
- /run/docker.sock:/run/docker.sock:ro
|
||||
- ${config-dir}/config/conf/:/etc/traefik/conf/:ro
|
||||
- ${config-dir}/config/traefik.yaml:/etc/traefik/traefik.yaml:ro
|
||||
- ${config-dir}/certs/:/var/traefik/certs/:rw
|
||||
- /run/user/1000/podman/podman.sock:/run/docker.sock:ro
|
||||
- ${config_dir}/rules/:/etc/traefik/conf/:ro
|
||||
- ${config_dir}/traefik.yaml:/etc/traefik/traefik.yaml:ro
|
||||
- ${config_dir}/certs/:/var/traefik/certs/:rw
|
||||
environment:
|
||||
- CF_DNS_API_TOKEN=$CF_DNS_API_TOKEN
|
||||
labels:
|
||||
@@ -43,7 +47,7 @@ in
|
||||
- traefik.http.services.traefik.loadbalancer.server.port=8080
|
||||
- traefik.http.services.traefik.loadbalancer.server.scheme=http
|
||||
- traefik.http.routers.traefik-https.entrypoints=websecure
|
||||
- traefik.http.routers.traefik-https.rule=Host(`reverse.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.traefik-https.rule=Host(`${container_name}.$DOMAIN_NAME`)
|
||||
- traefik.http.routers.traefik-https.tls=true
|
||||
- traefik.http.routers.traefik-https.tls.certresolver=cloudflare
|
||||
restart: always
|
||||
@@ -104,23 +108,44 @@ in
|
||||
config:
|
||||
- subnet: "172.16.50.0/24"
|
||||
gateway: "172.16.50.254"
|
||||
gitea_backend:
|
||||
name: gitea_backend
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "172.16.6.0/24"
|
||||
gateway: "172.16.6.254"
|
||||
gitea_frontend:
|
||||
name: gitea_frontend
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "172.16.60.0/24"
|
||||
gateway: "172.16.60.254"
|
||||
it-tools:
|
||||
name: it-tools
|
||||
driver: bridge
|
||||
ipam:
|
||||
config:
|
||||
- subnet: "172.16.7.0/24"
|
||||
gateway: "172.16.7.254"
|
||||
'';
|
||||
|
||||
systemd.services.traefik = {
|
||||
description = "Docker container : ${container_name}";
|
||||
after = [ "network.target" "docker.service" "docker.socket" ];
|
||||
requires = [ "docker.service" ];
|
||||
description = "Podman container : ${container_name}";
|
||||
after = [ "network.target" "docker.socket" ];
|
||||
requires = [ "network.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
path = [ pkgs.docker ];
|
||||
path = [ pkgs.podman-compose ];
|
||||
|
||||
serviceConfig = {
|
||||
Type = "exec";
|
||||
# Pull the latest image before running
|
||||
ExecStartPre = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml pull";
|
||||
ExecStartPre = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} pull";
|
||||
# Bring the service up
|
||||
ExecStart = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml up --remove-orphans";
|
||||
ExecStart = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} up --remove-orphans";
|
||||
# Take it down gracefully
|
||||
ExecStop = "${pkgs.docker}/bin/docker compose -f /etc/${compose-dir}/compose.yaml down";
|
||||
ExecStop = "${pkgs.podman-compose}/bin/podman-compose -f /etc/${compose_file} down";
|
||||
|
||||
Restart = "on-failure";
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
ssh_public_keys: "${SSH_PUBLIC_KEY}"
|
||||
sender_email_address_password: "${SENDER_EMAIL_ADDRESS_PASSWORD}"
|
||||
|
||||
podman:
|
||||
frigate: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
FRIGATE_MQTT_USER="${HOME_ASSISTANT_MQTT_USER}"
|
||||
FRIGATE_MQTT_PASSWORD="${HOME_ASSISTANT_MQTT_PASSWORD}"
|
||||
gitea: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
DB_NAME="${GITEA_DB_NAME}"
|
||||
DB_USERNAME="${GITEA_DB_USERNAME}"
|
||||
DB_PASSWORD="${GITEA_DB_PASSWORD}"
|
||||
POSTGRES_HOST="gitea-database"
|
||||
POSTGRES_PORT="5432"
|
||||
home_assistant: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
HOME_ASSISTANT_MQTT_USER="${HOME_ASSISTANT_MQTT_USER}"
|
||||
HOME_ASSISTANT_MQTT_PASSWORD="${HOME_ASSISTANT_MQTT_PASSWORD}"
|
||||
immich: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
DB_DATABASE_NAME="${IMMICH_DB_NAME}"
|
||||
DB_USERNAME="${IMMICH_DB_USERNAME}"
|
||||
DB_PASSWORD="${IMMICH_DB_PASSWORD}"
|
||||
IMMICH_VERSION="release"
|
||||
IMMICH_TRUSTED_PROXIES="172.16.50.253"
|
||||
REDIS_HOSTNAME="immich-redis"
|
||||
DB_HOSTNAME="immich-database"
|
||||
UPLOAD_LOCATION="/mnt/data/immich"
|
||||
DB_DATA_LOCATION="/mnt/config/immich/database"
|
||||
TZ="Europe/Paris"
|
||||
it_tools: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
nextcloud: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
NEXTCLOUD_ENABLE_DRI_DEVICE="${TARGET_GRAPHICS}"
|
||||
passbolt: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
PASSBOLT_MYSQL_DATABASE="${PASSBOLT_DB_NAME}"
|
||||
PASSBOLT_MYSQL_USER="${PASSBOLT_DB_USERNAME}"
|
||||
PASSBOLT_MYSQL_PASSWORD="${PASSBOLT_DB_PASSWORD}"
|
||||
SENDER_EMAIL_ADDRESS="${SENDER_EMAIL_ADDRESS}"
|
||||
SENDER_EMAIL_ADDRESS_PASSWORD="${SENDER_EMAIL_ADDRESS_PASSWORD}"
|
||||
SENDER_EMAIL_DOMAIN="${SENDER_EMAIL_DOMAIN}"
|
||||
SENDER_EMAIL_PORT="${SENDER_EMAIL_PORT}"
|
||||
EMAIL_ADDRESS="${EMAIL_ADDRESS}"
|
||||
TZ="Europe/Paris"
|
||||
pi_hole: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
HOME_ROUTER_SUBNET="${HOME_ROUTER_SUBNET}"
|
||||
HOME_ROUTER_IP="${HOME_ROUTER_IP}"
|
||||
HOME_SERVER_IP="${HOME_SERVER_IP}"
|
||||
FTLCONF_webserver_api_password=$FTLCONF_WEBSERVER_PASSWORD
|
||||
TZ="Europe/Paris"
|
||||
traefik: |
|
||||
DOMAIN_NAME="${DOMAIN_NAME}"
|
||||
CF_DNS_API_TOKEN="${CF_DNS_API_TOKEN}"
|
||||
|
||||
disks:
|
||||
content-disk-1: "${CONTENT_DISK_1_KEY:-Undefined}"
|
||||
content-disk-2: "${CONTENT_DISK_2_KEY:-Undefined}"
|
||||
content-disk-3: "${CONTENT_DISK_3_KEY:-Undefined}"
|
||||
content-disk-4: "${CONTENT_DISK_4_KEY:-Undefined}"
|
||||
content-disk-5: "${CONTENT_DISK_5_KEY:-Undefined}"
|
||||
content-disk-6: "${CONTENT_DISK_6_KEY:-Undefined}"
|
||||
parity-disk-1: "${PARITY_DISK_1_KEY:-Undefined}"
|
||||
parity-disk-2: "${PARITY_DISK_2_KEY:-Undefined}"
|
||||
parity-disk-3: "${PARITY_DISK_3_KEY:-Undefined}"
|
||||
+1
-1
@@ -48,7 +48,7 @@ serversTransport:
|
||||
providers:
|
||||
docker:
|
||||
exposedByDefault: false
|
||||
network: nextcloud-aio, passbolt_frontend, pihole, hass_frontend, immich_frontend
|
||||
network: nextcloud-aio, passbolt_frontend, pihole, hass_frontend, immich_frontend, it-tools, gitrea_frontend
|
||||
file:
|
||||
directory: "/etc/traefik/conf/"
|
||||
watch: true
|
||||
@@ -0,0 +1,24 @@
|
||||
#TARGET SETTINGS
|
||||
TARGET_HOST="192.168.1.10"
|
||||
TARGET_SSH_PUBLIC_KEY="ssh-ed25519 AAAAoefzefpoipoeCEZJCPEACPAcjapjcpajepcjAPJECJPEJAPJAZ yours@yourdomain.com"
|
||||
# TRAEFIK SETTINGS
|
||||
DOMAIN_NAME="yourdomain.com"
|
||||
DOMAIN_EMAIL_ADDRESS="your-mail@yourdomain.com"
|
||||
DOMAIN_CF_DNS_API_TOKEN="yourToken"
|
||||
#SMTP SETTINGS
|
||||
SENDER_EMAIL_ADDRESS="youraddress@gmail.com"
|
||||
SENDER_EMAIL_ADDRESS_PASSWORD="emrp raps vzoi vnoe"
|
||||
SENDER_EMAIL_DOMAIN="smtp.yourdomain.com"
|
||||
SENDER_EMAIL_PORT="587"
|
||||
#NETWORK SETTINGS
|
||||
NETWORK_HOME_ROUTER_SUBNET="192.168.1.0/24"
|
||||
NETWORK_HOME_ROUTER_IP="192.168.1.1"
|
||||
NETWORK_HOME_SERVER_IP="192.168.1.5"
|
||||
# SERVICE SETTINGS
|
||||
SELECTED_SERVICES=("frigate" "home-assistant")
|
||||
# DISK SETTINGS
|
||||
BOOT_DISK_ID_LIST=("/dev/disk/by-id/nvme001-dfzpjvp")
|
||||
DATA_DISKS_ID_LIST=("/dev/disk/by-id/sata-barracuda-veojapoj")
|
||||
SPINDOWN_DISKS_ID_LIST=("/dev/disk/by-id/sata-barracuda-veojapoj")
|
||||
CONTENT_DISK_NUMBER=2
|
||||
PARITY_DISK_NUMBER=2
|
||||
@@ -0,0 +1,220 @@
|
||||
#!/usr/bin/env nix-shell
|
||||
#!nix-shell -i bash -p gum fastfetch xkcdpass sops ssh-to-age age sshpass envsubst pciutils usbutils mosquitto
|
||||
|
||||
networking() {
|
||||
SELECTED_SUBACTION=$(gum choose --header "Choose a setting to change:" "${NETWORKING_SETTINGS_LIST[@]}")
|
||||
|
||||
if [[ "$SELECTED_SUBACTION" = " 🏠 Change the home router subnet" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🌐 Change the home router IP address" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🖥️ Change the server's IP address" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🌍 Change the domain name" ]]; then
|
||||
echo "Some future logic here"
|
||||
else
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
backup() {
|
||||
SELECTED_SUBACTION=$(gum choose --header "Choose a setting to change:" "${BACKUP_SETTINGS_LIST[@]}")
|
||||
|
||||
if [[ "$SELECTED_SUBACTION" = " 🕣 Change the backup time" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 💾 Backup all data to a ssh remote" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 💿 Backup all data to a local folder" ]]; then
|
||||
echo "Some future logic here"
|
||||
else
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
services() {
|
||||
echo "Some future logic here"
|
||||
}
|
||||
|
||||
devices() {
|
||||
echo "Some future logic here"
|
||||
}
|
||||
|
||||
|
||||
disks() {
|
||||
SELECTED_SUBACTION=$(gum choose --header "Choose a setting to change:" "${DISKS_SETTINGS_LIST[@]}")
|
||||
|
||||
if [[ "$SELECTED_SUBACTION" = " ➕ Add or remove a boot disk" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " ➕ Add or remove data disk(s)" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🔄 Replace a boot disk" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🔄 Replace a data disk" ]]; then
|
||||
echo "Some future logic here"
|
||||
else
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
health() {
|
||||
SELECTED_SUBACTION=$(gum choose --header "Choose a setting to change:" "${SERVER_HEALTH_SETTINGS_LIST[@]}")
|
||||
|
||||
if [[ "$SELECTED_SUBACTION" = " 🩺 Check disk(s) health" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " ⛑️ Check service(s) health" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🌐 Check connectivity" ]]; then
|
||||
echo "Some future logic here"
|
||||
else
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
email() {
|
||||
SELECTED_SUBACTION=$(gum choose --header "Choose a setting to change:" "${EMAIL_SETTINGS_LIST[@]}")
|
||||
|
||||
if [[ "$SELECTED_SUBACTION" = " ⚙️ Change the server's email SMTP settings" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 📧 Change your personal email" ]]; then
|
||||
echo "Some future logic here"
|
||||
else
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
passwords() {
|
||||
SELECTED_SUBACTION=$(gum choose --header "Choose a setting to change:" "${PASSWORD_SETTINGS_LIST[@]}")
|
||||
|
||||
if [[ "$SELECTED_SUBACTION" = " 👁️ Display the server's configuration credentials" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🔧 Change the numbus-admin's password" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " 🔑 Add or remove SSH keys" ]]; then
|
||||
echo "Some future logic here"
|
||||
elif [[ "$SELECTED_SUBACTION" = " ⚙️ Change Cloudflare API token" ]]; then
|
||||
echo "Some future logic here"
|
||||
else
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
configuration_export() {
|
||||
echo "Some future logic here"
|
||||
}
|
||||
|
||||
### --> Main logic
|
||||
set -euo pipefail
|
||||
|
||||
fastfetch --logo nixos --structure ''
|
||||
|
||||
cat <<EOF
|
||||
|
||||
██████ █████ █████
|
||||
▒▒██████ ▒▒███ ▒▒███
|
||||
▒███▒███ ▒███ █████ ████ █████████████ ▒███████ █████ ████ █████
|
||||
▒███▒▒███▒███ ▒▒███ ▒███ ▒▒███▒▒███▒▒███ ▒███▒▒███▒▒███ ▒███ ███▒▒
|
||||
▒███ ▒▒██████ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒▒█████
|
||||
▒███ ▒▒█████ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒███ ▒▒▒▒███
|
||||
█████ ▒▒█████ ▒▒████████ █████▒███ █████ ████████ ▒▒████████ ██████
|
||||
▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒
|
||||
|
||||
█████████
|
||||
███▒▒▒▒▒███
|
||||
▒███ ▒▒▒ ██████ ████████ █████ █████ ██████ ████████
|
||||
▒▒█████████ ███▒▒███▒▒███▒▒███▒▒███ ▒▒███ ███▒▒███▒▒███▒▒███
|
||||
▒▒▒▒▒▒▒▒███▒███████ ▒███ ▒▒▒ ▒███ ▒███ ▒███████ ▒███ ▒▒▒
|
||||
███ ▒███▒███▒▒▒ ▒███ ▒▒███ ███ ▒███▒▒▒ ▒███
|
||||
▒▒█████████ ▒▒██████ █████ ▒▒█████ ▒▒██████ █████
|
||||
▒▒▒▒▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒ ▒▒▒▒▒▒ ▒▒▒▒▒
|
||||
|
||||
EOF
|
||||
|
||||
sleep 1
|
||||
|
||||
source /etc/numbus-server/numbus-server.conf
|
||||
|
||||
gum confirm "\n\n 🚀 Welcome to the Numbus-Server administration interface. Here,
|
||||
you can tweak the settings of your homelab. Do you want to continue?" \
|
||||
|| { echo " ❌ Aborting as requested."; exit 1; }
|
||||
|
||||
ACTIONS_LIST=(
|
||||
" 🛜 Update networking settings" \
|
||||
" 💾 Update backup settings" \
|
||||
" 📱 Add or remove services" \ # No further options
|
||||
" 🧩 Add or remove devices" \ # No further options
|
||||
" 💿 Change disks configuration" \
|
||||
" ⛑️ Check server health" \
|
||||
" 📧 Change email settings" \
|
||||
" 🔐 Passwords and keys management" \
|
||||
" ↥ Export current configuration to a git server" \ # No further options
|
||||
)
|
||||
|
||||
NETWORKING_SETTINGS_LIST=(
|
||||
" 🏠 Change the home router subnet" \
|
||||
" 🌐 Change the home router IP address" \
|
||||
" 🖥️ Change the server's IP address" \
|
||||
" 🌍 Change the domain name" \
|
||||
)
|
||||
|
||||
BACKUP_SETTINGS_LIST=(
|
||||
" 🕣 Change the backup time" \
|
||||
" 💾 Backup all data to a ssh remote" \
|
||||
" 💿 Backup all data to a local folder" \
|
||||
)
|
||||
|
||||
DISKS_SETTINGS_LIST=(
|
||||
" ➕ Add or remove a boot disk" \
|
||||
" ➕ Add or remove data disk(s)" \
|
||||
" 🔄 Replace a boot disk" \
|
||||
" 🔄 Replace a data disk" \
|
||||
)
|
||||
|
||||
SERVER_HEALTH_SETTINGS_LIST=(
|
||||
" 🩺 Check disk(s) health"
|
||||
" ⛑️ Check service(s) health"
|
||||
" 🌐 Check connectivity"
|
||||
)
|
||||
|
||||
EMAIL_SETTINGS_LIST=(
|
||||
" ⚙️ Change the server's email SMTP settings"
|
||||
" 📧 Change your personal email"
|
||||
)
|
||||
|
||||
PASSWORD_SETTINGS_LIST=(
|
||||
" 👁️ Display the server's configuration credentials"
|
||||
" 🔧 Change the numbus-admin's password"
|
||||
" 🔑 Add or remove SSH keys"
|
||||
" ⚙️ Change Cloudflare API token"
|
||||
)
|
||||
|
||||
SELECTED_ACTION=$(gum choose --header "Choose a setting to change:" "${ACTIONS_LIST[@]}")
|
||||
|
||||
if [[ "$SELECTED_ACTION" = " 🛜 Update networking settings" ]]; then
|
||||
networking
|
||||
elif [[ "$SELECTED_ACTION" = " 💾 Update backup settings" ]]; then
|
||||
backup
|
||||
elif [[ "$SELECTED_ACTION" = " 📱 Add or remove services" ]]; then
|
||||
services
|
||||
elif [[ "$SELECTED_ACTION" = " 🧩 Add or remove devices" ]]; then
|
||||
devices
|
||||
elif [[ "$SELECTED_ACTION" = " 💿 Change disks configuration" ]]; then
|
||||
disks
|
||||
elif [[ "$SELECTED_ACTION" = " ⛑️ Check server health" ]]; then
|
||||
health
|
||||
elif [[ "$SELECTED_ACTION" = " 📧 Change email settings" ]]; then
|
||||
email
|
||||
elif [[ "$SELECTED_ACTION" = " 🔐 Passwords and keys management" ]]; then
|
||||
passwords
|
||||
elif [[ "$SELECTED_ACTION" = " ↥ Export current configuration to a git server" ]]; then
|
||||
configuration_export
|
||||
else
|
||||
echo -e "\n\n ❌ Unexpected bug. Please contact the developer. Aborting."
|
||||
exit 1
|
||||
fi
|
||||
### Main logic <--
|
||||
Reference in New Issue
Block a user