Files
n8n-install/scripts/install-local.sh

332 lines
12 KiB
Bash

#!/bin/bash
# =============================================================================
# install-local.sh - Local installation for n8n-install
# =============================================================================
# Runs the local development installation process (6 steps):
# 1. Secret Generation - generates passwords, API keys, bcrypt hashes
# 2. Service Selection Wizard - interactive service selection
# 3. Configure Services - service-specific configuration
# 4. Run Services - starts Docker Compose stack
# 5. Final Report - displays credentials and URLs
# 6. Fix Permissions - fixes file permissions
#
# Requirements:
# - Docker and Docker Compose installed and running
# - Bash 4.0+ (macOS: brew install bash)
# - whiptail (macOS: brew install newt)
# - openssl, git, python3
#
# Usage:
# make install-local
# Or directly: bash scripts/install-local.sh
# =============================================================================
# =============================================================================
# Check bash version FIRST (requires bash 4+ for associative arrays)
# =============================================================================
if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
echo "[ERROR] Bash 4.0 or higher is required. Current version: $BASH_VERSION"
echo ""
echo "On macOS, install modern bash and run with it:"
echo " brew install bash"
echo " /opt/homebrew/bin/bash ./scripts/install-local.sh"
echo ""
echo "Or use: make install-local"
exit 1
fi
set -e
# Local mode is fixed for this script
export INSTALL_MODE="local"
# Source the utilities file
source "$(dirname "$0")/utils.sh"
# Initialize paths
init_paths
# Source local mode utilities
source "$SCRIPT_DIR/local.sh"
# Source telemetry functions
source "$SCRIPT_DIR/telemetry.sh"
# =============================================================================
# Prerequisites Check (inline)
# =============================================================================
check_prerequisites() {
log_subheader "Checking Prerequisites for Local Installation"
local MISSING_DEPS=()
# Check Docker
log_info "Checking Docker..."
if ! command -v docker &> /dev/null; then
MISSING_DEPS+=("docker")
print_error "Docker is not installed"
case "$(uname)" in
Darwin)
log_info " Install Docker Desktop: https://www.docker.com/products/docker-desktop"
;;
Linux)
log_info " Install Docker: https://docs.docker.com/engine/install/"
;;
MINGW*|MSYS*|CYGWIN*)
log_info " Install Docker Desktop for Windows: https://www.docker.com/products/docker-desktop"
log_info " Then enable WSL2 integration in Docker Desktop settings"
;;
esac
else
local docker_version
docker_version=$(docker --version 2>/dev/null || echo "unknown")
print_ok "Docker is installed: $docker_version"
# Check Docker daemon
if ! docker info > /dev/null 2>&1; then
MISSING_DEPS+=("docker-daemon")
print_error "Docker daemon is not running"
case "$(uname)" in
Darwin)
log_info " Start Docker Desktop from Applications"
;;
Linux)
log_info " Start Docker: sudo systemctl start docker"
;;
esac
else
print_ok "Docker daemon is running"
fi
fi
# Check Docker Compose
log_info "Checking Docker Compose..."
if ! docker compose version &> /dev/null 2>&1; then
MISSING_DEPS+=("docker-compose")
print_error "Docker Compose plugin is not installed"
log_info " Docker Compose should be included with Docker Desktop"
log_info " Or install: https://docs.docker.com/compose/install/"
else
local compose_version
compose_version=$(docker compose version 2>/dev/null || echo "unknown")
print_ok "Docker Compose is installed: $compose_version"
fi
# Check whiptail
log_info "Checking whiptail..."
if ! command -v whiptail &> /dev/null; then
MISSING_DEPS+=("whiptail")
print_error "whiptail is not installed"
case "$(uname)" in
Darwin)
log_info " Install with: brew install newt"
;;
Linux)
if command -v apt-get &> /dev/null; then
log_info " Install with: sudo apt-get install -y whiptail"
elif command -v yum &> /dev/null; then
log_info " Install with: sudo yum install -y newt"
elif command -v pacman &> /dev/null; then
log_info " Install with: sudo pacman -S libnewt"
else
log_info " Install the 'newt' or 'whiptail' package for your distribution"
fi
;;
esac
else
print_ok "whiptail is installed"
fi
# Check openssl
log_info "Checking openssl..."
if ! command -v openssl &> /dev/null; then
MISSING_DEPS+=("openssl")
print_error "openssl is not installed"
case "$(uname)" in
Darwin)
log_info " openssl should be pre-installed on macOS"
log_info " Or install with: brew install openssl"
;;
Linux)
if command -v apt-get &> /dev/null; then
log_info " Install with: sudo apt-get install -y openssl"
elif command -v yum &> /dev/null; then
log_info " Install with: sudo yum install -y openssl"
else
log_info " Install openssl for your distribution"
fi
;;
esac
else
local openssl_version
openssl_version=$(openssl version 2>/dev/null || echo "unknown")
print_ok "openssl is installed: $openssl_version"
fi
# Check git
log_info "Checking git..."
if ! command -v git &> /dev/null; then
MISSING_DEPS+=("git")
print_error "git is not installed"
log_info " Install git: https://git-scm.com/downloads"
else
local git_version
git_version=$(git --version 2>/dev/null || echo "unknown")
print_ok "git is installed: $git_version"
fi
# Check Python3 and required modules
log_info "Checking Python3..."
if ! command -v python3 &> /dev/null; then
MISSING_DEPS+=("python3")
print_error "Python3 is not installed"
log_info " Install Python3: https://www.python.org/downloads/"
else
local python_version
python_version=$(python3 --version 2>/dev/null || echo "unknown")
print_ok "Python3 is installed: $python_version"
# Check and install required Python modules
local PYTHON_MODULES=("yaml:pyyaml" "dotenv:python-dotenv")
for module_pair in "${PYTHON_MODULES[@]}"; do
local import_name="${module_pair%%:*}"
local package_name="${module_pair##*:}"
log_info "Checking Python module: $package_name..."
if ! python3 -c "import $import_name" 2>/dev/null; then
print_warning "$package_name not found. Installing..."
if python3 -m pip install --user "$package_name" 2>/dev/null; then
print_ok "$package_name installed successfully"
else
MISSING_DEPS+=("$package_name")
print_error "Failed to install $package_name"
log_info " Install manually: pip3 install $package_name"
fi
else
print_ok "$package_name is available"
fi
done
fi
# Summary
echo ""
if [ ${#MISSING_DEPS[@]} -gt 0 ]; then
log_error "Missing dependencies: ${MISSING_DEPS[*]}"
log_info "Please install the missing dependencies and try again."
return 1
else
log_success "All prerequisites are satisfied!"
return 0
fi
}
# Setup error telemetry trap for tracking failures
setup_error_telemetry_trap
# Generate installation ID for telemetry correlation
INSTALLATION_ID=$(get_installation_id)
export INSTALLATION_ID
# Send telemetry: installation started
send_telemetry "install_start"
# Check required scripts
required_scripts=(
"03_generate_secrets.sh"
"04_wizard.sh"
"05_configure_services.sh"
"06_run_services.sh"
"07_final_report.sh"
"08_fix_permissions.sh"
)
missing_scripts=()
for script in "${required_scripts[@]}"; do
script_path="$SCRIPT_DIR/$script"
if [ ! -f "$script_path" ]; then
missing_scripts+=("$script")
fi
done
if [ ${#missing_scripts[@]} -gt 0 ]; then
log_error "The following required scripts are missing in $SCRIPT_DIR:"
printf " - %s\n" "${missing_scripts[@]}"
exit 1
fi
# Make scripts executable
chmod +x "$SCRIPT_DIR"/*.sh 2>/dev/null || true
# =============================================================================
# Run Local installation steps sequentially (6 steps total)
# =============================================================================
TOTAL_STEPS=6
log_header "Local Installation"
log_info "Starting local development installation..."
# Step 1: Prerequisites Check (inline)
show_step 1 $TOTAL_STEPS "Checking Prerequisites"
check_prerequisites || { log_error "Prerequisites check failed"; exit 1; }
log_success "Prerequisites check complete!"
# Pull Caddy image for bcrypt hash generation
log_info "Pulling Caddy image for password hashing..."
docker pull caddy:latest 2>/dev/null || log_warning "Could not pull Caddy image, will try during installation"
# Step 2: Secrets Generation
show_step 2 $TOTAL_STEPS "Generating Secrets and Configuration"
set_telemetry_stage "secrets_gen"
"$BASH" "$SCRIPT_DIR/03_generate_secrets.sh" || { log_error "Secret/Config Generation failed"; exit 1; }
log_success "Secret/Config Generation complete!"
# Step 3: Service Selection Wizard
show_step 3 $TOTAL_STEPS "Running Service Selection Wizard"
set_telemetry_stage "wizard"
"$BASH" "$SCRIPT_DIR/04_wizard.sh" || { log_error "Service Selection Wizard failed"; exit 1; }
log_success "Service Selection Wizard complete!"
# Step 4: Configure Services
show_step 4 $TOTAL_STEPS "Configure Services"
set_telemetry_stage "configure"
"$BASH" "$SCRIPT_DIR/05_configure_services.sh" || { log_error "Configure Services failed"; exit 1; }
log_success "Configure Services complete!"
# Step 5: Running Services
show_step 5 $TOTAL_STEPS "Running Services"
set_telemetry_stage "db_init"
# Start PostgreSQL first to initialize databases before other services
log_info "Starting PostgreSQL..."
docker compose -p localai up -d postgres || { log_error "Failed to start PostgreSQL"; exit 1; }
# Initialize PostgreSQL databases for services (creates if not exist)
source "$SCRIPT_DIR/databases.sh"
init_all_databases || { log_warning "Database initialization had issues, but continuing..."; }
# Now start all services (postgres is already running)
set_telemetry_stage "services_start"
"$BASH" "$SCRIPT_DIR/06_run_services.sh" || { log_error "Running Services failed"; exit 1; }
log_success "Running Services complete!"
# Step 6: Final Report
show_step 6 $TOTAL_STEPS "Generating Final Report"
set_telemetry_stage "final_report"
log_info "Installation Summary:"
echo -e " ${GREEN}*${NC} Prerequisites verified (Docker, whiptail, openssl, git)"
echo -e " ${GREEN}*${NC} Local installation mode configured (.local domains)"
echo -e " ${GREEN}*${NC} '.env' generated with secure passwords and secrets"
echo -e " ${GREEN}*${NC} Services launched via Docker Compose"
"$BASH" "$SCRIPT_DIR/07_final_report.sh" || { log_error "Final Report Generation failed"; exit 1; }
log_success "Final Report generated!"
# Fix Permissions (run silently, not as a numbered step for local)
set_telemetry_stage "fix_perms"
"$BASH" "$SCRIPT_DIR/08_fix_permissions.sh" || { log_warning "Fix Permissions had issues"; }
log_success "Local installation complete!"
# Send telemetry: installation completed with selected services
send_telemetry "install_complete" "$(read_env_var COMPOSE_PROFILES)"
exit 0