feat: Major UI improvements to ez-homelab.sh

- Add professional ASCII box styling to main menu
- Implement interactive variable configuration with validation
- Add icons to all prompts (🌐 🌍 🦆 🔑 👤 🔒 📧 🏠)
- Create vanishing prompts that replace with status confirmations
- Add comprehensive menu system with proceed/review/quit options
- Show current configuration values before deployment choices
- Implement proper error handling for invalid inputs
- Add immediate quit functionality with 'q' during any prompt
- Improve spacing and visual hierarchy throughout interface
- Fix deployment flow to prevent accidental starts on invalid input
This commit is contained in:
EZ-Homelab Assistant
2026-01-31 05:41:30 -05:00
parent 41d9a4cd7f
commit 6c4a3362e0
5 changed files with 499 additions and 296 deletions

4
aliases.sh Executable file
View File

@@ -0,0 +1,4 @@
alias ll='ls -alF'
alias dkrtable='docker ps --format "table {{.Names}}\t{{.Status}}\t{{.RunningFor}}"'
alias dkrrecreate='docker compose up -d --force-recreate'
alias fixpermissions='sudo chown -R 1000:1000 /opt ~'

View File

@@ -13,6 +13,6 @@
# host: 192.168.4.5
# port: 2375
#${SERVER_HOSTNAME}:
#jasper:
# host: 192.168.4.11
# port: 2375

View File

