#!/bin/bash # # Nextcloud Stack - Interactive Setup Script # This script collects all configuration variables and generates Ansible inventory # set -euo pipefail # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' # No Color # Header clear echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ Nextcloud Stack - Ansible Deployment Setup ║${NC}" echo -e "${CYAN}║ Version 1.0 ║${NC}" echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}" echo "" echo "This script will guide you through configuring your Nextcloud" echo "deployment. Information will be encrypted using Ansible Vault." echo "" # Arrays to store server data declare -a SERVER_IPS declare -a SERVER_HOSTNAMES declare -a SERVER_DOMAINS declare -a SERVER_SSH_USERS declare -a SERVER_SSH_KEYS # Global variables ADMIN_USER="" ADMIN_PASSWORD="" USER_NAME="" USER_EMAIL="" TIMEZONE="Europe/Zurich" INSTALL_RCLONE="y" ENABLE_PUBLIC_STATUS="n" ALERT_EMAIL="" TAILSCALE_AUTH_KEY="" # Subdomain defaults SUBDOMAIN_NEXTCLOUD="cloud" SUBDOMAIN_OFFICE="office" SUBDOMAIN_DRAW="draw" SUBDOMAIN_NOTES="notes" SUBDOMAIN_HOMARR="home" SUBDOMAIN_DOCKHAND="manage" SUBDOMAIN_UPTIME="uptime" # Database defaults DB_NAME="nextcloud" DB_USER="nextcloud" # Generate random password generate_password() { openssl rand -base64 32 | tr -d "=+/" | cut -c1-32 } # Validate IP address validate_ip() { local ip=$1 if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then return 0 else return 1 fi } # Validate domain validate_domain() { local domain=$1 if [[ $domain =~ ^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$ ]]; then return 0 else return 1 fi } # Server Configuration echo -e "${GREEN}=== Server Configuration ===${NC}" echo "Enter server details (press Enter without input to finish):" echo "" server_count=0 while true; do ((server_count++)) echo -e "${BLUE}Server $server_count:${NC}" # IP Address while true; do read -p " IP address: " ip if [[ -z "$ip" ]]; then ((server_count--)) break 2 fi if validate_ip "$ip"; then SERVER_IPS+=("$ip") break else echo -e "${RED} Invalid IP address. Please try again.${NC}" fi done # Hostname read -p " Hostname [cloud$(printf "%02d" $server_count)]: " hostname hostname=${hostname:-cloud$(printf "%02d" $server_count)} SERVER_HOSTNAMES+=("$hostname") # Domain while true; do read -p " Domain (e.g., example.com): " domain if [[ -z "$domain" ]]; then echo -e "${RED} Domain is required. Please try again.${NC}" elif validate_domain "$domain"; then SERVER_DOMAINS+=("$domain") break else echo -e "${RED} Invalid domain format. Please try again.${NC}" fi done # SSH User read -p " SSH user [root]: " ssh_user ssh_user=${ssh_user:-root} SERVER_SSH_USERS+=("$ssh_user") # SSH Key read -p " SSH key path [~/.ssh/id_rsa]: " ssh_key ssh_key=${ssh_key:-~/.ssh/id_rsa} # Expand tilde ssh_key="${ssh_key/#\~/$HOME}" SERVER_SSH_KEYS+=("$ssh_key") echo "" done if [[ ${#SERVER_IPS[@]} -eq 0 ]]; then echo -e "${RED}Error: At least one server is required.${NC}" exit 1 fi echo -e "${GREEN}✓ Configured ${#SERVER_IPS[@]} server(s)${NC}" echo "" # User Information echo -e "${GREEN}=== User Information ===${NC}" read -p "Your name: " USER_NAME while [[ -z "$USER_NAME" ]]; do echo -e "${RED}Name is required.${NC}" read -p "Your name: " USER_NAME done read -p "Your email: " USER_EMAIL while [[ -z "$USER_EMAIL" ]] || [[ ! "$USER_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; do echo -e "${RED}Valid email is required.${NC}" read -p "Your email: " USER_EMAIL done read -p "Timezone [Europe/Zurich]: " TIMEZONE TIMEZONE=${TIMEZONE:-Europe/Zurich} echo "" # Nextcloud Admin Account echo -e "${GREEN}=== Nextcloud Admin Account ===${NC}" read -p "Admin username [admin]: " ADMIN_USER ADMIN_USER=${ADMIN_USER:-admin} while true; do read -sp "Admin password: " ADMIN_PASSWORD echo "" read -sp "Confirm password: " ADMIN_PASSWORD_CONFIRM echo "" if [[ "$ADMIN_PASSWORD" == "$ADMIN_PASSWORD_CONFIRM" ]] && [[ ${#ADMIN_PASSWORD} -ge 8 ]]; then break elif [[ ${#ADMIN_PASSWORD} -lt 8 ]]; then echo -e "${RED}Password must be at least 8 characters.${NC}" else echo -e "${RED}Passwords do not match. Please try again.${NC}" fi done echo "" # Subdomain Configuration echo -e "${GREEN}=== Subdomain Configuration ===${NC}" echo "Press Enter to use defaults shown in brackets" read -p "Nextcloud subdomain [cloud]: " SUBDOMAIN_NEXTCLOUD SUBDOMAIN_NEXTCLOUD=${SUBDOMAIN_NEXTCLOUD:-cloud} read -p "OnlyOffice subdomain [office]: " SUBDOMAIN_OFFICE SUBDOMAIN_OFFICE=${SUBDOMAIN_OFFICE:-office} read -p "Excalidraw subdomain [draw]: " SUBDOMAIN_DRAW SUBDOMAIN_DRAW=${SUBDOMAIN_DRAW:-draw} read -p "Obsidian subdomain [notes]: " SUBDOMAIN_NOTES SUBDOMAIN_NOTES=${SUBDOMAIN_NOTES:-notes} read -p "Homarr subdomain [home]: " SUBDOMAIN_HOMARR SUBDOMAIN_HOMARR=${SUBDOMAIN_HOMARR:-home} read -p "Dockhand subdomain [manage]: " SUBDOMAIN_DOCKHAND SUBDOMAIN_DOCKHAND=${SUBDOMAIN_DOCKHAND:-manage} read -p "Uptime Kuma subdomain [uptime]: " SUBDOMAIN_UPTIME SUBDOMAIN_UPTIME=${SUBDOMAIN_UPTIME:-uptime} echo "" # Database Configuration echo -e "${GREEN}=== Database Configuration ===${NC}" read -p "Database name [nextcloud]: " DB_NAME DB_NAME=${DB_NAME:-nextcloud} read -p "Database user [nextcloud]: " DB_USER DB_USER=${DB_USER:-nextcloud} echo "Generating secure passwords..." DB_PASSWORD=$(generate_password) REDIS_PASSWORD=$(generate_password) HOMARR_SECRET=$(openssl rand -hex 32) echo -e "${GREEN}✓ Passwords generated${NC}" echo "" # Tailscale Configuration echo -e "${GREEN}=== Tailscale Configuration ===${NC}" read -p "Install Tailscale? (y/n) [y]: " install_tailscale install_tailscale=${install_tailscale:-y} if [[ "$install_tailscale" == "y" ]]; then read -p "Tailscale auth key (optional, press Enter to skip): " TAILSCALE_AUTH_KEY if [[ -z "$TAILSCALE_AUTH_KEY" ]]; then echo "Note: Tailscale will be installed but not activated." echo " Activate manually with: sudo tailscale up" fi fi echo "" # Monitoring Configuration echo -e "${GREEN}=== Monitoring Configuration ===${NC}" read -p "Email for uptime alerts: " ALERT_EMAIL while [[ -z "$ALERT_EMAIL" ]] || [[ ! "$ALERT_EMAIL" =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; do echo -e "${RED}Valid email is required.${NC}" read -p "Email for uptime alerts: " ALERT_EMAIL done read -p "Enable public status page? (y/n) [n]: " ENABLE_PUBLIC_STATUS ENABLE_PUBLIC_STATUS=${ENABLE_PUBLIC_STATUS:-n} echo "" # Backup Configuration echo -e "${GREEN}=== Backup Configuration ===${NC}" echo "Backup retention: 30 days (default)" read -p "Install rclone for future remote backups? (y/n) [y]: " INSTALL_RCLONE INSTALL_RCLONE=${INSTALL_RCLONE:-y} if [[ "$INSTALL_RCLONE" == "y" ]]; then echo "Note: rclone will be installed but not configured." echo " Configure later with: rclone config" fi echo "" # Ansible Vault Password echo -e "${GREEN}=== Security ===${NC}" echo "Create Ansible Vault password (will encrypt all secrets):" while true; do read -sp "Vault password: " VAULT_PASSWORD echo "" read -sp "Confirm: " VAULT_PASSWORD_CONFIRM echo "" if [[ "$VAULT_PASSWORD" == "$VAULT_PASSWORD_CONFIRM" ]] && [[ ${#VAULT_PASSWORD} -ge 8 ]]; then break elif [[ ${#VAULT_PASSWORD} -lt 8 ]]; then echo -e "${RED}Password must be at least 8 characters.${NC}" else echo -e "${RED}Passwords do not match. Please try again.${NC}" fi done echo "" # Configuration Summary echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ CONFIGURATION SUMMARY ║${NC}" echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}" echo "" echo "Servers: ${#SERVER_IPS[@]}" for i in "${!SERVER_IPS[@]}"; do echo " • ${SERVER_IPS[$i]} (${SERVER_DOMAINS[$i]})" done echo "" echo "Services (per server):" echo " • Nextcloud: https://$SUBDOMAIN_NEXTCLOUD." echo " • OnlyOffice: https://$SUBDOMAIN_OFFICE." echo " • Excalidraw: https://$SUBDOMAIN_DRAW." echo " • Obsidian: https://$SUBDOMAIN_NOTES." echo " • Homarr: https://$SUBDOMAIN_HOMARR. (Tailscale)" echo " • Dockhand: https://$SUBDOMAIN_DOCKHAND. (Tailscale)" echo " • Uptime Kuma: https://$SUBDOMAIN_UPTIME. (Tailscale)" echo "" read -p "Proceed with these settings? (y/n): " confirm if [[ "$confirm" != "y" ]]; then echo "Setup cancelled." exit 0 fi echo "" # Generate Configuration Files echo "Generating configuration files..." # Create inventory directory mkdir -p inventory/group_vars/all # Generate hosts.yml cat >inventory/hosts.yml <>inventory/hosts.yml <inventory/group_vars/all/vars.yml <.vault_pass_temp # Create encrypted vault echo "$VAULT_CONTENT" | ansible-vault encrypt --vault-password-file=.vault_pass_temp --output=inventory/group_vars/all/vault.yml # Clean up temp file rm .vault_pass_temp echo -e "${GREEN}✓ Created: inventory/group_vars/all/vault.yml (encrypted)${NC}" echo "" # Save vault password hint echo "IMPORTANT: Save your vault password!" echo "You will need it to run the playbook." echo "" echo "Vault password: **************** (hidden)" echo "" # Final Instructions echo -e "${CYAN}╔════════════════════════════════════════════════════════════╗${NC}" echo -e "${CYAN}║ READY TO DEPLOY! ║${NC}" echo -e "${CYAN}╚════════════════════════════════════════════════════════════╝${NC}" echo "" echo "Next steps:" echo "" echo "1. Review configuration (optional):" echo " ansible-inventory --list" echo "" echo "2. Test connectivity:" echo " ansible all -m ping --ask-vault-pass" echo "" echo "3. Deploy stack:" echo " ansible-playbook playbooks/site.yml --ask-vault-pass" echo "" echo " OR use Makefile:" echo " make deploy" echo "" echo "Estimated deployment time: 30-45 minutes per server" echo "" echo -e "${YELLOW}WARNING: Ensure DNS records are configured before deploying!${NC}" echo " Let's Encrypt will fail if DNS is not pointing correctly." echo "" echo "Required DNS records for each server:" for i in "${!SERVER_DOMAINS[@]}"; do echo " ${SERVER_DOMAINS[$i]}:" echo " $SUBDOMAIN_NEXTCLOUD.${SERVER_DOMAINS[$i]} → ${SERVER_IPS[$i]}" echo " $SUBDOMAIN_OFFICE.${SERVER_DOMAINS[$i]} → ${SERVER_IPS[$i]}" echo " $SUBDOMAIN_DRAW.${SERVER_DOMAINS[$i]} → ${SERVER_IPS[$i]}" echo " $SUBDOMAIN_NOTES.${SERVER_DOMAINS[$i]} → ${SERVER_IPS[$i]}" echo " $SUBDOMAIN_HOMARR.${SERVER_DOMAINS[$i]} → ${SERVER_IPS[$i]}" echo " $SUBDOMAIN_DOCKHAND.${SERVER_DOMAINS[$i]} → ${SERVER_IPS[$i]}" echo " $SUBDOMAIN_UPTIME.${SERVER_DOMAINS[$i]} → ${SERVER_IPS[$i]}" echo "" done echo "" echo "Setup complete! 🎉"