#!/usr/bin/env bash set -euo pipefail # Ensure we're in a flakes-enabled environment with required tools if ! command -v nix &> /dev/null; then echo "❌ Nix is not installed. Please install Nix first:" echo "curl --proto '=https' --tlsv1.2 -sSf -L https://install.determinate.systems/nix | sh -s -- install" exit 1 fi # Check if we need to enter a new shell if [ -z "${INSIDE_NIX_SHELL+x}" ]; then export NIX_CONFIG="experimental-features = nix-command flakes" export INSIDE_NIX_SHELL=1 exec nix shell nixpkgs#git nixpkgs#mkpasswd --command bash "$0" fi # Function to setup from template setup_from_template() { local TEMPLATE=starter local DIR_NAME="self-host-playbook" if [ -d "$DIR_NAME" ]; then echo "📂 Directory '$DIR_NAME' already exists" read -p "Do you want to proceed in the existing directory? (y/N) " -n 1 -r echo if [[ $REPLY =~ ^[Yy]$ ]]; then cd "$DIR_NAME" else echo "❌ Please choose a different directory or remove the existing one" exit 1 fi else echo "🔄 Creating new self-host-playbook configuration from template..." nix flake new --template "git+https://code.m3tam3re.com/m3tam3re/self-host-playbook#${TEMPLATE}" "$DIR_NAME" cd "$DIR_NAME" fi } # Function to generate SSH key generate_ssh_key() { local KEY_NAME="self-host-playbook" local KEY_PATH="$HOME/.ssh/${KEY_NAME}" if [ ! -f "$KEY_PATH" ]; then mkdir -p "$HOME/.ssh" echo "🔑 Generating new SSH key pair..." >&2 ssh-keygen -t ed25519 -f "$KEY_PATH" -N "" >&2 echo "✅ New SSH key pair generated" >&2 else echo "🔑 Using existing SSH key pair" >&2 fi if [ ! -f "${KEY_PATH}.pub" ]; then echo "❌ Error: Public key file not found" >&2 exit 1 fi printf "%s" "$KEY_PATH" } # Function to hash password using mkpasswd hash_password() { local password=$1 mkpasswd -m sha-512 "$password" } # Function to display device detection guide show_device_guide() { echo echo "📝 How to find your root device name:" echo "------------------------------------" echo "1. SSH into your server with the credentials provided by your cloud provider or use the web console" echo "2. Run the following command:" echo " lsblk -d -o NAME,SIZE" echo echo "Look for the main disk, usually the largest one. It will be shown as:" echo "- AWS (older): xvda" echo "- AWS (newer): nvme0n1" echo "- GCP/Azure/Linode: sda" echo "- DigitalOcean: vda" echo echo "The device name will be /dev/[name shown in lsblk]" echo echo "💡 Example:" echo " NAME SIZE" echo " sda 76.3G" echo " sr0 1024M" echo "------------------------------------" echo } # Function to get device name based on provider get_device_name() { local provider=$1 case $provider in "aws-new") echo "/dev/nvme0n1" ;; "aws-old") echo "/dev/xvda" ;; "gcp") echo "/dev/sda" ;; "azure") echo "/dev/sda" ;; "digitalocean") echo "/dev/vda" ;; "linode") echo "/dev/sda" ;; "hetzner") echo "/dev/sda" ;; *) echo "unknown" ;; esac } echo "🚀 Welcome to the Self-Host Playbook!" echo "================================================" echo "This script will help you manage your NixOS server with:" echo "- Portainer (Docker management)" echo "- n8n (Workflow automation)" echo "- Baserow (No-code database)" echo "- Caddy (Automatic HTTPS reverse proxy)" echo "================================================" echo read -p "Press ANY KEY to continue or CTRL + C to abort..." echo # Generate SSH key SSH_KEY_PATH=$(generate_ssh_key) || exit 1 SSH_PUB_KEY=$(cat "${SSH_KEY_PATH}.pub") || { echo "❌ Error: Failed to read public key from ${SSH_KEY_PATH}.pub" exit 1 } echo echo "🔑 Here is your public key:" echo cat $SSH_KEY_PATH.pub echo "" echo "📁 You can also find the keyfile here:" echo echo $SSH_KEY_PATH.pub echo read -p "Press ENTER to continue or CTRL + C to abort..." # Collect user input echo "" echo "📝 Please provide the following information:" echo "-------------------------------------------" read -p "1. Enter target server IP address: " SERVER_IP read -p "2. Enter desired username for server access: " USERNAME read -s -p "3. Enter desired password: " PASSWORD echo echo "4. Enter domain names for services (must point to $SERVER_IP):" read -p " - Domain for Portainer: " PORTAINER_DOMAIN read -p " - Domain for n8n: " N8N_DOMAIN read -p " - Domain for Baserow: " BASEROW_DOMAIN echo echo "5. How do you authentiate to the target machine?" echo "-------------------------------------------" echo " 1) Password" echo " 2) SSH Key" echo read -p "Enter your choice (1-2): " KEY_CHOICE case $KEY_CHOICE in 1) INSTALL_COMMAND="nix run github:nix-community/nixos-anywhere -- --flake .#server root@$SERVER_IP" ;; 2) INSTALL_COMMAND="nix run github:nix-community/nixos-anywhere -- --flake .#server -i $SSH_KEY_PATH root@$SERVER_IP" ;; *) echo "❌ Invalid choice" exit 1 ;; esac setup_from_template echo echo "6. Select your cloud provider:" echo " 1) AWS (Newer instances with NVMe)" echo " 2) AWS (Older instances)" echo " 3) Google Cloud Platform" echo " 4) Microsoft Azure" echo " 5) DigitalOcean" echo " 6) Linode" echo " 7) Hetzner" echo " 8) I'm not sure (Show detection guide)" echo read -p "Enter your choice (1-8): " PROVIDER_CHOICE # Set device name based on provider choice case $PROVIDER_CHOICE in 1) PROVIDER="aws-new" ;; 2) PROVIDER="aws-old" ;; 3) PROVIDER="gcp" ;; 4) PROVIDER="azure" ;; 5) PROVIDER="digitalocean" ;; 6) PROVIDER="linode" ;; 7) PROVIDER="hetzner" ;; 8) show_device_guide read -p "Enter your root device name (e.g., /dev/sda): " DEVICE_NAME PROVIDER="custom" ;; *) echo "❌ Invalid choice" exit 1 ;; esac if [ "$PROVIDER" != "custom" ]; then DEVICE_NAME=$(get_device_name "$PROVIDER") fi echo echo "Using root device: $DEVICE_NAME" read -p "Is this correct? (y/N) " CONFIRM if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then echo "Installation aborted. Please run the script again with the correct device." exit 1 fi echo echo "🛠️ Preparing server configuration..." # Hash the password HASHED_PASSWORD=$(hash_password "$PASSWORD") echo "📝 Customizing configuration files..." # Write configuration to JSON file cat > config.json << EOF { "username": "$USERNAME", "hashedPassword": "$HASHED_PASSWORD", "sshKey": "$SSH_PUB_KEY", "domains": { "portainer": "$PORTAINER_DOMAIN", "n8n": "$N8N_DOMAIN", "baserow": "$BASEROW_DOMAIN" }, "rootDevice": "$DEVICE_NAME" } EOF echo "📦 Setting up environment files..." # Update environment files with domains if [[ "$OSTYPE" == "darwin"* ]]; then sed -i '' "s/N8N_DOMAIN/$N8N_DOMAIN/g" ./env/n8n.env sed -i '' "s/BASEROW_DOMAIN/$BASEROW_DOMAIN/g" ./env/baserow.env else sed -i "s/N8N_DOMAIN/$N8N_DOMAIN/g" ./env/n8n.env sed -i "s/BASEROW_DOMAIN/$BASEROW_DOMAIN/g" ./env/baserow.env fi echo echo "⚠️ Important: By proceeding the existing virtual machine will be overwritten!" echo read -p "Do you want to proceed? (y/N) " CONFIRM if [[ ! $CONFIRM =~ ^[Yy]$ ]]; then echo "Installation aborted." exit 1 fi echo echo "🚀 Starting NixOS installation..." echo "This process might take several minutes..." # Run nixos-anywhere installation $INSTALL_COMMAND && { echo echo "🎉 Installation completed successfully!" echo "=====================================>" echo "You can now access your services at:" echo "- Portainer: https://$PORTAINER_DOMAIN" echo "- n8n: https://$N8N_DOMAIN" echo "- Baserow: https://$BASEROW_DOMAIN" echo echo "To connect to your server, use:" echo "ssh -i $SSH_KEY_PATH -p 2222 $USERNAME@$SERVER_IP" echo echo "⚠️ Important: Please save your SSH key path: $SSH_KEY_PATH" echo "=====================================>" } || echo "Command failed with exit status $?"