|
|
|
@@ -7,10 +7,10 @@ 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" \
|
|
|
|
|
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" "SELECTED_SERVICES" "SERVER_OWNER_NAME")
|
|
|
|
|
"HOME_SERVER_IP" "SELECTED_SERVICES" "SERVER_OWNER_NAME" )
|
|
|
|
|
### Default settings <--
|
|
|
|
|
|
|
|
|
|
user_input() {
|
|
|
|
@@ -141,7 +141,7 @@ hardware_detection() {
|
|
|
|
|
|
|
|
|
|
ssh_to_host 'bash -s' << SSHEND
|
|
|
|
|
for brand in Intel AMD NVIDIA; do
|
|
|
|
|
if lspci -nn 2>/dev/null | grep -i "vga" | grep -iq "\${brand}"; then
|
|
|
|
|
if lspci -nn > /dev/null 2>&1 | grep -i "vga" | grep -iq "\${brand}"; then
|
|
|
|
|
TARGET_GRAPHICS="true"
|
|
|
|
|
TARGET_GRAPHICS_BRAND+=("\${brand}")
|
|
|
|
|
else
|
|
|
|
@@ -149,14 +149,14 @@ for brand in Intel AMD NVIDIA; do
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
ls /dev/dri/ 2>/dev/null | grep -iq "renderD128" && TARGET_GRAPHICS_RENDERER="true" || TARGET_GRAPHICS_RENDERER="false"
|
|
|
|
|
lsusb 2>/dev/null | grep -iq "google" && TARGET_USB_CORAL="true" || TARGET_USB_CORAL="false"
|
|
|
|
|
lspci -nn 2>/dev/null | grep -iq "089a" && TARGET_PCIE_CORAL="true" || TARGET_PCIE_CORAL="false"
|
|
|
|
|
ls /dev/serial/by-id/ 2>/dev/null | grep -i "zigbee" && TARGET_ZIGBEE_DEVICE=\$(ls /dev/serial/by-id/ 2>/dev/null | grep -i "zigbee" | head -n 1) || TARGET_ZIGBEE_DEVICE=""
|
|
|
|
|
ls /dev/dri/ > /dev/null 2>&1 | grep -iq "renderD128" && TARGET_GRAPHICS_RENDERER="true" || TARGET_GRAPHICS_RENDERER="false"
|
|
|
|
|
lsusb > /dev/null 2>&1 | grep -iq "google" && TARGET_USB_CORAL="true" || TARGET_USB_CORAL="false"
|
|
|
|
|
lspci -nn > /dev/null 2>&1 | grep -iq "089a" && TARGET_PCIE_CORAL="true" || TARGET_PCIE_CORAL="false"
|
|
|
|
|
ls /dev/serial/by-id/ > /dev/null 2>&1 | grep -i "zigbee" && TARGET_ZIGBEE_DEVICE=\$(ls /dev/serial/by-id/ > /dev/null 2>&1 | grep -i "zigbee" | head -n 1) || TARGET_ZIGBEE_DEVICE=""
|
|
|
|
|
|
|
|
|
|
TARGET_INTERFACE=\$(ip -4 route show default | awk '{print \$5}' | head -n1)
|
|
|
|
|
|
|
|
|
|
if ls -l /sys/class/tpm/tpm0/ >/dev/null 2>&1; then
|
|
|
|
|
if ls -l /sys/class/tpm/tpm0/ > /dev/null 2>&1; then
|
|
|
|
|
TARGET_TPM="true"
|
|
|
|
|
TARGET_TPM_VERSION=\$(cat /sys/class/tpm/tpm0/tpm_version_major)
|
|
|
|
|
else
|
|
|
|
@@ -186,7 +186,7 @@ for DISK in \$(lsblk -x SIZE -d -n -e 7,11 -o NAME); do
|
|
|
|
|
else DISK_TYPE+=("Other")
|
|
|
|
|
fi
|
|
|
|
|
# Disk health
|
|
|
|
|
if [[ \$(echo "$REMOTE_PASS" | sudo -S smartctl -H /dev/\$DISK 2>/dev/null | grep 'self-assessment' | awk '{print \$6}') == "PASSED" ]]; then
|
|
|
|
|
if [[ \$(echo "$REMOTE_PASS" | sudo -S smartctl -H /dev/\$DISK > /dev/null 2>&1 | grep 'self-assessment' | awk '{print \$6}') == "PASSED" ]]; then
|
|
|
|
|
DISK_HEALTH+=("PASSED")
|
|
|
|
|
else
|
|
|
|
|
DISK_HEALTH+=("N/A")
|
|
|
|
@@ -239,7 +239,7 @@ SSHEND
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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:"
|
|
|
|
|
|
|
|
|
|
local AVAILABLE_SERVICES=( "frigate" "gitea" "home-assistant" "immich" "it-tools" \
|
|
|
|
|
"nextcloud" "passbolt" "pi-hole" "virtualization" )
|
|
|
|
@@ -258,12 +258,20 @@ services_selection() {
|
|
|
|
|
local SELECTED_SERVICES_DESCRIPTION=$(gum choose --no-limit --header "Homelab services:" "${SERVICES_DESCRIPTION[@]}")
|
|
|
|
|
|
|
|
|
|
for i in ${!AVAILABLE_SERVICES[@]}; do
|
|
|
|
|
if printf '%s' "$SELECTED_SERVICES_DESCRIPTION" | grep -iq "${AVAILABLE_SERVICES[$i]}"; then
|
|
|
|
|
SELECTED_SERVICES+=(${AVAILABLE_SERVICES[$i]})
|
|
|
|
|
if printf '%s' "${SELECTED_SERVICES_DESCRIPTION}" | grep -iq "${AVAILABLE_SERVICES[${i}]}"; then
|
|
|
|
|
SELECTED_SERVICES+=("${AVAILABLE_SERVICES[${i}]}")
|
|
|
|
|
if [[ "${AVAILABLE_SERVICES[${i}]}" == "nextcloud" ]]; then
|
|
|
|
|
SELECTED_SERVICES_DNS+=("nextcloud.${DOMAIN_NAME}" "nextcloud-aio.${DOMAIN_NAME}")
|
|
|
|
|
elif [[ "${AVAILABLE_SERVICES[${i}]}" == "virtualization" ]]; then
|
|
|
|
|
:
|
|
|
|
|
else
|
|
|
|
|
SELECTED_SERVICES_DNS+=("${AVAILABLE_SERVICES[${i}]}.${DOMAIN_NAME}")
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
export SELECTED_SERVICES
|
|
|
|
|
export SELECTED_SERVICES_DNS
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
disks_selection() {
|
|
|
|
@@ -274,14 +282,14 @@ disks_selection() {
|
|
|
|
|
!! 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)"
|
|
|
|
|
echo -e "\n\n 🔎 Fetching and analyzing disks from target host... (This may take a moment)"
|
|
|
|
|
### Disk wiping warning <--
|
|
|
|
|
|
|
|
|
|
### --> Disk selection
|
|
|
|
|
if [[ "${#DISK_NAME[@]}" -eq 0 ]]; then
|
|
|
|
|
echo -e "\n❌ No disks found on the target host. Aborting."
|
|
|
|
|
echo -e "\n ❌ No disks found on the target host. Aborting."
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
@@ -291,13 +299,13 @@ disks_selection() {
|
|
|
|
|
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}]}")
|
|
|
|
|
local GUM_PRINTED_ELEMENTS+=("$GUM_PRINTED_ELEMENT")
|
|
|
|
|
local GUM_PRINTED_ELEMENTS+=("${GUM_PRINTED_ELEMENT}")
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
echo ""
|
|
|
|
|
gum style --foreground 212 "➡️ Please choose one (stripe) or two (mirror) disks for your NixOS boot installation :"
|
|
|
|
|
|
|
|
|
|
local 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
|
|
|
|
@@ -308,23 +316,23 @@ disks_selection() {
|
|
|
|
|
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 "\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]}"
|
|
|
|
|
export BOOT_DISK_1_NAME="${DISK_NAME[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⚠️ If the two disks are different sizes, the resulting usable space size will be \
|
|
|
|
|
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]}"
|
|
|
|
|
export BOOT_DISK_1_NAME="${BOOT_DISKS_NAME[0]}"
|
|
|
|
|
export BOOT_DISK_2_NAME="${BOOT_DISKS_NAME[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
|
|
|
|
|
|
|
|
|
@@ -384,7 +392,7 @@ services_generation() {
|
|
|
|
|
export "${SERVICE_UPPER}_DB_PASSWORD"="$(xkcdpass -d "-")"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo -e "\n✅ Writing configuration files for the selected homelab services..."
|
|
|
|
|
echo -e "\n ✅ Writing configuration files for the selected homelab services..."
|
|
|
|
|
cp templates/nix-config/podman/traefik.nix final-nix-config/etc/nixos/podman/traefik.nix
|
|
|
|
|
cp -avu templates/nix-config/configuration.nix final-nix-config/etc/nixos/configuration.nix
|
|
|
|
|
envsubst < templates/podman-config/traefik/traefik.yaml > final-nix-config/mnt/config/traefik/traefik.yaml
|
|
|
|
@@ -473,7 +481,7 @@ services_generation() {
|
|
|
|
|
|
|
|
|
|
disks_generation() {
|
|
|
|
|
# Boot disk(s)
|
|
|
|
|
echo -e "\n\n✅ Generating disko configuration from templates..."
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
@@ -527,7 +535,7 @@ disks_generation() {
|
|
|
|
|
MOUNT_DEPENDENCIES_STOP+=" \${pkgs.util-linux}/bin/umount /mnt/content-${j}"$'\n'
|
|
|
|
|
MOUNT_DEPENDENCIES_STOP+=" \${pkgs.cryptsetup}/bin/cryptsetup close crypted-content-${j}"$'\n'
|
|
|
|
|
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 $CONTENT_DISK_NUMBER $((${#DATA_DISKS_ID[@]} - 1))); do
|
|
|
|
|
export j=$((j + 1))
|
|
|
|
@@ -541,7 +549,7 @@ disks_generation() {
|
|
|
|
|
MOUNT_DEPENDENCIES_STOP+=" \${pkgs.util-linux}/bin/umount /mnt/parity-${j}"$'\n'
|
|
|
|
|
MOUNT_DEPENDENCIES_STOP+=" \${pkgs.cryptsetup}/bin/cryptsetup close crypted-parity-${j}"$'\n'
|
|
|
|
|
done
|
|
|
|
|
echo -e "\n✅ Generated $PARITY_DISK_NUMBER parity disk configuration(s)."
|
|
|
|
|
echo -e "\n ✅ Generated $PARITY_DISK_NUMBER parity disk configuration(s)."
|
|
|
|
|
export SNAPRAID_CONTENT_FILES
|
|
|
|
|
export SNAPRAID_DATA_DISKS
|
|
|
|
|
export SNAPRAID_PARITY_FILES
|
|
|
|
@@ -557,7 +565,7 @@ disks_generation() {
|
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
@@ -572,7 +580,7 @@ EOF
|
|
|
|
|
FORMATTED_DISKS+=" \"$disk\"\n"
|
|
|
|
|
done
|
|
|
|
|
sed -i "s|DISK_LIST|${FORMATTED_DISKS}|" final-nix-config/etc/nixos/disks/spindown.nix
|
|
|
|
|
echo -e "\n✅ Disk spindown configuration created."
|
|
|
|
|
echo -e "\n ✅ Disk spindown configuration created."
|
|
|
|
|
fi
|
|
|
|
|
fi
|
|
|
|
|
### Config generation <--
|
|
|
|
@@ -601,20 +609,20 @@ EOF
|
|
|
|
|
PASS="$(xkcdpass)"
|
|
|
|
|
echo -n "$PASS" > "final-nix-config/etc/secrets/disks/parity-${i}"
|
|
|
|
|
chmod 600 "final-nix-config/etc/secrets/disks/parity-${i}"
|
|
|
|
|
ssh_to_host 'bash -s' << EOF
|
|
|
|
|
ssh_to_host 'bash -s' << EOF
|
|
|
|
|
echo "$REMOTE_PASS" | sudo -S bash -c "printf '%s' '$PASS' > /etc/secrets/disks/parity-${i}"
|
|
|
|
|
EOF
|
|
|
|
|
done
|
|
|
|
|
### Generate disk keys <--
|
|
|
|
|
|
|
|
|
|
echo -e "\n✅ Generating sops-nix keys..."
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
echo -e "\n✅ Generating sops-nix configuration files..."
|
|
|
|
|
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✅ Encrypting secrets in the correct file..."
|
|
|
|
|
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 \
|
|
|
|
@@ -623,12 +631,12 @@ EOF
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nix_generation() {
|
|
|
|
|
echo -e "\n✅ Copying the configuration to the new machine..."
|
|
|
|
|
echo -e "\n ✅ Copying the configuration to the new machine..."
|
|
|
|
|
cp -avu templates/nix-config/flake.nix final-nix-config/etc/nixos/
|
|
|
|
|
cp -avu templates/nix-config/misc/* final-nix-config/etc/nixos/misc/
|
|
|
|
|
|
|
|
|
|
echo "${SERVER_OWNER_NAME:-User}" > final-nix-config/etc/numbus-server/owner
|
|
|
|
|
echo -e "\n✅ Writing correct ips to configuration.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
|
|
|
|
|
sed -i "s|TARGET_INTERFACE|${TARGET_INTERFACE}|g" final-nix-config/etc/nixos/misc/networking.nix
|
|
|
|
@@ -668,7 +676,7 @@ EOF
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "$(gum format <<< "${DISK_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; }
|
|
|
|
|
### Disk selection recap <--
|
|
|
|
|
|
|
|
|
|
### Keys recap <--
|
|
|
|
@@ -701,7 +709,7 @@ EOF
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "$(gum format <<< "${KEYS_RECAP_CONTENT}")"
|
|
|
|
|
gum confirm "Do you want to deploy NixOS on the target host?" || { echo -e "\n\n❌ Aborting as requested"; exit 1; }
|
|
|
|
|
gum confirm "Do you want to deploy NixOS on the target host?" || { echo -e "\n\n ❌ Aborting as requested"; exit 1; }
|
|
|
|
|
### Keys recap <--
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -729,59 +737,86 @@ export_configuration() {
|
|
|
|
|
echo -e "\n# Podman SETTINGS" >> $CONFIG_EXPORT_FILE
|
|
|
|
|
echo "export PODMAN_NETWORKS=\"${PODMAN_NETWORKS}\"" >> $CONFIG_EXPORT_FILE
|
|
|
|
|
echo "export TRAEFIK_NETWORKS=\"${TRAEFIK_NETWORKS}\"" >> $CONFIG_EXPORT_FILE
|
|
|
|
|
echo "export TRAEFIK_REF_NETWORKS=\"${TRAEFIK_REF_NETWORKS}\"" >> $CONFIG_EXPORT_FILE
|
|
|
|
|
echo "export TRAEFIK_REF_NETWORKS=\"${TRAEFIK_REF_NETWORKS}\"" >> $CONFIG_EXPORT_FILE
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cloudflare_dns_setup() {
|
|
|
|
|
echo -e "\n\n☁️ Configuring Cloudflare DNS records..."
|
|
|
|
|
local ZONE_ID && local RECORD_COUNT && local IS_MATCHING
|
|
|
|
|
local DNS_RECORDS && local CREATION_STATUS
|
|
|
|
|
|
|
|
|
|
# 1. Get Zone ID
|
|
|
|
|
local ZONE_ID
|
|
|
|
|
create_records() {
|
|
|
|
|
local SUBDOMAIN="${1}"
|
|
|
|
|
local CREATION_STATUS
|
|
|
|
|
|
|
|
|
|
CREATION_STATUS=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
|
|
|
|
|
-H "Authorization: Bearer ${CF_DNS_API_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
--data "{\"type\":\"A\",\"name\":\"${SUBDOMAIN}\",\"content\":\"${HOME_SERVER_IP}\",\"ttl\":1,\"proxied\":false}" | jq -r '.success')
|
|
|
|
|
|
|
|
|
|
if [[ "${CREATION_STATUS}" == "true" ]]; then
|
|
|
|
|
echo " ✅ Successfully create a DNS record for ${SUBDOMAIN}"
|
|
|
|
|
else
|
|
|
|
|
echo -e " ❌ Failed to create a DNS record for ${SUBDOMAIN}. Check documentation to \n
|
|
|
|
|
learn how you can create them manually."
|
|
|
|
|
fi
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
erase_records() {
|
|
|
|
|
local SUBDOMAIN="${1}"
|
|
|
|
|
local DELETION_STATUS
|
|
|
|
|
|
|
|
|
|
gum style --border normal --margin "1" --padding "1 2" --border-foreground 212 "
|
|
|
|
|
⚠️ $(gum style --foreground 212 'WARNING:') One or more existing type A DNS records found for \`${SUBDOMAIN}\`.
|
|
|
|
|
This script can clear those DNS records for you and create the correct ones needed for the server.
|
|
|
|
|
If you are unsure that these records are actually in use, please select \"no\"."
|
|
|
|
|
gum confirm "Select \"yes\" to clear ALL EXISTING type A DNS records for this subdomain and automatically create the correct ones." \
|
|
|
|
|
|| { echo -e "\n ⚠️ DNS records for ${SUBDOMAIN} will not be updated"; return 0; }
|
|
|
|
|
|
|
|
|
|
RECORD_IDS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${SUBDOMAIN}&type=A" \
|
|
|
|
|
-H "Authorization: Bearer ${CF_DNS_API_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" | jq -r '.result[].id')
|
|
|
|
|
|
|
|
|
|
for id in ${RECORD_IDS}; do
|
|
|
|
|
curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records/${id}" \
|
|
|
|
|
-H "Authorization: Bearer ${CF_DNS_API_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" > /dev/null 2>&1
|
|
|
|
|
done
|
|
|
|
|
|
|
|
|
|
create_records "${SUBDOMAIN}"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
echo -e "\n\n ☁️ Configuring Cloudflare DNS records..."
|
|
|
|
|
|
|
|
|
|
# Get Zone ID
|
|
|
|
|
ZONE_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones?name=${DOMAIN_NAME}" \
|
|
|
|
|
-H "Authorization: Bearer ${CF_DNS_API_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" | jq -r '.result[0].id')
|
|
|
|
|
|
|
|
|
|
if [[ "${ZONE_ID}" == "null" || -z "${ZONE_ID}" ]]; then
|
|
|
|
|
echo -e "\n\n⚠️ Could not fetch Zone ID for ${DOMAIN_NAME}. Please check your Cloudflare \"DNS ZONE\" API token"
|
|
|
|
|
echo "Check out the Numbus-Server documentation to see out to get one."
|
|
|
|
|
echo -e "\n\n ⚠️ Could not fetch Zone ID for ${DOMAIN_NAME}. Please check your Cloudflare \"DNS ZONE\" API token"
|
|
|
|
|
echo "Check the Numbus-Server documentation to learn how to get one."
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
# 2. Iterate services
|
|
|
|
|
for service in "${SELECTED_SERVICES[@]}"; do
|
|
|
|
|
if [[ "${service}" == "virtualization" ]]; then continue; fi
|
|
|
|
|
|
|
|
|
|
local SUBDOMAIN="${service}.${DOMAIN_NAME}"
|
|
|
|
|
echo -n " - Checking for existing record : ${SUBDOMAIN}..."
|
|
|
|
|
|
|
|
|
|
# Check existence
|
|
|
|
|
local RECORD_ID
|
|
|
|
|
RECORD_ID=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${SUBDOMAIN}&type=A" \
|
|
|
|
|
# Check for existing records and create them if non-existent
|
|
|
|
|
for service_domain in "${SELECTED_SERVICES_DNS[@]}"; do
|
|
|
|
|
DNS_RECORDS=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${service_domain}&type=A" \
|
|
|
|
|
-H "Authorization: Bearer ${CF_DNS_API_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" | jq -r '.result[0].id')
|
|
|
|
|
-H "Content-Type: application/json")
|
|
|
|
|
|
|
|
|
|
if [[ "${RECORD_ID}" != "null" && -n "${RECORD_ID}" ]]; then
|
|
|
|
|
RECORD_ID_CONTENT=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records?name=${SUBDOMAIN}&type=A" \
|
|
|
|
|
-H "Authorization: Bearer ${CF_DNS_API_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" | jq -r '.result[0].content')
|
|
|
|
|
if [[ "${RECORD_ID_CONTENT}" == "${HOME_SERVER_IP}" ]]; then
|
|
|
|
|
echo " ✅ Already configured"
|
|
|
|
|
else
|
|
|
|
|
echo " ⚠️ A DNS record is configured but does not point to the correct IP"
|
|
|
|
|
echo "Do you want to update it? It could break past DNS record you defined"
|
|
|
|
|
fi
|
|
|
|
|
else
|
|
|
|
|
echo -n " ⏳ Creating..."
|
|
|
|
|
local CREATE_RES
|
|
|
|
|
CREATE_RES=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
|
|
|
|
|
-H "Authorization: Bearer ${CF_DNS_API_TOKEN}" \
|
|
|
|
|
-H "Content-Type: application/json" \
|
|
|
|
|
--data "{\"type\":\"A\",\"name\":\"${SUBDOMAIN}\",\"content\":\"${HOME_SERVER_IP}\",\"ttl\":1,\"proxied\":false}" | jq -r '.success')
|
|
|
|
|
RECORD_COUNT=$(echo "${DNS_RECORDS}" | jq '.result | length')
|
|
|
|
|
|
|
|
|
|
if [[ "${CREATE_RES}" == "true" ]]; then
|
|
|
|
|
echo " ✅ Created."
|
|
|
|
|
if [[ "${RECORD_COUNT}" -eq 0 ]]; then
|
|
|
|
|
echo -e "\n ⚠️ No DNS record found for ${service_domain}"
|
|
|
|
|
create_records "${service_domain}"
|
|
|
|
|
elif [[ "${RECORD_COUNT}" -eq 1 ]]; then
|
|
|
|
|
if [[ $(echo "${DNS_RECORDS}" | jq ".result[0].content == \"${HOME_SERVER_IP}\"") == "true" ]]; then
|
|
|
|
|
echo -e "\n ✅ DNS record already configured for ${service_domain}"
|
|
|
|
|
else
|
|
|
|
|
echo " ❌ Failed."
|
|
|
|
|
echo -e "\n ⚠️ No DNS record found for ${service_domain}"
|
|
|
|
|
erase_records "${service_domain}"
|
|
|
|
|
fi
|
|
|
|
|
elif [[ "${RECORD_COUNT}" -gt 1 ]]; then
|
|
|
|
|
erase_records "${service_domain}"
|
|
|
|
|
fi
|
|
|
|
|
done
|
|
|
|
|
}
|
|
|
|
|