added ansible script
This commit is contained in:
463
ansible/setup.sh
Executable file
463
ansible/setup.sh
Executable file
@@ -0,0 +1,463 @@
|
||||
#!/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.<domain>"
|
||||
echo " • OnlyOffice: https://$SUBDOMAIN_OFFICE.<domain>"
|
||||
echo " • Excalidraw: https://$SUBDOMAIN_DRAW.<domain>"
|
||||
echo " • Obsidian: https://$SUBDOMAIN_NOTES.<domain>"
|
||||
echo " • Homarr: https://$SUBDOMAIN_HOMARR.<domain> (Tailscale)"
|
||||
echo " • Dockhand: https://$SUBDOMAIN_DOCKHAND.<domain> (Tailscale)"
|
||||
echo " • Uptime Kuma: https://$SUBDOMAIN_UPTIME.<domain> (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 <<EOF
|
||||
# Ansible Inventory - Generated by setup.sh
|
||||
# Date: $(date)
|
||||
|
||||
all:
|
||||
children:
|
||||
nextcloud_servers:
|
||||
hosts:
|
||||
EOF
|
||||
|
||||
for i in "${!SERVER_IPS[@]}"; do
|
||||
cat >>inventory/hosts.yml <<EOF
|
||||
${SERVER_HOSTNAMES[$i]}:
|
||||
ansible_host: ${SERVER_IPS[$i]}
|
||||
ansible_user: ${SERVER_SSH_USERS[$i]}
|
||||
ansible_ssh_private_key_file: ${SERVER_SSH_KEYS[$i]}
|
||||
domain: ${SERVER_DOMAINS[$i]}
|
||||
EOF
|
||||
done
|
||||
|
||||
echo -e "${GREEN}✓ Created: inventory/hosts.yml${NC}"
|
||||
|
||||
# Generate vars.yml (public variables)
|
||||
cat >inventory/group_vars/all/vars.yml <<EOF
|
||||
# Public Variables - Generated by setup.sh
|
||||
# Date: $(date)
|
||||
|
||||
# User Information
|
||||
user_name: "$USER_NAME"
|
||||
user_email: "$USER_EMAIL"
|
||||
timezone: "$TIMEZONE"
|
||||
|
||||
# Admin Account
|
||||
admin_user: "$ADMIN_USER"
|
||||
|
||||
# Subdomain Configuration
|
||||
subdomain_nextcloud: "$SUBDOMAIN_NEXTCLOUD"
|
||||
subdomain_office: "$SUBDOMAIN_OFFICE"
|
||||
subdomain_draw: "$SUBDOMAIN_DRAW"
|
||||
subdomain_notes: "$SUBDOMAIN_NOTES"
|
||||
subdomain_homarr: "$SUBDOMAIN_HOMARR"
|
||||
subdomain_dockhand: "$SUBDOMAIN_DOCKHAND"
|
||||
subdomain_uptime: "$SUBDOMAIN_UPTIME"
|
||||
|
||||
# Database Configuration
|
||||
db_name: "$DB_NAME"
|
||||
db_user: "$DB_USER"
|
||||
|
||||
# Backup Configuration
|
||||
backup_retention_days: 30
|
||||
install_rclone: $INSTALL_RCLONE
|
||||
|
||||
# Monitoring
|
||||
alert_email: "$ALERT_EMAIL"
|
||||
enable_public_status: $ENABLE_PUBLIC_STATUS
|
||||
|
||||
# Deployment Settings
|
||||
deployment_dir: "/opt/nextcloud-stack"
|
||||
stack_name: "nextcloud"
|
||||
|
||||
# Docker Configuration
|
||||
docker_compose_version: "v2"
|
||||
EOF
|
||||
|
||||
echo -e "${GREEN}✓ Created: inventory/group_vars/all/vars.yml${NC}"
|
||||
|
||||
# Generate vault.yml (encrypted secrets)
|
||||
VAULT_CONTENT=$(
|
||||
cat <<EOF
|
||||
# Encrypted Secrets - Generated by setup.sh
|
||||
# Date: $(date)
|
||||
|
||||
# Admin Password
|
||||
admin_password: "$ADMIN_PASSWORD"
|
||||
|
||||
# Database Credentials
|
||||
db_password: "$DB_PASSWORD"
|
||||
redis_password: "$REDIS_PASSWORD"
|
||||
|
||||
# Application Secrets
|
||||
homarr_secret: "$HOMARR_SECRET"
|
||||
|
||||
# Tailscale
|
||||
tailscale_auth_key: "$TAILSCALE_AUTH_KEY"
|
||||
EOF
|
||||
)
|
||||
|
||||
# Save vault password to temporary file
|
||||
echo "$VAULT_PASSWORD" >.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! 🎉"
|
||||
Reference in New Issue
Block a user