@@ -4,288 +4,288 @@
- Dashboards:
- Homepage:
icon: homepage.png
href: https://homepage.${DOMAIN}
href: https://homepage.kelinreij.duckdns.org
description: Hosted on Raspberry Pi
- Homepage - ${REMOTE_SERVER_HOSTNAME}:
icon: homepage.png
href: https://homepage.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://homepage.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Application Dashboard
- Homarr:
icon: homarr.png
href: https://homarr.${DOMAIN}
href: https://homarr.kelinreij.duckdns.org
description: Alternative Dashboard
- Homarr - ${REMOTE_SERVER_HOSTNAME}:
icon: homarr.png
href: https://homarr.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://homarr.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Alternative Dashboard
- Dockge - ${SERVER_HOSTNAME}:
- Dockge - jasper:
icon: dockge.png
href: https://${SERVER_HOSTNAME}.${DOMAIN}
href: https://jasper.kelinreij.duckdns.org
description: Main Server
- Dockge - ${REMOTE_SERVER_HOSTNAME}:
icon: dockge.png
href: https://${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: Raspberry Pi Authentication Server
- Core:
- Traefik:
icon: traefik.png
href: https://traefik.${DOMAIN}
href: https://traefik.kelinreij.duckdns.org
description: Reverse Proxy & SSL
- Authelia:
icon: authelia.png
href: https://auth.${DOMAIN}
href: https://auth.kelinreij.duckdns.org
description: Authentication SSO Portal
- Pi-hole:
icon: pi-hole.png
href: https://pihole.${DOMAIN}
href: https://pihole.kelinreij.duckdns.org
description: Network-wide Ad Blocking
- Monitoring Stack:
- Dozzle:
icon: dozzle.png
href: https://dozzle.${SERVER_HOSTNAME}.${DOMAIN}
description: ${SERVER_HOSTNAME} - Real-time Log Viewer
href: https://dozzle.jasper.kelinreij.duckdns.org
description: jasper - Real-time Log Viewer
- Dozzle:
icon: dozzle.png
href: https://dozzle.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://dozzle.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Real-time Log Viewer
- Glances - ${SERVER_HOSTNAME}:
- Glances - jasper:
icon: glances.png
href: https://glances.${SERVER_HOSTNAME}.${DOMAIN}
description: ${SERVER_HOSTNAME} - System Monitoring
href: https://glances.jasper.kelinreij.duckdns.org
description: jasper - System Monitoring
- Glances - ${REMOTE_SERVER_HOSTNAME}:
icon: glances.png
href: https://glances.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://glances.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - System Monitoring
- Uptime Kuma:
icon: uptime-kuma.png
href: https://uptime-kuma.${DOMAIN}
href: https://uptime-kuma.kelinreij.duckdns.org
description: Uptime Monitoring
- Grafana - ${REMOTE_SERVER_HOSTNAME}:
icon: grafana.png
href: https://grafana.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://grafana.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Metrics Dashboard
- Prometheus - ${REMOTE_SERVER_HOSTNAME}:
icon: prometheus.png
href: https://prometheus.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://prometheus.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Metrics Collection
- Uptime Kuma - ${REMOTE_SERVER_HOSTNAME}:
icon: uptime-kuma.png
href: https://status.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://status.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Uptime Monitoring
- Media:
- Jellyfin:
icon: jellyfin.png
href: https://jellyfin.${DOMAIN}
href: https://jellyfin.kelinreij.duckdns.org
description: Open Source Media Server
- Jellyseerr:
icon: jellyseerr.png
href: https://jellyseerr.${DOMAIN}
href: https://jellyseerr.kelinreij.duckdns.org
description: Media Request Manager
- Calibre-Web:
icon: calibre-web.png
href: https://calibre.${DOMAIN}
href: https://calibre.kelinreij.duckdns.org
description: Ebook Library
- Media Management:
- Sonarr:
icon: sonarr.png
href: https://sonarr.${DOMAIN}
href: https://sonarr.kelinreij.duckdns.org
description: TV Shows Automation
- Radarr:
icon: radarr.png
href: https://radarr.${DOMAIN}
href: https://radarr.kelinreij.duckdns.org
description: Movies Automation
- Prowlarr:
icon: prowlarr.png
href: https://prowlarr.${DOMAIN}
href: https://prowlarr.kelinreij.duckdns.org
description: Indexer Manager
- Readarr:
icon: readarr.png
href: https://readarr.${DOMAIN}
href: https://readarr.kelinreij.duckdns.org
description: Books Automation
- Lidarr:
icon: lidarr.png
href: https://lidarr.${DOMAIN}
href: https://lidarr.kelinreij.duckdns.org
description: Music Automation
- Mylar3:
icon: mylar.png
href: https://mylar.${DOMAIN}
href: https://mylar.kelinreij.duckdns.org
description: Comics Manager
- Home Automation:
- Home Assistant:
icon: home-assistant.png
href: https://hass.${DOMAIN}
href: https://hass.kelinreij.duckdns.org
description: Home Automation Platform
- ESPHome:
icon: esphome.png
href: https://esphome.${DOMAIN}
href: https://esphome.kelinreij.duckdns.org
description: ESP Device Manager
- Node-RED:
icon: node-red.png
href: https://nodered.${DOMAIN}
href: https://nodered.kelinreij.duckdns.org
description: Flow-based Automation
- Zigbee2MQTT:
icon: zigbee2mqtt.png
href: https://zigbee.${DOMAIN}
href: https://zigbee.kelinreij.duckdns.org
description: Zigbee Bridge
- Mosquitto:
icon: mosquitto.png
href: https://mqtt.${DOMAIN}
href: https://mqtt.kelinreij.duckdns.org
description: MQTT Broker
- Productivity:
- Nextcloud:
icon: nextcloud.png
href: https://nextcloud.${DOMAIN}
href: https://nextcloud.kelinreij.duckdns.org
description: Cloud Storage & Collaboration
- Gitea:
icon: gitea.png
href: https://gitea.${DOMAIN}
href: https://gitea.kelinreij.duckdns.org
description: Git Repository
- Mealie:
icon: mealie.png
href: https://mealie.${DOMAIN}
href: https://mealie.kelinreij.duckdns.org
description: Recipe Manager
- WordPress:
icon: wordpress.png
href: https://wordpress.${DOMAIN}
href: https://wordpress.kelinreij.duckdns.org
description: CMS Platform
- Wikis:
- BookStack:
icon: bookstack.png
href: https://bookstack.${DOMAIN}
href: https://bookstack.kelinreij.duckdns.org
description: Wiki Platform
- DokuWiki:
icon: dokuwiki.png
href: https://dokuwiki.${DOMAIN}
href: https://dokuwiki.kelinreij.duckdns.org
description: Simple Wiki
- Mediawiki:
icon: mediawiki.png
href: https://mediawiki.${DOMAIN}
href: https://mediawiki.kelinreij.duckdns.org
description: Collaborative Wiki
- Development:
- VS Code Server:
icon: vscode.png
href: https://code.${DOMAIN}
href: https://code.kelinreij.duckdns.org
description: Browser-based IDE
- Jupyter:
icon: jupyter.png
href: https://jupyter.${DOMAIN}
href: https://jupyter.kelinreij.duckdns.org
description: Data Science Notebooks
- Downloaders:
- qBittorrent:
icon: qbittorrent.png
href: https://qbit.${DOMAIN}
href: https://qbit.kelinreij.duckdns.org
description: Torrent Client
- Transcoders:
- Tdarr:
icon: tdarr.png
href: https://tdarr.${DOMAIN}
href: https://tdarr.kelinreij.duckdns.org
description: Media Transcoding
- Unmanic:
icon: unmanic.png
href: https://unmanic.${DOMAIN}
href: https://unmanic.kelinreij.duckdns.org
description: Media Transcoder
- Utilities:
- Vaultwarden:
icon: vaultwarden.png
href: https://vault.${DOMAIN}
href: https://vault.kelinreij.duckdns.org
description: Password Manager
- Formio:
icon: mdi-form-select
href: https://formio.${DOMAIN}
href: https://formio.kelinreij.duckdns.org
description: Form Builder
- Backup:
- Backrest:
icon: mdi-backup-restore
href: https://backrest.${DOMAIN}
href: https://backrest.kelinreij.duckdns.org
description: Backup Solution
- Backrest - ${REMOTE_SERVER_HOSTNAME}:
icon: mdi-backup-restore
href: https://backrest.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://backrest.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Backup Solution
- Duplicati:
icon: duplicati.png
href: https://duplicati.${DOMAIN}
href: https://duplicati.kelinreij.duckdns.org
description: Backup Software
- Duplicati - ${REMOTE_SERVER_HOSTNAME}:
icon: duplicati.png
href: https://duplicati.${REMOTE_SERVER_HOSTNAME}.${DOMAIN}
href: https://duplicati.${REMOTE_SERVER_HOSTNAME}.kelinreij.duckdns.org
description: ${REMOTE_SERVER_HOSTNAME} - Backup Software
- Metrics:
- Grafana:
icon: grafana.png
href: https://grafana.${DOMAIN}
href: https://grafana.kelinreij.duckdns.org
description: Metrics Dashboard
- Prometheus:
icon: prometheus.png
href: https://prometheus.${DOMAIN}
href: https://prometheus.kelinreij.duckdns.org
description: Metrics Collection
- cAdvisor:
icon: cadvisor.png
href: https://cadvisor.${DOMAIN}
href: https://cadvisor.kelinreij.duckdns.org
description: Container Metrics
- Alternatives:
- Portainer:
icon: portainer.png
href: https://portainer.${DOMAIN}
href: https://portainer.kelinreij.duckdns.org
description: Container Management UI
- Authentik:
icon: authentik.png
href: https://authentik.${DOMAIN}
href: https://authentik.kelinreij.duckdns.org
description: Alternative Auth Provider
- Plex:
icon: plex.png
href: https://plex.${DOMAIN}
href: https://plex.kelinreij.duckdns.org
description: Media Server

