#!/bin/bash # nullpoint installer - run this from Hetzner rescue mode # wget -qO- https://git.dominik-roth.eu/dodox/nullpoint/raw/branch/master/install.sh | bash set -euo pipefail # If we're being piped, save to a temp file and re-execute if [ ! -t 0 ]; then TEMP_SCRIPT=$(mktemp) cat > "$TEMP_SCRIPT" chmod +x "$TEMP_SCRIPT" exec bash "$TEMP_SCRIPT" fi BANNER=$(cat << "EOF" :^7J5GB##&&##GPY?~: ^75B&@@@@@@&&&@@@@@@@#GJ~: 5&@@@&B5?7~^^^^^~!7YP#@@@@#! Y##P7^ :~JB#B! :: : 7PP?: :^~!!~^: :?PP7 :B@@B: !5B&@@@@&B5! :#@@B: :!!: ^G@@@&BPPB@@@@G^ :!!: :B@@@5^ ^5@@@B: :7J7: !@@@# :&@@@~ :?J7: J@@@5 :#@@@Y: :Y@@@B: 5@@@J !@@@&^ ~B@@@&G55G&@@@B~ ~&@@@~ 5@@@G: :7P#@@@@@@#P7: :B@@@Y :P@@@B~ :~!77!~: ~B@@@P Y@@@&Y^ ^5@@@@J !G@@@&P7^ ^7P&@@@G~ !P&@@@&B? :: ?B&@@@&P! ^75#&&Y :P&&5: 5&&B57^ :^^ :P&&5: ^^: ^^ [nullpoint] EOF ) clear echo -e "\n$BANNER" echo -e "\n[+] nullpoint installer starting..." # Check if we're in Hetzner rescue mode if [ ! -f /etc/hetzner-build ]; then echo "ERROR: This script must be run from Hetzner rescue mode!" exit 1 fi # Get SSH key from current session echo "[+] Detecting SSH key from current session..." SSH_KEY=$(grep "^ssh-" ~/.ssh/authorized_keys | head -1) if [ -z "$SSH_KEY" ]; then echo "ERROR: No SSH key found in authorized_keys!" echo "Please enter your SSH public key:" read -r SSH_KEY if [ -z "$SSH_KEY" ]; then echo "SSH key is required!" exit 1 fi fi echo "Found SSH key: ${SSH_KEY:0:50}..." # Ask for hostname echo -e "\n[+] Server configuration" read -r -p "Enter hostname [nullpoint]: " HOSTNAME < /dev/tty HOSTNAME=${HOSTNAME:-nullpoint} # Ask for username read -r -p "Enter username for admin account [null]: " USERNAME < /dev/tty USERNAME=${USERNAME:-null} # Generate secure LUKS passphrase echo -e "\n[+] Generating secure LUKS passphrase..." LUKS_PASS=$(openssl rand -base64 30) echo -e "\n================================================" echo "LUKS PASSPHRASE (SAVE THIS!):" echo "$LUKS_PASS" echo "================================================" echo -e "\nPress Enter when you've saved the passphrase..." read -r < /dev/tty # Clone or download the nullpoint repo echo "[+] Downloading nullpoint configuration..." if command -v git &> /dev/null; then git clone https://git.dominik-roth.eu/dodox/nullpoint.git /tmp/nullpoint else echo "ERROR: git not available and wget fallback insufficient for dotfiles" echo "Please install git or use manual installation method" exit 1 fi # Update install.conf echo "[+] Configuring installation..." cd /tmp/nullpoint # Auto-detect drives echo "[+] Detecting drives..." DRIVES=($(lsblk -dno NAME,TYPE | grep disk | awk '{print "/dev/"$1}' | sort)) if [ ${#DRIVES[@]} -lt 2 ]; then echo "ERROR: Need at least 2 drives for RAID1, found ${#DRIVES[@]}" exit 1 fi DRIVE1="${DRIVES[0]}" DRIVE2="${DRIVES[1]}" echo " Found drives: $DRIVE1 and $DRIVE2" # Update install.conf with detected drives if ! sed -i "s|^DRIVE1 .*|DRIVE1 $DRIVE1|" install.conf; then echo "ERROR: Failed to update DRIVE1 in install.conf" exit 1 fi if ! sed -i "s|^DRIVE2 .*|DRIVE2 $DRIVE2|" install.conf; then echo "ERROR: Failed to update DRIVE2 in install.conf" exit 1 fi # Update hostname if ! sed -i "s/^HOSTNAME .*/HOSTNAME $HOSTNAME/" install.conf; then echo "ERROR: Failed to update HOSTNAME in install.conf" exit 1 fi # Use awk for CRYPTPASSWORD to handle special characters if ! awk -v pass="$LUKS_PASS" ' /^CRYPTPASSWORD / { print "CRYPTPASSWORD " pass; next } { print } ' install.conf > install.conf.tmp; then echo "ERROR: Failed to update CRYPTPASSWORD in install.conf" exit 1 fi mv install.conf.tmp install.conf # Update post-install.sh if ! sed -i "s/^ALMA_USER=.*/ALMA_USER=\"$USERNAME\"/" post-install.sh; then echo "ERROR: Failed to update ALMA_USER in post-install.sh" exit 1 fi # Use awk to replace SSH_KEY line to avoid sed issues with special characters if ! awk -v key="$SSH_KEY" ' /^SSH_KEY=/ { print "SSH_KEY=\"" key "\""; next } { print } ' post-install.sh > post-install.sh.tmp; then echo "ERROR: Failed to update SSH_KEY in post-install.sh" exit 1 fi mv post-install.sh.tmp post-install.sh # Copy to root directory where installimage expects them if ! cp install.conf /root/; then echo "ERROR: Failed to copy install.conf to /root/" exit 1 fi if ! cp post-install.sh /root/; then echo "ERROR: Failed to copy post-install.sh to /root/" exit 1 fi chmod +x /root/post-install.sh # Ask for optional features echo -e "\n[+] Optional features:" read -r -p "Do you have a TPM and want to use it? [y/N]: " USE_TPM < /dev/tty if [[ "$USE_TPM" =~ ^[Yy]$ ]]; then echo "TPM will be configured if available." else sed -i 's/^TPM_ENABLED=.*/TPM_ENABLED=false/' /root/post-install.sh fi read -r -p "Do you want to configure remote unlock Tang servers? [y/N]: " USE_TANG < /dev/tty if [[ "$USE_TANG" =~ ^[Yy]$ ]]; then echo "Configuring Tang servers..." TANG_CONFIG="" while true; do read -r -p "Enter Tang server URL (or press Enter to finish): " TANG_URL < /dev/tty if [ -z "$TANG_URL" ]; then break fi read -r -p "Enter thumbprint for $TANG_URL: " TANG_THUMBPRINT < /dev/tty if [ -n "$TANG_THUMBPRINT" ]; then TANG_CONFIG+=" \"$TANG_URL $TANG_THUMBPRINT\"\n" echo "Added Tang server: $TANG_URL" else echo "Skipping server (no thumbprint provided)" fi done if [ -n "$TANG_CONFIG" ]; then # Update the TANG_SERVERS array in post-install.sh sed -i '/^TANG_SERVERS=(/,/^)/ { /^TANG_SERVERS=(/ { r /dev/stdin d } /^)/ !d }' /root/post-install.sh << EOF TANG_SERVERS=( $TANG_CONFIG) EOF echo "Configured Tang servers in post-install script." else echo "No Tang servers configured." fi fi # Final confirmation echo -e "\n[+] Ready to install with these settings:" echo " Hostname: $HOSTNAME" echo " Username: $USERNAME" echo " SSH Key: ${SSH_KEY:0:50}..." echo " LUKS Passphrase: $LUKS_PASS" echo "" read -r -p "Proceed with installation? [Y/n]: " CONFIRM < /dev/tty if [[ "$CONFIRM" =~ ^[Nn]$ ]]; then echo "Installation cancelled." exit 1 fi # Check if installimage exists if ! command -v installimage &> /dev/null; then echo "ERROR: installimage command not found!" echo "This might not be a Hetzner rescue system, or installimage is not in PATH." echo "On Hetzner rescue, installimage is usually at /root/.oldroot/nfs/install/installimage" # Try common locations if [ -x "/root/.oldroot/nfs/install/installimage" ]; then echo "Found installimage at /root/.oldroot/nfs/install/installimage" INSTALLIMAGE_CMD="/root/.oldroot/nfs/install/installimage" else echo "Could not find installimage. Please check your Hetzner rescue environment." exit 1 fi else INSTALLIMAGE_CMD="installimage" fi # Run the installer echo -e "\n[+] Starting Hetzner installimage..." echo "The installer will now run. Follow any prompts if needed." echo "" if ! $INSTALLIMAGE_CMD -a -c /root/install.conf -s /root/post-install.sh; then echo -e "\nERROR: Installation failed!" exit 1 fi echo -e "\n[+] Installation complete!" echo "" echo "IMPORTANT REMINDERS:" echo "1. Save your LUKS passphrase securely!" echo "2. After reboot, you'll need to enter it twice (once per disk)" echo "3. SSH to the server as user '$USERNAME'" echo "" echo "The system is ready for use!"