mirror of
https://github.com/kossakovsky/n8n-install.git
synced 2026-03-07 06:13:05 +00:00
adds appsmith as an optional service with caddy reverse proxy, auto-generated encryption secrets, wizard selection, welcome page integration, update preview support, and final report output. bumps version to 1.3.0.
279 lines
12 KiB
Bash
Executable File
279 lines
12 KiB
Bash
Executable File
#!/bin/bash
|
||
# =============================================================================
|
||
# 04_wizard.sh - Interactive service selection wizard
|
||
# =============================================================================
|
||
# Guides the user through selecting which services to install using whiptail.
|
||
#
|
||
# Features:
|
||
# - Single-screen checklist for service selection
|
||
# - Default services: n8n, portainer, monitoring, databasus
|
||
# - Preserves previously selected services on re-run
|
||
# - Updates COMPOSE_PROFILES in .env file
|
||
#
|
||
# Usage: bash scripts/04_wizard.sh
|
||
# =============================================================================
|
||
|
||
# Source the utilities file and initialize paths
|
||
source "$(dirname "$0")/utils.sh"
|
||
init_paths
|
||
|
||
# Verify whiptail is available
|
||
require_whiptail
|
||
|
||
# Set DEBIAN_FRONTEND for whiptail
|
||
save_debian_frontend
|
||
|
||
# --- Read current COMPOSE_PROFILES from .env ---
|
||
CURRENT_PROFILES_VALUE=""
|
||
if [ -f "$ENV_FILE" ]; then
|
||
LINE_CONTENT=$(grep "^COMPOSE_PROFILES=" "$ENV_FILE" || echo "")
|
||
if [ -n "$LINE_CONTENT" ]; then
|
||
# Get value after '=', remove potential surrounding quotes
|
||
CURRENT_PROFILES_VALUE=$(echo "$LINE_CONTENT" | cut -d'=' -f2- | sed 's/^"//' | sed 's/"$//')
|
||
fi
|
||
fi
|
||
# Prepare comma-separated current profiles for easy matching, adding leading/trailing commas
|
||
current_profiles_for_matching=",$CURRENT_PROFILES_VALUE,"
|
||
|
||
# --- Define available services and their descriptions ---
|
||
# Base service definitions (tag, description)
|
||
base_services_data=(
|
||
"appsmith" "Appsmith (Low-code Platform for Internal Tools & Dashboards)"
|
||
"cloudflare-tunnel" "Cloudflare Tunnel (Zero-Trust Secure Access)"
|
||
"comfyui" "ComfyUI (Node-based Stable Diffusion UI)"
|
||
"crawl4ai" "Crawl4ai (Web Crawler for AI)"
|
||
"databasus" "Databasus (Database backups & monitoring)"
|
||
"dify" "Dify (AI Application Development Platform with LLMOps)"
|
||
"docling" "Docling (Universal Document Converter to Markdown/JSON)"
|
||
"flowise" "Flowise (AI Agent Builder)"
|
||
"gost" "Gost Proxy (HTTP/HTTPS proxy for AI services outbound traffic)"
|
||
"gotenberg" "Gotenberg (Document Conversion API)"
|
||
"langfuse" "Langfuse Suite (AI Observability - includes Clickhouse, Minio)"
|
||
"letta" "Letta (Agent Server & SDK)"
|
||
"libretranslate" "LibreTranslate (Self-hosted translation API - 50+ languages)"
|
||
"lightrag" "LightRAG (Graph-based RAG with knowledge graphs)"
|
||
"monitoring" "Monitoring Suite (Prometheus, Grafana, cAdvisor, Node-Exporter)"
|
||
"n8n" "n8n, n8n-worker, n8n-import (Workflow Automation)"
|
||
"neo4j" "Neo4j (Graph Database)"
|
||
"nocodb" "NocoDB (Open Source Airtable Alternative - Spreadsheet Database)"
|
||
"ollama" "Ollama (Local LLM Runner - select hardware in next step)"
|
||
"open-webui" "Open WebUI (ChatGPT-like Interface)"
|
||
"paddleocr" "PaddleOCR (OCR API Server)"
|
||
"portainer" "Portainer (Docker management UI)"
|
||
"postiz" "Postiz (Social publishing platform)"
|
||
"python-runner" "Python Runner (Run your custom Python code from ./python-runner)"
|
||
"qdrant" "Qdrant (Vector Database)"
|
||
"ragapp" "RAGApp (Open-source RAG UI + API)"
|
||
"ragflow" "RAGFlow (Deep document understanding RAG engine)"
|
||
"searxng" "SearXNG (Private Metasearch Engine)"
|
||
"supabase" "Supabase (Backend as a Service)"
|
||
"waha" "WAHA – WhatsApp HTTP API (NOWEB engine)"
|
||
"weaviate" "Weaviate (Vector Database with API Key Auth)"
|
||
)
|
||
|
||
services=() # This will be the final array for whiptail
|
||
|
||
# Populate the services array for whiptail based on current profiles or defaults
|
||
idx=0
|
||
while [ $idx -lt ${#base_services_data[@]} ]; do
|
||
tag="${base_services_data[idx]}"
|
||
description="${base_services_data[idx+1]}"
|
||
status="OFF" # Default to OFF
|
||
|
||
if [ -n "$CURRENT_PROFILES_VALUE" ] && [ "$CURRENT_PROFILES_VALUE" != '""' ]; then # Check if .env has profiles
|
||
if [[ "$tag" == "ollama" ]]; then
|
||
if [[ "$current_profiles_for_matching" == *",cpu,"* || \
|
||
"$current_profiles_for_matching" == *",gpu-nvidia,"* || \
|
||
"$current_profiles_for_matching" == *",gpu-amd,"* ]]; then
|
||
status="ON"
|
||
fi
|
||
elif [[ "$current_profiles_for_matching" == *",$tag,"* ]]; then
|
||
status="ON"
|
||
fi
|
||
else
|
||
# .env has no COMPOSE_PROFILES or it's empty/just quotes, use hardcoded defaults
|
||
case "$tag" in
|
||
"n8n"|"portainer"|"monitoring"|"databasus") status="ON" ;;
|
||
*) status="OFF" ;;
|
||
esac
|
||
fi
|
||
services+=("$tag" "$description" "$status")
|
||
idx=$((idx + 2))
|
||
done
|
||
|
||
# Use whiptail to display the checklist (with adaptive sizing)
|
||
CHOICES=$(wt_checklist "Service Selection Wizard" \
|
||
"Choose the services you want to deploy.\nUse ARROW KEYS to navigate, SPACEBAR to select/deselect, ENTER to confirm." \
|
||
"${services[@]}")
|
||
exitstatus=$?
|
||
|
||
# Restore original DEBIAN_FRONTEND
|
||
restore_debian_frontend
|
||
|
||
# Exit if user pressed Cancel or Esc
|
||
if [ $exitstatus -ne 0 ]; then
|
||
log_info "Service selection cancelled by user. Exiting wizard."
|
||
log_info "No changes made to service profiles. Default services will be used."
|
||
# Set COMPOSE_PROFILES to empty to ensure only core services run
|
||
update_compose_profiles ""
|
||
exit 0
|
||
fi
|
||
|
||
# Process selected services
|
||
selected_profiles=()
|
||
ollama_selected=0
|
||
ollama_profile=""
|
||
|
||
if [ -n "$CHOICES" ]; then
|
||
# Parse whiptail output safely (without eval)
|
||
temp_choices=()
|
||
wt_parse_choices "$CHOICES" temp_choices
|
||
|
||
for choice in "${temp_choices[@]}"; do
|
||
if [ "$choice" == "ollama" ]; then
|
||
ollama_selected=1
|
||
else
|
||
selected_profiles+=("$choice")
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Enforce mutual exclusivity between Dify and Supabase (compact)
|
||
if printf '%s\n' "${selected_profiles[@]}" | grep -qx "dify" && \
|
||
printf '%s\n' "${selected_profiles[@]}" | grep -qx "supabase"; then
|
||
CHOSEN_EXCLUSIVE=$(wt_radiolist "Conflict: Dify and Supabase" \
|
||
"Dify and Supabase are mutually exclusive. Choose which one to keep." \
|
||
"supabase" \
|
||
"dify" "Keep Dify (AI App Platform)" OFF \
|
||
"supabase" "Keep Supabase (Backend as a Service)" ON)
|
||
[ -z "$CHOSEN_EXCLUSIVE" ] && CHOSEN_EXCLUSIVE="supabase"
|
||
|
||
to_remove=$([ "$CHOSEN_EXCLUSIVE" = "dify" ] && echo "supabase" || echo "dify")
|
||
tmp=()
|
||
for p in "${selected_profiles[@]}"; do
|
||
[ "$p" = "$to_remove" ] || tmp+=("$p")
|
||
done
|
||
selected_profiles=("${tmp[@]}")
|
||
log_info "Mutual exclusivity enforced: kept '$CHOSEN_EXCLUSIVE', removed '$to_remove'."
|
||
fi
|
||
|
||
# If Ollama was selected, prompt for the hardware profile
|
||
if [ $ollama_selected -eq 1 ]; then
|
||
# Determine default selected Ollama hardware profile from .env
|
||
default_ollama_hardware="cpu" # Fallback default
|
||
ollama_hw_on_cpu="OFF"
|
||
ollama_hw_on_gpu_nvidia="OFF"
|
||
ollama_hw_on_gpu_amd="OFF"
|
||
|
||
# Check current_profiles_for_matching which includes commas, e.g., ",cpu,"
|
||
if [[ "$current_profiles_for_matching" == *",cpu,"* ]]; then
|
||
ollama_hw_on_cpu="ON"
|
||
default_ollama_hardware="cpu"
|
||
elif [[ "$current_profiles_for_matching" == *",gpu-nvidia,"* ]]; then
|
||
ollama_hw_on_gpu_nvidia="ON"
|
||
default_ollama_hardware="gpu-nvidia"
|
||
elif [[ "$current_profiles_for_matching" == *",gpu-amd,"* ]]; then
|
||
ollama_hw_on_gpu_amd="ON"
|
||
default_ollama_hardware="gpu-amd"
|
||
else
|
||
# If ollama was selected in the main list, but no specific hardware profile was previously set,
|
||
# default to CPU ON for the radiolist.
|
||
ollama_hw_on_cpu="ON"
|
||
default_ollama_hardware="cpu"
|
||
fi
|
||
|
||
ollama_hardware_options=(
|
||
"cpu" "CPU (Recommended for most users)" "$ollama_hw_on_cpu"
|
||
"gpu-nvidia" "NVIDIA GPU (Requires NVIDIA drivers & CUDA)" "$ollama_hw_on_gpu_nvidia"
|
||
"gpu-amd" "AMD GPU (Requires ROCm drivers)" "$ollama_hw_on_gpu_amd"
|
||
)
|
||
CHOSEN_OLLAMA_PROFILE=$(wt_radiolist "Ollama Hardware Profile" \
|
||
"Choose the hardware profile for Ollama. This will be added to your Docker Compose profiles." \
|
||
"$default_ollama_hardware" \
|
||
"${ollama_hardware_options[@]}")
|
||
|
||
ollama_exitstatus=$?
|
||
if [ $ollama_exitstatus -eq 0 ] && [ -n "$CHOSEN_OLLAMA_PROFILE" ]; then
|
||
selected_profiles+=("$CHOSEN_OLLAMA_PROFILE")
|
||
ollama_profile="$CHOSEN_OLLAMA_PROFILE" # Store for user message
|
||
log_info "Ollama hardware profile selected: $CHOSEN_OLLAMA_PROFILE"
|
||
else
|
||
log_info "Ollama hardware profile selection cancelled or no choice made. Ollama will not be configured with a specific hardware profile."
|
||
# ollama_selected remains 1, but no specific profile is added.
|
||
# This means "ollama" won't be in COMPOSE_PROFILES unless a hardware profile is chosen.
|
||
ollama_selected=0 # Mark as not fully selected if profile choice is cancelled
|
||
fi
|
||
fi
|
||
|
||
# If Gost was selected, prompt for upstream proxy URL
|
||
gost_selected=0
|
||
for p in "${selected_profiles[@]}"; do
|
||
[ "$p" = "gost" ] && gost_selected=1 && break
|
||
done
|
||
|
||
if [ $gost_selected -eq 1 ]; then
|
||
# Get existing value from .env if available
|
||
EXISTING_UPSTREAM=$(read_env_var "GOST_UPSTREAM_PROXY")
|
||
|
||
GOST_UPSTREAM_INPUT=$(wt_input "Gost Upstream Proxy" \
|
||
"Enter your external proxy URL for geo-bypass.\n\nExamples:\n socks5://user:pass@proxy.com:1080\n http://user:pass@proxy.com:8080\n\nIMPORTANT: For HTTP proxies use http://, NOT https://.\nThe protocol refers to proxy type, not connection security.\n\nThis proxy should be located outside restricted regions." \
|
||
"$EXISTING_UPSTREAM") || true
|
||
|
||
if [ -n "$GOST_UPSTREAM_INPUT" ]; then
|
||
# Save upstream proxy to .env file
|
||
write_env_var "GOST_UPSTREAM_PROXY" "$GOST_UPSTREAM_INPUT"
|
||
log_info "Gost upstream proxy configured: $GOST_UPSTREAM_INPUT"
|
||
|
||
# Also generate GOST_PROXY_URL (needed because wizard runs AFTER generate_secrets)
|
||
GOST_USER=$(read_env_var "GOST_USERNAME")
|
||
GOST_PASS=$(read_env_var "GOST_PASSWORD")
|
||
if [ -n "$GOST_USER" ] && [ -n "$GOST_PASS" ]; then
|
||
GOST_PROXY_URL="http://${GOST_USER}:${GOST_PASS}@gost:8080"
|
||
write_env_var "GOST_PROXY_URL" "$GOST_PROXY_URL"
|
||
log_info "Gost proxy URL generated: http://***:***@gost:8080"
|
||
fi
|
||
else
|
||
# Remove gost from selected profiles if no upstream provided
|
||
tmp=()
|
||
for p in "${selected_profiles[@]}"; do
|
||
[ "$p" != "gost" ] && tmp+=("$p")
|
||
done
|
||
selected_profiles=("${tmp[@]}")
|
||
log_warning "Gost requires an upstream proxy. Gost has been removed from selection."
|
||
fi
|
||
fi
|
||
|
||
if [ ${#selected_profiles[@]} -eq 0 ]; then
|
||
log_info "No optional services selected."
|
||
COMPOSE_PROFILES_VALUE=""
|
||
else
|
||
log_info "Selected service profiles:"
|
||
# Join the array into a comma-separated string
|
||
COMPOSE_PROFILES_VALUE=$(IFS=,; echo "${selected_profiles[*]}")
|
||
for profile in "${selected_profiles[@]}"; do
|
||
# Check if the current profile is an Ollama hardware profile that was chosen
|
||
if [[ "$profile" == "cpu" || "$profile" == "gpu-nvidia" || "$profile" == "gpu-amd" ]]; then
|
||
if [ "$profile" == "$ollama_profile" ]; then
|
||
echo -e " ${GREEN}*${NC} Ollama ($profile profile)"
|
||
else
|
||
echo -e " ${GREEN}*${NC} $profile"
|
||
fi
|
||
else
|
||
echo -e " ${GREEN}*${NC} $profile"
|
||
fi
|
||
done
|
||
fi
|
||
|
||
# Update or add COMPOSE_PROFILES in .env file
|
||
update_compose_profiles "$COMPOSE_PROFILES_VALUE"
|
||
if [ -z "$COMPOSE_PROFILES_VALUE" ]; then
|
||
log_info "Only core services (Caddy, Postgres, Redis) will be started."
|
||
else
|
||
log_info "The following Docker Compose profiles will be active: ${COMPOSE_PROFILES_VALUE}"
|
||
fi
|
||
|
||
# Cleanup any .bak files created by sed
|
||
cleanup_bak_files "$PROJECT_ROOT"
|
||
|
||
exit 0
|