60
markup.yml Normal file
View File

@@ -0,0 +1,60 @@
echo "╔═════════════════════════════════════════════════════════════╗"
echo "║ EZ-HOMELAB SETUP & DEPLOYMENT ║"
echo "║ ║"
echo "║ 1) Install Docker ║"
echo "║ 2) Deploy Core Server ║"
echo "║ 3) Deploy Additional Server ║"
echo "║ 4) Install NVIDIA Drivers ║"
echo "║ ║"
echo "║ q) Quit ║"
echo "╚═════════════════════════════════════════════════════════════╝"
echo "╔═════════════════════════════════════════════════════════════╗
echo "║ ✅ SERVER_IP: 192.168.4.4 ║
echo "║ ✅ SERVER_HOSTNAME: jasper ║
echo "║ ✅ DUCKDNS_SUBDOMAINS: kelinreij ║
echo "║ ✅ DUCKDNS_TOKEN: 41ef7faa-fc93-41d2-a32f-340fd2b75b2f ║
echo "║ ✅ DOMAIN: kelinreij.duckdns.org ║
echo "║ ✅ DEFAULT_USER: kelin ║
echo "║ ✅ DEFAULT_PASSWORD: Tiberi0u$ ║
echo "║ ✅ DEFAULT_EMAIL: kelinshomelab@gmail.com ║
echo "╚═════════════════════════════════════════════════════════════╝
echo "╔═════════════════════════════════════════════════════════════╗
echo "║ Use These Values ? (Y/n) ║
echo "╚═════════════════════════════════════════════════════════════╝
echo "╔═════════════════════════════════════════════════════════════╗
echo "║ Deployment Complete! ║
echo "║ SSL Certificates may take a few minutes to be issued. ║
echo "║ ║
echo "║ https://dockge.kelinreij.duckdns.org ║
echo "║ http://192.168.4.4:5001 ║
echo "║ ║
echo "║ https://homepage.kelinreij.duckdns.org ║
echo "║ http://192.168.4.4:3003 ║
echo "║ ║
echo "║ https://authelia.kelinreij.duckdns.org ║
echo "║ http://192.168.4.4:9091 ║
echo "║ ║
echo "║ https://traefik.kelinreij.duckdns.org ║
echo "║ http://192.168.4.4:8080 ║
echo "║ ║
echo "╚═════════════════════════════════════════════════════════════╝
echo "╔═════════════════════════════════════════════════════════════╗
echo "║ ⚠️ WARNING ⚠️ ║
echo "║ The following variables were not defined ║
echo "║ If something isn't working as expected check these first ║
echo "║ ║
echo "║ WATCHTOWER_NOTIFICATION_URL WATCHTOWER_NOTIFICATION_URL ║
echo "║ AUTHENTIK_DB_NAME AUTHENTIK_DB_PASSWORD ║
echo "║ ║
echo "╚═════════════════════════════════════════════════════════════╝

View File

@@ -8,6 +8,7 @@ set -e # Exit on error
# Debug logging configuration
DEBUG=${DEBUG:-false}
VERBOSE=${VERBOSE:-false} # New verbosity toggle
DEBUG_LOG_FILE="/tmp/ez-homelab-debug.log"
# Colors for output
@@ -33,17 +34,23 @@ fi
# Log functions
log_info() {
if [ "$VERBOSE" = true ]; then
echo -e "${BLUE}[INFO]${NC} $1"
fi
debug_log "[INFO] $1"
}
log_success() {
if [ "$VERBOSE" = true ]; then
echo -e "${GREEN}[SUCCESS]${NC} $1"
fi
debug_log "[SUCCESS] $1"
}
log_warning() {
if [ "$VERBOSE" = true ]; then
echo -e "${YELLOW}[WARNING]${NC} $1"
fi
debug_log "[WARNING] $1"
}
@@ -107,6 +114,14 @@ replace_env_placeholders() {
debug_log "Found variables to replace: $vars"
for var in $vars; do
# Skip derived variables that should not be replaced
case "$var" in
"ACME_EMAIL"|"AUTHELIA_ADMIN_EMAIL"|"SMTP_USERNAME"|"SMTP_PASSWORD")
debug_log "Skipping derived variable: $var"
continue
;;
esac
if [ -z "${!var:-}" ]; then
log_warning "Environment variable $var not found in .env file"
debug_log "Missing variable: $var"
@@ -132,6 +147,38 @@ replace_env_placeholders() {
fi
}
# Enhanced placeholder replacement for all configuration files
enhance_placeholder_replacement() {
log_info "Starting enhanced placeholder replacement..."
local processed_files=0
# Process docker-compose files
if [ -d "$REPO_DIR/docker-compose" ]; then
while IFS= read -r -d '' file_path; do
if [ -f "$file_path" ]; then
debug_log "Processing docker-compose file: $file_path"
replace_env_placeholders "$file_path" false
processed_files=$((processed_files + 1))
fi
done < <(find "$REPO_DIR/docker-compose" -name "*.yml" -o -name "*.yaml" -print0 2>/dev/null)
fi
# Process config-templates files
if [ -d "$REPO_DIR/config-templates" ]; then
while IFS= read -r -d '' file_path; do
if [ -f "$file_path" ]; then
debug_log "Processing config template file: $file_path"
replace_env_placeholders "$file_path" false
processed_files=$((processed_files + 1))
fi
done < <(find "$REPO_DIR/config-templates" -name "*.yml" -o -name "*.yaml" -print0 2>/dev/null)
fi
log_success "Enhanced placeholder replacement completed - processed $processed_files files"
debug_log "Enhanced replacement completed for $processed_files files"
}
# Function to generate shared CA for multi-server TLS
generate_shared_ca() {
local ca_dir="/opt/stacks/core/shared-ca"
@@ -296,35 +343,14 @@ DEPLOY_DASHBOARDS=false
SETUP_STACKS=false
TLS_ISSUES_SUMMARY=""
# Required variables for configuration
REQUIRED_VARS=("SERVER_IP" "SERVER_HOSTNAME" "DUCKDNS_SUBDOMAINS" "DUCKDNS_TOKEN" "DOMAIN" "DEFAULT_USER" "DEFAULT_PASSWORD" "DEFAULT_EMAIL")
# Load existing .env file if it exists
load_env_file() {
if [ -f "$REPO_DIR/.env" ]; then
log_info "Found existing .env file, loading current configuration..."
load_env_file_safely "$REPO_DIR/.env"
# Show current values
echo ""
echo "Current configuration:"
echo " Domain: ${DOMAIN:-Not set}"
echo " Server IP: ${SERVER_IP:-Not set}"
echo " Server Hostname: ${SERVER_HOSTNAME:-Not set}"
echo " Remote Server IP: ${REMOTE_SERVER_IP:-Not set}"
echo " Remote Server Hostname: ${REMOTE_SERVER_HOSTNAME:-Not set}"
echo " Remote Server User: ${REMOTE_SERVER_USER:-Not set}"
if [ -n "${REMOTE_SERVER_PASSWORD:-}" ]; then
echo " Remote Server Password: [HIDDEN]"
else
echo " Remote Server Password: Not set"
fi
echo " Default User: ${DEFAULT_USER:-Not set}"
if [ -n "${DEFAULT_PASSWORD:-}" ]; then
echo " Default Password: [HIDDEN]"
else
echo " Default Password: Not set"
fi
echo " Timezone: ${TZ:-Not set}"
echo ""
return 0
else
log_info "No existing .env file found. We'll create one during setup."
@@ -332,6 +358,256 @@ load_env_file() {
fi
}
# Validate variable values
validate_variable() {
local var_name="$1"
local var_value="$2"
case "$var_name" in
"SERVER_IP")
# Basic IP validation
if [[ $var_value =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
return 0
else
return 1
fi
;;
"DOMAIN")
# Basic domain validation
if [[ $var_value =~ ^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
return 0
else
return 1
fi
;;
"DUCKDNS_SUBDOMAINS")
# DuckDNS subdomain should be non-empty and contain only valid characters
local trimmed_value=$(echo "$var_value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [ -n "$trimmed_value" ] && [[ $trimmed_value =~ ^[a-zA-Z0-9.-]+$ ]]; then
return 0
else
return 1
fi
;;
"DEFAULT_PASSWORD")
# Password should be at least 8 characters
if [ ${#var_value} -ge 8 ]; then
return 0
else
return 1
fi
;;
"DEFAULT_EMAIL")
# Basic email validation
if [[ $var_value =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
return 0
else
return 1
fi
;;
*)
# For other variables, trim whitespace and check they're not empty
local trimmed_value=$(echo "$var_value" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [ -n "$trimmed_value" ]; then
return 0
else
return 1
fi
;;
esac
}
# Prompt for a single variable
prompt_for_variable() {
local var="$1"
local user_input=""
local current_value="${!var:-}"
local prompt_text=""
while true; do
# Build prompt text with current value if it exists
if [ -n "$current_value" ]; then
if [ "$var" = "DEFAULT_PASSWORD" ]; then
prompt_text="🔒 ${var} ([HIDDEN]): "
else
prompt_text="${var} (${current_value}): "
fi
else
prompt_text="${var}: "
fi
# Add icon prefix
case "$var" in
"SERVER_IP")
prompt_text="🌐 ${prompt_text}"
;;
"DOMAIN")
prompt_text="🌍 ${prompt_text}"
;;
"DUCKDNS_SUBDOMAINS")
prompt_text="🦆 ${prompt_text}"
;;
"DUCKDNS_TOKEN")
prompt_text="🔑 ${prompt_text}"
;;
"DEFAULT_USER")
prompt_text="👤 ${prompt_text}"
;;
"DEFAULT_PASSWORD")
# Lock icon already added above for passwords
;;
"DEFAULT_EMAIL")
prompt_text="📧 ${prompt_text}"
;;
"SERVER_HOSTNAME")
prompt_text="🏠 ${prompt_text}"
;;
esac
# Get user input
if [ "$var" = "DEFAULT_PASSWORD" ]; then
read -s -p "$prompt_text" user_input
echo ""
else
read -p "$prompt_text" user_input
fi
# Check for quit command
if [ "$user_input" = "q" ] || [ "$user_input" = "Q" ]; then
log_info "Setup cancelled by user"
exit 0
fi
if [ -z "$user_input" ]; then
if [ -n "$current_value" ]; then
# Use existing value - overwrite prompt with status
if [ "$var" != "DEFAULT_PASSWORD" ]; then
echo -e "\033[1A\033[K✅ ${var}: ${current_value}"
fi
return 0
else
log_warning "${var} cannot be empty. Please provide a value."
continue
fi
fi
if validate_variable "$var" "$user_input"; then
eval "$var=\"$user_input\""
# Overwrite prompt with status
if [ "$var" != "DEFAULT_PASSWORD" ]; then
echo -e "\033[1A\033[K✅ ${var}: ${user_input}"
else
echo -e "\033[1A\033[K✅ ${var}: [HIDDEN]"
fi
return 0
else
log_warning "Invalid value for ${var}. Please try again."
continue
fi
done
}
# Validate and prompt for required variables with loop
validate_and_prompt_variables() {
local all_valid=false
local user_wants_to_review=false
local first_display=true
while true; do
user_wants_to_review=false
all_valid=true
# Check validity without showing initial summary
for var in "${REQUIRED_VARS[@]}"; do
local display_value=$(echo "${!var:-}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [ -z "$display_value" ] || ! validate_variable "$var" "${!var}"; then
all_valid=false
fi
done
if [ "$all_valid" = true ]; then
if [ "$first_display" = true ]; then
echo "Current configuration:"
for var in "${REQUIRED_VARS[@]}"; do
local display_value=$(echo "${!var:-}" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [ "$var" = "DEFAULT_PASSWORD" ]; then
echo "${var}: [HIDDEN]"
else
echo "${var}: ${display_value}"
fi
done
echo ""
first_display=false
fi
echo ""
echo "Choose an option:"
echo " 1) ✅ Deploy now"
echo " 2) 🔄 Make Changes"
echo " q) ❌ Quit setup"
echo ""
read -p "Enter your choice (1, 2, or q): " user_choice
case "$user_choice" in
1|"p"|"proceed")
log_info "Proceeding with current configuration..."
return 0
;;
2|"r"|"review"|"change")
user_wants_to_review=true
echo ""
echo "Reviewing all variables - press Enter to keep current value or enter new value:"
echo ""
;;
[Qq]|[Qq]uit)
log_info "Setup cancelled by user"
exit 0
;;
*)
log_warning "Invalid choice. Please enter 1, 2, or q."
echo ""
continue
;;
esac
else
echo ""
echo "Some variables need configuration. Press Enter to continue or 'q' to quit."
read -p "Press Enter to configure missing variables, or 'q' to quit: " user_choice
case "$user_choice" in
[Qq]|[Qq]uit)
log_info "Setup cancelled by user"
exit 0
;;
""|"c"|"continue")
# Continue with prompting
;;
*)
log_warning "Invalid choice. Press Enter to continue or 'q' to quit."
continue
;;
esac
fi
# Prompt for variables (either missing ones or all if reviewing)
if [ "$user_wants_to_review" = true ]; then
# Review all variables one by one
for var in "${REQUIRED_VARS[@]}"; do
prompt_for_variable "$var"
done
# After review, continue the loop to show menu again
continue
else
# Only prompt for missing/invalid variables
for var in "${REQUIRED_VARS[@]}"; do
if [ -z "${!var:-}" ] || ! validate_variable "$var" "${!var}"; then
prompt_for_variable "$var"
fi
done
fi
done
}
# Save configuration to .env file
save_env_file() {
debug_log "save_env_file() called, DEPLOY_CORE=$DEPLOY_CORE"
@@ -342,15 +618,20 @@ save_env_file() {
sudo -u "$ACTUAL_USER" cp "$REPO_DIR/.env.example" "$REPO_DIR/.env"
fi
# Update values as the actual user
sudo -u "$ACTUAL_USER" sed -i "s%DOMAIN=.*%DOMAIN=$DOMAIN%" "$REPO_DIR/.env"
sudo -u "$ACTUAL_USER" sed -i "s%SERVER_IP=.*%SERVER_IP=$SERVER_IP%" "$REPO_DIR/.env"
sudo -u "$ACTUAL_USER" sed -i "s%SERVER_HOSTNAME=.*%SERVER_HOSTNAME=$SERVER_HOSTNAME%" "$REPO_DIR/.env"
sudo -u "$ACTUAL_USER" sed -i "s%REMOTE_SERVER_IP=.*%REMOTE_SERVER_IP=$REMOTE_SERVER_IP%" "$REPO_DIR/.env"
sudo -u "$ACTUAL_USER" sed -i "s%REMOTE_SERVER_HOSTNAME=.*%REMOTE_SERVER_HOSTNAME=$REMOTE_SERVER_HOSTNAME%" "$REPO_DIR/.env"
sudo -u "$ACTUAL_USER" sed -i "s%REMOTE_SERVER_USER=.*%REMOTE_SERVER_USER=$REMOTE_SERVER_USER%" "$REPO_DIR/.env"
sudo -u "$ACTUAL_USER" sed -i "s%REMOTE_SERVER_PASSWORD=.*%REMOTE_SERVER_PASSWORD=$REMOTE_SERVER_PASSWORD%" "$REPO_DIR/.env"
sudo -u "$ACTUAL_USER" sed -i "s%TZ=.*%TZ=$TZ%" "$REPO_DIR/.env"
# Update only the required variables
for var in "${REQUIRED_VARS[@]}"; do
if [ -n "${!var:-}" ]; then
sudo -u "$ACTUAL_USER" sed -i "s|^${var}=.*|${var}=${!var}|" "$REPO_DIR/.env"
fi
done
# Update HOMEPAGE_ALLOWED_HOSTS dynamically
if [ -n "${DOMAIN:-}" ] && [ -n "${SERVER_IP:-}" ]; then
# Allow user to specify homepage subdomain
HOMEPAGE_SUBDOMAIN="${HOMEPAGE_SUBDOMAIN:-homepage}"
HOMEPAGE_ALLOWED_HOSTS="${HOMEPAGE_SUBDOMAIN}.${DOMAIN},${SERVER_IP}:3003"
sudo -u "$ACTUAL_USER" sed -i "s|HOMEPAGE_ALLOWED_HOSTS=.*|HOMEPAGE_ALLOWED_HOSTS=$HOMEPAGE_ALLOWED_HOSTS|" "$REPO_DIR/.env"
fi
# Authelia settings (only generate secrets if deploying core)
if [ "$DEPLOY_CORE" = true ]; then
@@ -471,141 +752,6 @@ validate_secrets() {
debug_log "Secret validation passed"
}
# Prompt for required values
prompt_for_values() {
echo ""
log_info "Configuration Setup:"
echo ""
# Set defaults from env file or hardcoded fallbacks
DEFAULT_DOMAIN="${DOMAIN:-example.duckdns.org}"
DEFAULT_SERVER_IP="${SERVER_IP:-$(hostname -I | awk '{print $1}')}"
DEFAULT_CORE_SERVER_IP="${CORE_SERVER_IP:-}"
DEFAULT_SERVER_HOSTNAME="${SERVER_HOSTNAME:-$(hostname)}"
DEFAULT_REMOTE_SERVER_IP="${REMOTE_SERVER_IP:-}"
DEFAULT_REMOTE_SERVER_HOSTNAME="${REMOTE_SERVER_HOSTNAME:-}"
DEFAULT_REMOTE_SERVER_USER="${REMOTE_SERVER_USER:-${DEFAULT_USER}}"
DEFAULT_REMOTE_SERVER_PASSWORD="${REMOTE_SERVER_PASSWORD:-}"
DEFAULT_TZ="${TZ:-America/New_York}"
# Display current/default configuration
echo "Please review the following configuration:"
echo " Domain: $DEFAULT_DOMAIN"
echo " Server IP: $DEFAULT_SERVER_IP"
echo " Server Hostname: $DEFAULT_SERVER_HOSTNAME"
echo " Remote Server IP: $DEFAULT_REMOTE_SERVER_IP"
echo " Remote Server Hostname: $DEFAULT_REMOTE_SERVER_HOSTNAME"
echo " Remote Server User: $DEFAULT_REMOTE_SERVER_USER"
if [ -n "$DEFAULT_REMOTE_SERVER_PASSWORD" ]; then
echo " Remote Server Password: [HIDDEN]"
else
echo " Remote Server Password: Not set"
fi
echo " Timezone: $DEFAULT_TZ"
if [ "$DEPLOY_CORE" = false ] && [ -z "$DEFAULT_CORE_SERVER_IP" ]; then
echo " Core Server IP: [Will be prompted for multi-server TLS]"
elif [ -n "$DEFAULT_CORE_SERVER_IP" ]; then
echo " Core Server IP: $DEFAULT_CORE_SERVER_IP"
fi
if [ "$DEPLOY_CORE" = true ]; then
DEFAULT_ADMIN_USER="${DEFAULT_USER:-admin}"
DEFAULT_ADMIN_EMAIL="${DEFAULT_EMAIL:-${DEFAULT_ADMIN_USER}@${DEFAULT_DOMAIN}}"
echo " Admin User: $DEFAULT_ADMIN_USER"
echo " Admin Email: $DEFAULT_ADMIN_EMAIL"
echo " Admin Password: [Will be prompted if needed]"
fi
echo ""
read -p "Use these default values? (Y/n): " -n 1 -r
echo ""
if [[ $REPLY =~ ^[Nn]$ ]]; then
echo "Please enter custom values:"
echo ""
# Domain
read -p "Domain [$DEFAULT_DOMAIN]: " DOMAIN
DOMAIN="${DOMAIN:-$DEFAULT_DOMAIN}"
# Server IP
read -p "Server IP [$DEFAULT_SERVER_IP]: " SERVER_IP
SERVER_IP="${SERVER_IP:-$DEFAULT_SERVER_IP}"
# Server Hostname
read -p "Server Hostname [$DEFAULT_SERVER_HOSTNAME]: " SERVER_HOSTNAME
SERVER_HOSTNAME="${SERVER_HOSTNAME:-$DEFAULT_SERVER_HOSTNAME}"
# Remote Server IP
read -p "Remote Server IP [$DEFAULT_REMOTE_SERVER_IP]: " REMOTE_SERVER_IP
REMOTE_SERVER_IP="${REMOTE_SERVER_IP:-$DEFAULT_REMOTE_SERVER_IP}"
# Remote Server Hostname
read -p "Remote Server Hostname [$DEFAULT_REMOTE_SERVER_HOSTNAME]: " REMOTE_SERVER_HOSTNAME
REMOTE_SERVER_HOSTNAME="${REMOTE_SERVER_HOSTNAME:-$DEFAULT_REMOTE_SERVER_HOSTNAME}"
# Remote Server User
read -p "Remote Server User [$DEFAULT_REMOTE_SERVER_USER]: " REMOTE_SERVER_USER
REMOTE_SERVER_USER="${REMOTE_SERVER_USER:-$DEFAULT_REMOTE_SERVER_USER}"
# Remote Server Password
read -s -p "Remote Server Password: " REMOTE_SERVER_PASSWORD
echo ""
if [ -z "$REMOTE_SERVER_PASSWORD" ]; then
REMOTE_SERVER_PASSWORD="$DEFAULT_REMOTE_SERVER_PASSWORD"
fi
# Timezone
read -p "Timezone [$DEFAULT_TZ]: " TZ
TZ="${TZ:-$DEFAULT_TZ}"
# Core server IP (for multi-server setup)
if [ "$DEPLOY_CORE" = false ]; then
echo ""
read -p "Core server IP (for shared TLS CA): " CORE_SERVER_IP
fi
# Admin credentials (only if deploying core)
if [ "$DEPLOY_CORE" = true ]; then
echo ""
log_info "Authelia Admin Credentials:"
read -p "Admin username [$DEFAULT_ADMIN_USER]: " ADMIN_USER
ADMIN_USER="${ADMIN_USER:-$DEFAULT_ADMIN_USER}"
read -p "Admin email [$DEFAULT_ADMIN_EMAIL]: " ADMIN_EMAIL
ADMIN_EMAIL="${ADMIN_EMAIL:-$DEFAULT_ADMIN_EMAIL}"
if [ -z "$ADMIN_PASSWORD" ]; then
while [ -z "$ADMIN_PASSWORD" ]; do
read -s -p "Admin password (will be hashed): " ADMIN_PASSWORD
echo ""
if [ ${#ADMIN_PASSWORD} -lt 8 ]; then
log_warning "Password must be at least 8 characters"
ADMIN_PASSWORD=""
fi
done
else
log_info "Admin password already configured"
fi
fi
else
# Use defaults
DOMAIN="$DEFAULT_DOMAIN"
SERVER_IP="$DEFAULT_SERVER_IP"
SERVER_HOSTNAME="$DEFAULT_SERVER_HOSTNAME"
TZ="$DEFAULT_TZ"
CORE_SERVER_IP="$DEFAULT_CORE_SERVER_IP"
if [ "$DEPLOY_CORE" = true ]; then
ADMIN_USER="$DEFAULT_ADMIN_USER"
ADMIN_EMAIL="$DEFAULT_ADMIN_EMAIL"
fi
fi
echo ""
}
# System setup function (Docker, directories, etc.)
system_setup() {
log_info "Performing system setup..."
@@ -1057,13 +1203,7 @@ perform_deployment() {
log_info "Please update your .env file and redeploy affected stacks."
fi
# Report any TLS issues
if [ -n "$TLS_ISSUES_SUMMARY" ]; then
echo ""
log_warning "TLS Configuration Issues Detected:"
echo "$TLS_ISSUES_SUMMARY"
echo ""
fi
# TLS issues will be reported in the final summary
}
# Setup Docker TLS function
@@ -1186,28 +1326,18 @@ setup_stacks_for_dockge() {
# Main menu
show_main_menu() {
echo "=========================================="
echo " EZ-HOMELAB SETUP & DEPLOYMENT"
echo "=========================================="
clear
echo ""
echo "What would you like to do?"
echo ""
echo "1) 🚀 Default Setup (Recommended)"
echo " - Deploy Dockge, core infrastructure, dashboards & monitoring"
echo " - All additional stacks prepared for Dockge"
echo ""
echo "2) 🏗️ Core Only"
echo " - Deploy Dockge and core infrastructure only"
echo " - All stacks prepared for Dockge"
echo ""
echo "3) 🔧 Infrastructure Only"
echo " - Deploy Dockge and monitoring tools"
echo " - Requires existing Traefik (from previous setup)"
echo " - Configures TLS for remote Docker access (Sablier)"
echo " - Services accessible without authentication"
echo " - All stacks prepared for Dockge"
echo ""
echo "4) ❌ Exit"
echo "╔═════════════════════════════════════════════════════════════╗"
echo "║ EZ-HOMELAB SETUP & DEPLOYMENT ║"
echo "║ ║"
echo " 1) Install Prerequisites ║"
echo "║ 2) Deploy Core Server ║"
echo "║ 3) Deploy Additional Server ║"
echo "║ 4) Install NVIDIA Drivers ║"
echo " "
echo " q) Quit ║"
echo "╚═════════════════════════════════════════════════════════════╝"
echo ""
}
@@ -1228,31 +1358,24 @@ main() {
# Show main menu
show_main_menu
read -p "Choose an option (1-4): " MAIN_CHOICE
read -p "Choose an option (1-3): " MAIN_CHOICE
case $MAIN_CHOICE in
1)
log_info "Selected: Default Setup"
log_info "Selected: Core Server"
DEPLOY_CORE=true
DEPLOY_INFRASTRUCTURE=true
DEPLOY_DASHBOARDS=true
SETUP_STACKS=true
;;
2)
log_info "Selected: Core Only"
DEPLOY_CORE=true
DEPLOY_INFRASTRUCTURE=false
DEPLOY_DASHBOARDS=true
SETUP_STACKS=true
;;
3)
log_info "Selected: Infrastructure Only"
log_info "Selected: Additional Server"
DEPLOY_CORE=false
DEPLOY_INFRASTRUCTURE=true
DEPLOY_DASHBOARDS=false
SETUP_STACKS=true
;;
4)
3)
log_info "Exiting..."
exit 0
;;
@@ -1316,11 +1439,14 @@ main() {
log_success "Directories ready"
# Prompt for configuration values
prompt_for_values
validate_and_prompt_variables
# Save configuration
save_env_file
# Perform enhanced placeholder replacement across all config files
enhance_placeholder_replacement
# Validate secrets for core deployment
validate_secrets
@@ -1329,36 +1455,49 @@ main() {
# Show completion message
echo ""
echo "=========================================="
log_success "Setup and deployment completed successfully!"
echo "=========================================="
echo ""
echo "╔═════════════════════════════════════════════════════════════╗"
echo "║ Deployment Complete! ║"
echo "║ SSL Certificates may take a few minutes to be issued. ║"
echo "║ ║"
echo "║ https://dockge.kelinreij.duckdns.org ║"
echo "║ http://192.168.4.4:5001 ║"
echo "║ ║"
echo "║ https://homepage.kelinreij.duckdns.org ║"
echo "║ http://192.168.4.4:3003 ║"
echo "║ ║"
echo "╚═════════════════════════════════════════════════════════════╝"
if [ "$DEPLOY_INFRASTRUCTURE" = true ]; then
log_info "Access your services:"
echo ""
echo " 🚀 Dockge: https://dockge.${DOMAIN}"
[ "$DEPLOY_CORE" = true ] && echo " 🔒 Authelia: https://auth.${DOMAIN}"
[ "$DEPLOY_CORE" = true ] && echo " 🔀 Traefik: https://traefik.${DOMAIN}"
echo " 📊 Homepage: https://homepage.${DOMAIN}"
echo ""
# Show consolidated warnings if any
if [ -n "$MISSING_VARS_SUMMARY" ] || [ -n "$TLS_ISSUES_SUMMARY" ]; then
echo "╔═════════════════════════════════════════════════════════════╗"
echo "║ ⚠️ WARNING ⚠️ ║"
echo "║ The following variables were not defined ║"
echo "║ If something isn't working as expected check these first ║"
echo "║ ║"
if [ -n "$MISSING_VARS_SUMMARY" ]; then
log_warning "Missing Environment Variables:"
echo "$MISSING_VARS_SUMMARY"
echo "║ ║"
fi
log_info "Next steps:"
echo ""
echo " 1. Access Dockge at https://dockge.${DOMAIN}"
if [ "$DEPLOY_CORE" = true ]; then
echo " (Use your Authelia credentials: ${AUTHELIA_ADMIN_USER})"
if [ -n "$TLS_ISSUES_SUMMARY" ]; then
log_warning "TLS Configuration Issues:"
echo "$TLS_ISSUES_SUMMARY"
echo "║ ║"
fi
fi
echo "╚═════════════════════════════════════════════════════════════╝"
echo "╔══════════════════════════════════════════╗"
echo "║ 📚 RESOURCES ║"
echo "╚══════════════════════════════════════════╝"
echo ""
echo " 2. Start additional stacks from Dockge's web UI"
echo " 📖 Documentation: $REPO_DIR/docs/"
echo " 🔧 Quick Reference: $REPO_DIR/docs/quick-reference.md"
echo " 🐙 Repository: https://github.com/your-repo/ez-homelab"
echo " 📋 Wiki: https://github.com/your-repo/ez-homelab/wiki"
echo ""
echo " 3. Configure services via the AI assistant in VS Code"
echo ""
echo "=========================================="
echo ""
log_info "For documentation, see: $REPO_DIR/docs/"
log_info "For troubleshooting, see: $REPO_DIR/docs/quick-reference.md"
debug_log "Script completed successfully"
echo ""
}