This commit adds comprehensive email testing support and improves the Homepage dashboard configuration logic: MailHog Email Testing: - Add MailHog service with configurable SMTP and Web UI ports - Configure MailHog ports in config.sh with defaults (1025 SMTP, 8025 Web) - Add port conflict checking for MailHog ports - Use environment variables for MailHog ports in docker-compose.yml Enhanced Homepage Configuration: - Improve update_services_yaml() function to handle Production and Local tabs separately - Add local IP address configuration prompt for Homepage Local tab - Support custom local network IPs (e.g., Tailscale) for local service access - Add comprehensive port-based URL mappings for all services in Local tab - Include MailHog in both Production and Local service mappings Configuration Improvements: - Add local_ip parameter to update_services_yaml function - Display MailHog information in port summary and next steps - Update completion message with Homepage Local tab configuration info These changes enable developers to test email functionality locally and provide better support for accessing services via local network IPs.
1546 lines
52 KiB
Bash
Executable File
1546 lines
52 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
cat << "EOF"
|
|
██████╗██╗ ██╗ █████╗ ███╗ ██╗ ██████╗ ███████╗
|
|
██╔════╝██║ ██║██╔══██╗████╗ ██║██╔════╝ ██╔════╝
|
|
██║ ███████║███████║██╔██╗ ██║██║ ███╗█████╗
|
|
██║ ██╔══██║██╔══██║██║╚██╗██║██║ ██║██╔══╝
|
|
╚██████╗██║ ██║██║ ██║██║ ╚████║╚██████╔╝███████╗
|
|
╚═════╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚══════╝
|
|
|
|
███╗ ███╗ █████╗ ██╗ ██╗███████╗██████╗
|
|
████╗ ████║██╔══██╗██║ ██╔╝██╔════╝██╔══██╗
|
|
██╔████╔██║███████║█████╔╝ █████╗ ██████╔╝
|
|
██║╚██╔╝██║██╔══██║██╔═██╗ ██╔══╝ ██╔══██╗
|
|
██║ ╚═╝ ██║██║ ██║██║ ██╗███████╗██║ ██║
|
|
╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
Configuration Wizard
|
|
EOF
|
|
|
|
# Get the absolute path of the script directory
|
|
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
ENV_FILE="$SCRIPT_DIR/.env"
|
|
MKDOCS_YML="$SCRIPT_DIR/mkdocs/mkdocs.yml" # Fixed path - removed extra 'docs' directory
|
|
TUNNEL_CONFIG_DIR="$SCRIPT_DIR/configs/cloudflare"
|
|
TUNNEL_CONFIG_FILE="$TUNNEL_CONFIG_DIR/tunnel-config.yml"
|
|
SERVICES_YAML="$SCRIPT_DIR/configs/homepage/services.yaml"
|
|
MAIN_HTML="$SCRIPT_DIR/mkdocs/docs/overrides/main.html"
|
|
MAP_ENV_FILE="$SCRIPT_DIR/map/.env" # Add the map's .env file path
|
|
DOCKER_COMPOSE_FILE="$SCRIPT_DIR/docker-compose.yml"
|
|
|
|
echo "Looking for .env file at: $ENV_FILE"
|
|
|
|
# Function to generate a random secure password
|
|
generate_password() {
|
|
local length=${1:-16}
|
|
openssl rand -base64 48 | tr -dc 'a-zA-Z0-9!@#$%^&*()-_=+' | head -c "$length"
|
|
}
|
|
|
|
# Function to safely update environment variables in .env file
|
|
update_env_var() {
|
|
local key=$1
|
|
local value=$2
|
|
|
|
# More robust method to handle special characters in passwords
|
|
if grep -q "^$key=" "$ENV_FILE"; then
|
|
# Create a temporary file
|
|
local tmpfile=$(mktemp)
|
|
|
|
# Process the .env file line by line
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ ^$key= ]]; then
|
|
echo "$key=$value" >> "$tmpfile"
|
|
else
|
|
echo "$line" >> "$tmpfile"
|
|
fi
|
|
done < "$ENV_FILE"
|
|
|
|
# Replace the original file with the temporary file
|
|
mv "$tmpfile" "$ENV_FILE"
|
|
echo "Updated $key in .env file"
|
|
else
|
|
# Add new key-value pair if it doesn't exist
|
|
echo "$key=$value" >> "$ENV_FILE"
|
|
echo "Added $key to .env file"
|
|
fi
|
|
}
|
|
|
|
# Function to create a timestamped backup of the .env file
|
|
backup_env_file() {
|
|
if [ -f "$ENV_FILE" ]; then
|
|
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
local backup_file="$ENV_FILE.backup_$timestamp"
|
|
|
|
echo "Creating backup of current .env file to: $backup_file"
|
|
if cp "$ENV_FILE" "$backup_file"; then
|
|
echo "Backup created successfully!"
|
|
return 0
|
|
else
|
|
echo "Failed to create backup file. Proceeding with caution..."
|
|
return 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# Function to fix permissions on directories that containers need to write to
|
|
# This prevents EACCES errors when containers try to create files/directories
|
|
fix_container_permissions() {
|
|
echo ""
|
|
echo "=== Fixing Container Directory Permissions ==="
|
|
echo "Setting up directories that containers need write access to..."
|
|
|
|
# Get the user/group IDs (default to 1000 if not set)
|
|
local user_id=${USER_ID:-1000}
|
|
local group_id=${GROUP_ID:-1000}
|
|
|
|
# Define directories that need to be writable by containers
|
|
# Format: "path:description"
|
|
local -a writable_dirs=(
|
|
"$SCRIPT_DIR/configs/code-server/.config:Code Server config"
|
|
"$SCRIPT_DIR/configs/code-server/.local:Code Server local data"
|
|
"$SCRIPT_DIR/mkdocs/.cache:MkDocs cache (social cards, etc.)"
|
|
"$SCRIPT_DIR/mkdocs/site:MkDocs built site"
|
|
"$SCRIPT_DIR/assets/uploads:Listmonk uploads"
|
|
"$SCRIPT_DIR/assets/images:Shared images"
|
|
)
|
|
|
|
local errors=0
|
|
|
|
for dir_entry in "${writable_dirs[@]}"; do
|
|
local dir_path="${dir_entry%%:*}"
|
|
local dir_desc="${dir_entry#*:}"
|
|
|
|
# Create directory if it doesn't exist
|
|
if [ ! -d "$dir_path" ]; then
|
|
echo " Creating: $dir_path ($dir_desc)"
|
|
mkdir -p "$dir_path"
|
|
fi
|
|
|
|
# Add .gitkeep to track empty directories in git
|
|
if [ ! -f "$dir_path/.gitkeep" ]; then
|
|
touch "$dir_path/.gitkeep"
|
|
fi
|
|
|
|
# Fix permissions - make writable by container user
|
|
if chmod -R 777 "$dir_path" 2>/dev/null; then
|
|
echo " ✅ $dir_desc: permissions fixed"
|
|
else
|
|
echo " ⚠️ $dir_desc: could not fix permissions (may need sudo)"
|
|
((errors++))
|
|
fi
|
|
done
|
|
|
|
# Handle directories that may have been created by containers with different UIDs
|
|
# These need special handling (may require sudo)
|
|
local -a potentially_owned_by_container=(
|
|
"$SCRIPT_DIR/mkdocs/site"
|
|
)
|
|
|
|
for dir_path in "${potentially_owned_by_container[@]}"; do
|
|
if [ -d "$dir_path" ]; then
|
|
# Check if we own the directory
|
|
if [ ! -w "$dir_path" ]; then
|
|
echo ""
|
|
echo " ⚠️ Directory $dir_path is not writable."
|
|
echo " This may have been created by a container with a different UID."
|
|
echo " To fix, run: sudo chown -R $user_id:$group_id $dir_path"
|
|
((errors++))
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo ""
|
|
if [ $errors -eq 0 ]; then
|
|
echo "✅ All container directories are properly configured!"
|
|
else
|
|
echo "⚠️ Some directories may need manual permission fixes."
|
|
echo " You can try: sudo chown -R $user_id:$group_id $SCRIPT_DIR"
|
|
fi
|
|
echo ""
|
|
|
|
return $errors
|
|
}
|
|
|
|
# Function to get all used ports on the system
|
|
get_used_ports() {
|
|
local used_ports=()
|
|
|
|
# Try different methods to get used ports, in order of preference
|
|
if command -v ss >/dev/null 2>&1; then
|
|
# Use ss (preferred, modern replacement for netstat)
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ :([0-9]+)[[:space:]] ]]; then
|
|
used_ports+=("${BASH_REMATCH[1]}")
|
|
fi
|
|
done < <(ss -tuln 2>/dev/null | grep -E ':[0-9]+[[:space:]]')
|
|
elif command -v netstat >/dev/null 2>&1; then
|
|
# Use netstat (fallback)
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ :([0-9]+)[[:space:]] ]]; then
|
|
used_ports+=("${BASH_REMATCH[1]}")
|
|
fi
|
|
done < <(netstat -tuln 2>/dev/null | grep -E ':[0-9]+[[:space:]]')
|
|
elif command -v lsof >/dev/null 2>&1; then
|
|
# Use lsof (another fallback)
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ :([0-9]+)[[:space:]] ]]; then
|
|
used_ports+=("${BASH_REMATCH[1]}")
|
|
fi
|
|
done < <(lsof -i -P -n 2>/dev/null | grep LISTEN | grep -E ':[0-9]+[[:space:]]')
|
|
else
|
|
echo "Warning: No port scanning tools available (ss, netstat, or lsof)"
|
|
return 1
|
|
fi
|
|
|
|
# Remove duplicates and sort
|
|
printf '%s\n' "${used_ports[@]}" | sort -nu
|
|
}
|
|
|
|
# Function to check if a specific port is available
|
|
is_port_available() {
|
|
local port=$1
|
|
local used_ports_list=$2
|
|
|
|
# Check if port is in the used ports list
|
|
if echo "$used_ports_list" | grep -q "^$port$"; then
|
|
return 1 # Port is in use
|
|
else
|
|
return 0 # Port is available
|
|
fi
|
|
}
|
|
|
|
# Function to find next available port starting from a given port
|
|
find_next_available_port() {
|
|
local start_port=$1
|
|
local used_ports_list=$2
|
|
local max_attempts=${3:-100} # Maximum ports to check
|
|
|
|
for ((i=0; i<max_attempts; i++)); do
|
|
local test_port=$((start_port + i))
|
|
|
|
# Skip ports below 1024 (system ports) and above 65535
|
|
if [ "$test_port" -lt 1024 ] || [ "$test_port" -gt 65535 ]; then
|
|
continue
|
|
fi
|
|
|
|
if is_port_available "$test_port" "$used_ports_list"; then
|
|
echo "$test_port"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
echo "Error: Could not find available port starting from $start_port" >&2
|
|
return 1
|
|
}
|
|
|
|
# Function to initialize available ports for services
|
|
initialize_available_ports() {
|
|
echo "Scanning system for used ports to avoid conflicts..."
|
|
|
|
# Get list of all used ports
|
|
local used_ports_list
|
|
used_ports_list=$(get_used_ports)
|
|
|
|
if [ $? -ne 0 ] || [ -z "$used_ports_list" ]; then
|
|
echo "Warning: Could not scan system ports. Using default ports."
|
|
echo "You may need to manually resolve conflicts later."
|
|
return 1
|
|
fi
|
|
|
|
echo "Found $(echo "$used_ports_list" | wc -l) ports currently in use"
|
|
|
|
# Define desired starting ports for each service
|
|
local -A service_ports=(
|
|
["CODE_SERVER_PORT"]=8888
|
|
["LISTMONK_PORT"]=9000
|
|
["LISTMONK_DB_PORT"]=5432
|
|
["MKDOCS_PORT"]=4000
|
|
["MKDOCS_SITE_SERVER_PORT"]=4001
|
|
["N8N_PORT"]=5678
|
|
["NOCODB_PORT"]=8090
|
|
["HOMEPAGE_PORT"]=3010
|
|
["GITEA_WEB_PORT"]=3030
|
|
["GITEA_SSH_PORT"]=2222
|
|
["MAP_PORT"]=3000
|
|
["INFLUENCE_PORT"]=3333
|
|
["MINI_QR_PORT"]=8089
|
|
["REDIS_PORT"]=6379
|
|
["PROMETHEUS_PORT"]=9090
|
|
["GRAFANA_PORT"]=3001
|
|
["CADVISOR_PORT"]=8080
|
|
["NODE_EXPORTER_PORT"]=9100
|
|
["REDIS_EXPORTER_PORT"]=9121
|
|
["ALERTMANAGER_PORT"]=9093
|
|
["GOTIFY_PORT"]=8889
|
|
["MAILHOG_SMTP_PORT"]=1025
|
|
["MAILHOG_WEB_PORT"]=8025
|
|
)
|
|
|
|
# Find available ports for each service
|
|
local -A available_ports
|
|
for service in "${!service_ports[@]}"; do
|
|
local preferred_port=${service_ports[$service]}
|
|
local available_port
|
|
|
|
if is_port_available "$preferred_port" "$used_ports_list"; then
|
|
available_port=$preferred_port
|
|
echo "✅ $service: Using preferred port $preferred_port"
|
|
else
|
|
available_port=$(find_next_available_port "$preferred_port" "$used_ports_list")
|
|
if [ $? -eq 0 ]; then
|
|
echo "⚠️ $service: Port $preferred_port in use, using $available_port instead"
|
|
else
|
|
echo "❌ $service: Could not find available port, using $preferred_port (may conflict)"
|
|
available_port=$preferred_port
|
|
fi
|
|
fi
|
|
|
|
available_ports[$service]=$available_port
|
|
# Add the assigned port to used_ports_list to avoid double-assignment
|
|
used_ports_list=$(printf '%s\n%s' "$used_ports_list" "$available_port" | sort -nu)
|
|
done
|
|
|
|
# Export the available ports as global variables
|
|
for service in "${!available_ports[@]}"; do
|
|
export "$service=${available_ports[$service]}"
|
|
done
|
|
|
|
echo "Port assignment completed successfully!"
|
|
return 0
|
|
}
|
|
|
|
# Function to initialize the .env file with default values
|
|
initialize_env_file() {
|
|
echo "Initializing new .env file with available ports..."
|
|
|
|
# Initialize available ports before creating the .env file
|
|
initialize_available_ports
|
|
|
|
cat > "$ENV_FILE" << EOL
|
|
# Never share this file publicly. It contains sensitive information.
|
|
# This file is used to configure various applications and services.
|
|
# Generated by Changemaker Config Wizard on $(date)
|
|
|
|
# User and Group Configuration
|
|
USER_NAME=coder
|
|
USER_ID=1000
|
|
GROUP_ID=1000
|
|
|
|
# Port Configuration (automatically assigned to avoid conflicts)
|
|
CODE_SERVER_PORT=${CODE_SERVER_PORT:-8888}
|
|
LISTMONK_PORT=${LISTMONK_PORT:-9000}
|
|
LISTMONK_DB_PORT=${LISTMONK_DB_PORT:-5432}
|
|
MKDOCS_PORT=${MKDOCS_PORT:-4000}
|
|
MKDOCS_SITE_SERVER_PORT=${MKDOCS_SITE_SERVER_PORT:-4001}
|
|
N8N_PORT=${N8N_PORT:-5678}
|
|
NOCODB_PORT=${NOCODB_PORT:-8090}
|
|
HOMEPAGE_PORT=${HOMEPAGE_PORT:-3010}
|
|
GITEA_WEB_PORT=${GITEA_WEB_PORT:-3030}
|
|
GITEA_SSH_PORT=${GITEA_SSH_PORT:-2222}
|
|
MAP_PORT=${MAP_PORT:-3000}
|
|
INFLUENCE_PORT=${INFLUENCE_PORT:-3333}
|
|
MINI_QR_PORT=${MINI_QR_PORT:-8089}
|
|
|
|
# Centralized Services Ports
|
|
REDIS_PORT=${REDIS_PORT:-6379}
|
|
PROMETHEUS_PORT=${PROMETHEUS_PORT:-9090}
|
|
GRAFANA_PORT=${GRAFANA_PORT:-3001}
|
|
|
|
# Monitoring Exporters Ports
|
|
CADVISOR_PORT=${CADVISOR_PORT:-8080}
|
|
NODE_EXPORTER_PORT=${NODE_EXPORTER_PORT:-9100}
|
|
REDIS_EXPORTER_PORT=${REDIS_EXPORTER_PORT:-9121}
|
|
|
|
# Alerting Services Ports
|
|
ALERTMANAGER_PORT=${ALERTMANAGER_PORT:-9093}
|
|
GOTIFY_PORT=${GOTIFY_PORT:-8889}
|
|
|
|
# MailHog Email Testing Ports
|
|
MAILHOG_SMTP_PORT=${MAILHOG_SMTP_PORT:-1025}
|
|
MAILHOG_WEB_PORT=${MAILHOG_WEB_PORT:-8025}
|
|
|
|
# Domain Configuration
|
|
BASE_DOMAIN=https://changeme.org
|
|
DOMAIN=changeme.org
|
|
LISTMONK_HOSTNAME=listmonk.changeme.org
|
|
N8N_HOST=n8n.changeme.org
|
|
GITEA_DOMAIN=git.changeme.org
|
|
GITEA_ROOT_URL=https://git.changeme.org
|
|
HOMEPAGE_VAR_BASE_URL=https://changeme.org
|
|
|
|
# Cookie and CORS Configuration
|
|
COOKIE_DOMAIN=.changeme.org
|
|
ALLOWED_ORIGINS=https://map.changeme.org,http://localhost:3000
|
|
|
|
# Cloudflare Configuration
|
|
CF_API_TOKEN=your_cloudflare_api_token
|
|
CF_ZONE_ID=your_cloudflare_zone_id
|
|
CF_TUNNEL_ID=your_cloudflared_tunnel_id
|
|
CF_DOMAIN=changeme.org
|
|
CF_ACCOUNT_ID=your_cloudflare_account_id
|
|
|
|
# Database Configuration (PostgreSQL for Listmonk)
|
|
POSTGRES_USER=listmonk
|
|
POSTGRES_PASSWORD=changeMe
|
|
POSTGRES_DB=listmonk
|
|
|
|
# Listmonk Database Performance Settings
|
|
LISTMONK_DB_MAX_OPEN=25
|
|
LISTMONK_DB_MAX_IDLE=25
|
|
LISTMONK_DB_MAX_LIFETIME=300s
|
|
|
|
# Listmonk Admin Configuration
|
|
LISTMONK_ADMIN_USER=admin
|
|
LISTMONK_ADMIN_PASSWORD=changeMe
|
|
|
|
# N8N Configuration
|
|
N8N_USER_EMAIL=admin@example.com
|
|
N8N_USER_PASSWORD=changeMe
|
|
N8N_ENCRYPTION_KEY=changeMe
|
|
GENERIC_TIMEZONE=UTC
|
|
|
|
# Nocodb Configuration
|
|
NOCODB_JWT_SECRET=changeMe
|
|
NOCODB_DB_NAME=nocodb
|
|
NOCODB_DB_USER=noco
|
|
NOCODB_DB_PASSWORD=changeMe
|
|
|
|
# Gitea Database Configuration
|
|
GITEA_DB_PASSWD=changeMe
|
|
GITEA_DB_ROOT_PASSWORD=changeMe
|
|
|
|
# Centralized Services Configuration
|
|
# Redis (used by all applications for caching, sessions, queues)
|
|
REDIS_HOST=redis-changemaker
|
|
REDIS_PORT=6379
|
|
REDIS_PASSWORD=
|
|
|
|
# Prometheus (metrics collection)
|
|
PROMETHEUS_PORT=9090
|
|
PROMETHEUS_RETENTION_TIME=30d
|
|
|
|
# Grafana (monitoring dashboards)
|
|
GRAFANA_PORT=3001
|
|
GRAFANA_ADMIN_USER=admin
|
|
GRAFANA_ADMIN_PASSWORD=changeMe
|
|
GRAFANA_ROOT_URL=http://localhost:3001
|
|
|
|
# Monitoring Exporters
|
|
CADVISOR_PORT=8080
|
|
NODE_EXPORTER_PORT=9100
|
|
REDIS_EXPORTER_PORT=9121
|
|
|
|
# Alertmanager (alert routing)
|
|
ALERTMANAGER_PORT=9093
|
|
|
|
# Gotify (push notifications)
|
|
GOTIFY_PORT=8889
|
|
GOTIFY_ADMIN_USER=admin
|
|
GOTIFY_ADMIN_PASSWORD=changeMe
|
|
GOTIFY_APP_TOKEN=
|
|
|
|
# Alert Email Configuration
|
|
ALERT_EMAIL_TO=admin@changeme.org
|
|
EOL
|
|
|
|
echo "New .env file created with conflict-free port assignments."
|
|
|
|
# Show port assignments summary
|
|
echo ""
|
|
echo "=== Port Assignments Summary ==="
|
|
echo "Code Server: ${CODE_SERVER_PORT:-8888}"
|
|
echo "Listmonk: ${LISTMONK_PORT:-9000}"
|
|
echo "Listmonk DB: ${LISTMONK_DB_PORT:-5432}"
|
|
echo "MkDocs: ${MKDOCS_PORT:-4000}"
|
|
echo "MkDocs Site: ${MKDOCS_SITE_SERVER_PORT:-4001}"
|
|
echo "N8N: ${N8N_PORT:-5678}"
|
|
echo "NocoDB: ${NOCODB_PORT:-8090}"
|
|
echo "Homepage: ${HOMEPAGE_PORT:-3010}"
|
|
echo "Gitea Web: ${GITEA_WEB_PORT:-3030}"
|
|
echo "Gitea SSH: ${GITEA_SSH_PORT:-2222}"
|
|
echo "Map: ${MAP_PORT:-3000}"
|
|
echo "Influence: ${INFLUENCE_PORT:-3333}"
|
|
echo "Mini QR: ${MINI_QR_PORT:-8089}"
|
|
echo ""
|
|
echo "=== Centralized Services ==="
|
|
echo "Redis: ${REDIS_PORT:-6379}"
|
|
echo "Prometheus: ${PROMETHEUS_PORT:-9090}"
|
|
echo "Grafana: ${GRAFANA_PORT:-3001}"
|
|
echo ""
|
|
echo "=== Monitoring Services ==="
|
|
echo "cAdvisor: ${CADVISOR_PORT:-8080}"
|
|
echo "Node Exporter: ${NODE_EXPORTER_PORT:-9100}"
|
|
echo "Redis Exporter: ${REDIS_EXPORTER_PORT:-9121}"
|
|
echo "Alertmanager: ${ALERTMANAGER_PORT:-9093}"
|
|
echo "Gotify: ${GOTIFY_PORT:-8889}"
|
|
echo ""
|
|
echo "=== Email Testing ==="
|
|
echo "MailHog SMTP: ${MAILHOG_SMTP_PORT:-1025}"
|
|
echo "MailHog Web: ${MAILHOG_WEB_PORT:-8025}"
|
|
echo "================================"
|
|
}
|
|
|
|
# Function to update the site_url in mkdocs.yml
|
|
update_mkdocs_yml() {
|
|
local new_domain=$1
|
|
|
|
if [ ! -f "$MKDOCS_YML" ]; then
|
|
echo "Warning: mkdocs.yml not found at $MKDOCS_YML"
|
|
return 1
|
|
fi
|
|
|
|
echo "Updating site_url in mkdocs.yml..."
|
|
|
|
# Create a backup of the mkdocs.yml file
|
|
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
local backup_file="${MKDOCS_YML}.backup_${timestamp}"
|
|
cp "$MKDOCS_YML" "$backup_file"
|
|
echo "Created backup of mkdocs.yml at $backup_file"
|
|
|
|
# Update the site_url value - handle both http and https
|
|
sed -i "s|^site_url:.*|site_url: https://$new_domain|" "$MKDOCS_YML"
|
|
|
|
if grep -q "site_url: https://$new_domain" "$MKDOCS_YML"; then
|
|
echo "✅ Updated site_url in mkdocs.yml to: https://$new_domain"
|
|
return 0
|
|
else
|
|
echo "Warning: Failed to update site_url in mkdocs.yml"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# Function to update service URLs in services.yaml
|
|
update_services_yaml() {
|
|
local new_domain=$1
|
|
local local_ip=${2:-"localhost"} # Optional parameter for local IP address
|
|
|
|
if [ ! -f "$SERVICES_YAML" ]; then
|
|
echo "Warning: services.yaml not found at $SERVICES_YAML"
|
|
return 1
|
|
fi
|
|
|
|
echo "Updating service URLs in services.yaml..."
|
|
|
|
# Create a backup of the services.yaml file
|
|
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
local backup_file="${SERVICES_YAML}.backup_${timestamp}"
|
|
cp "$SERVICES_YAML" "$backup_file"
|
|
echo "Created backup of services.yaml at $backup_file"
|
|
|
|
# Load environment variables to get port numbers
|
|
load_env_vars
|
|
|
|
# Define service name to subdomain mapping for Production tab
|
|
# This approach is URL-agnostic - it doesn't matter what the current URLs are
|
|
declare -A production_mappings=(
|
|
["Code Server"]="code.$new_domain"
|
|
["Listmonk"]="listmonk.$new_domain"
|
|
["NocoDB"]="db.$new_domain"
|
|
["Main Site"]="$new_domain"
|
|
["MkDocs (Live)"]="docs.$new_domain"
|
|
["Mini QR"]="qr.$new_domain"
|
|
["MailHog"]="mail.$new_domain"
|
|
["n8n"]="n8n.$new_domain"
|
|
["Gitea"]="git.$new_domain"
|
|
["Prometheus"]="prometheus.$new_domain"
|
|
["Grafana"]="grafana.$new_domain"
|
|
["Alertmanager"]="alertmanager.$new_domain"
|
|
["Gotify"]="gotify.$new_domain"
|
|
["cAdvisor"]="cadvisor.$new_domain"
|
|
)
|
|
|
|
# Define service name to local URL mapping for Local tab
|
|
declare -A local_mappings=(
|
|
["Code Server"]="$local_ip:${CODE_SERVER_PORT:-8888}"
|
|
["NocoDB"]="$local_ip:${NOCODB_PORT:-8090}"
|
|
["Homepage"]="$local_ip:${HOMEPAGE_PORT:-3010}"
|
|
["Main Site"]="$local_ip:${MKDOCS_SITE_SERVER_PORT:-4001}"
|
|
["MkDocs (Live)"]="$local_ip:${MKDOCS_PORT:-4000}"
|
|
["Mini QR"]="$local_ip:${MINI_QR_PORT:-8089}"
|
|
["Listmonk"]="$local_ip:${LISTMONK_PORT:-9001}"
|
|
["MailHog"]="$local_ip:${MAILHOG_WEB_PORT:-8025}"
|
|
["n8n"]="$local_ip:${N8N_PORT:-5678}"
|
|
["Gitea"]="$local_ip:${GITEA_WEB_PORT:-3030}"
|
|
["Prometheus"]="$local_ip:${PROMETHEUS_PORT:-9090}"
|
|
["Grafana"]="$local_ip:${GRAFANA_PORT:-3001}"
|
|
["Alertmanager"]="$local_ip:${ALERTMANAGER_PORT:-9093}"
|
|
["Gotify"]="$local_ip:${GOTIFY_PORT:-8889}"
|
|
["cAdvisor"]="$local_ip:${CADVISOR_PORT:-8080}"
|
|
["Node Exporter"]="$local_ip:${NODE_EXPORTER_PORT:-9100}/metrics"
|
|
["Redis Exporter"]="$local_ip:${REDIS_EXPORTER_PORT:-9121}/metrics"
|
|
)
|
|
|
|
# Update Production URLs
|
|
echo "Updating Production tab URLs..."
|
|
for service_name in "${!production_mappings[@]}"; do
|
|
local target_url="https://${production_mappings[$service_name]}"
|
|
|
|
# Use awk to find and update the href for Production services only
|
|
awk -v service="$service_name" -v new_url="$target_url" '
|
|
BEGIN {
|
|
in_production = 0
|
|
in_service = 0
|
|
}
|
|
|
|
# Track if we are in Production section
|
|
/^- Production/ { in_production = 1; in_service = 0 }
|
|
/^- Local/ { in_production = 0; in_service = 0 }
|
|
|
|
# Check if we found the service name in Production section
|
|
in_production && /^ - [^:]+:/ {
|
|
if ($0 ~ (" - " service ":")) {
|
|
in_service = 1
|
|
} else {
|
|
in_service = 0
|
|
}
|
|
}
|
|
|
|
# If we are in the target service and find href line, update it
|
|
in_production && in_service && /href:/ {
|
|
gsub(/href: "[^"]*"/, "href: \"" new_url "\"")
|
|
}
|
|
|
|
# Print the line (modified or not)
|
|
{ print }
|
|
' "$SERVICES_YAML" > "${SERVICES_YAML}.tmp"
|
|
|
|
mv "${SERVICES_YAML}.tmp" "$SERVICES_YAML"
|
|
echo " ✓ Production: $service_name -> $target_url"
|
|
done
|
|
|
|
# Update Local URLs
|
|
echo "Updating Local tab URLs..."
|
|
for service_name in "${!local_mappings[@]}"; do
|
|
local target_url="http://${local_mappings[$service_name]}"
|
|
|
|
# Use awk to find and update the href for Local services only
|
|
awk -v service="$service_name" -v new_url="$target_url" '
|
|
BEGIN {
|
|
in_local = 0
|
|
in_service = 0
|
|
}
|
|
|
|
# Track if we are in Local section
|
|
/^- Local/ { in_local = 1; in_service = 0 }
|
|
/^- Production/ { in_local = 0; in_service = 0 }
|
|
|
|
# Check if we found the service name in Local section
|
|
in_local && /^ - [^:]+:/ {
|
|
if ($0 ~ (" - " service ":")) {
|
|
in_service = 1
|
|
} else {
|
|
in_service = 0
|
|
}
|
|
}
|
|
|
|
# If we are in the target service and find href line, update it
|
|
in_local && in_service && /href:/ {
|
|
gsub(/href: "[^"]*"/, "href: \"" new_url "\"")
|
|
}
|
|
|
|
# Print the line (modified or not)
|
|
{ print }
|
|
' "$SERVICES_YAML" > "${SERVICES_YAML}.tmp"
|
|
|
|
mv "${SERVICES_YAML}.tmp" "$SERVICES_YAML"
|
|
echo " ✓ Local: $service_name -> $target_url"
|
|
done
|
|
|
|
echo "✅ All service URLs updated:"
|
|
echo " - Production tab: $new_domain"
|
|
echo " - Local tab: $local_ip"
|
|
return 0
|
|
}
|
|
|
|
# Function to update the login URL in main.html
|
|
update_main_html() {
|
|
local new_domain=$1
|
|
|
|
if [ ! -f "$MAIN_HTML" ]; then
|
|
echo "Warning: main.html not found at $MAIN_HTML"
|
|
return 1
|
|
fi
|
|
|
|
echo "Updating login URL in main.html..."
|
|
|
|
# Create a backup of the main.html file
|
|
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
local backup_file="${MAIN_HTML}.backup_${timestamp}"
|
|
cp "$MAIN_HTML" "$backup_file"
|
|
echo "Created backup of main.html at $backup_file"
|
|
|
|
# Update the login button href - handle current domain
|
|
sed -i "s|href=\"https://homepage\.[^\"]*\"|href=\"https://homepage.$new_domain\"|g" "$MAIN_HTML"
|
|
|
|
# Also update any albertademocracytaskforce.org references
|
|
sed -i "s|albertademocracytaskforce\.org|$new_domain|g" "$MAIN_HTML"
|
|
|
|
# Update any test.com or changeme.org references
|
|
sed -i "s|test\.com|$new_domain|g" "$MAIN_HTML"
|
|
sed -i "s|changeme\.org|$new_domain|g" "$MAIN_HTML"
|
|
|
|
echo "✅ Updated login URL in main.html to: https://homepage.$new_domain"
|
|
return 0
|
|
}
|
|
|
|
# Function to get Cloudflare API Token and Zone ID
|
|
get_cloudflare_credentials() {
|
|
echo ""
|
|
echo "To use Cloudflare tunnels, you'll need to configure your credentials."
|
|
echo ""
|
|
echo "=== Cloudflare Configuration ==="
|
|
echo ""
|
|
echo "You'll need:"
|
|
echo "1. Your Cloudflare API Token (with Zone.DNS and Account.Cloudflare Tunnel permissions)"
|
|
echo "2. Your Cloudflare Zone ID (found in the Cloudflare dashboard overview)"
|
|
echo "3. Your Cloudflare Account ID (found in the Cloudflare dashboard)"
|
|
echo ""
|
|
echo "These credentials will be used for:"
|
|
echo "- Creating and configuring tunnels"
|
|
echo "- Managing DNS records"
|
|
echo "- Setting up access policies"
|
|
echo ""
|
|
}
|
|
|
|
# Function to update the tunnel configuration file with new domain
|
|
update_tunnel_config() {
|
|
local new_domain=$1
|
|
local tunnel_id=${2:-"(insert-tunnel-id)"}
|
|
local creds_path=${3:-"/path/to/credentials/file"}
|
|
|
|
# Create directory if it doesn't exist
|
|
mkdir -p "$TUNNEL_CONFIG_DIR"
|
|
|
|
echo "Updating tunnel configuration with new domain..."
|
|
|
|
# Create a backup if file exists
|
|
if [ -f "$TUNNEL_CONFIG_FILE" ]; then
|
|
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
local backup_file="${TUNNEL_CONFIG_FILE}.backup_${timestamp}"
|
|
cp "$TUNNEL_CONFIG_FILE" "$backup_file"
|
|
echo "Created backup of tunnel-config.yml at $backup_file"
|
|
fi
|
|
|
|
# Load current environment variables to get port numbers
|
|
load_env_vars
|
|
|
|
# Create/update the tunnel configuration
|
|
cat > "$TUNNEL_CONFIG_FILE" << EOL
|
|
# filepath: /home/bunker-admin/changemaker.lite/configs/cloudflare/tunnel-config.yml
|
|
# Cloudflare Tunnel Configuration
|
|
# Auto-generated by Changemaker Configuration Wizard
|
|
|
|
tunnel: $tunnel_id # e.g. 1234567890abcdef
|
|
credentials-file: $creds_path # e.g. /home/bunker-admin/.cloudflared/[insert tunnel number].json
|
|
ingress:
|
|
|
|
- hostname: homepage.$new_domain
|
|
service: http://localhost:${HOMEPAGE_PORT:-3010}
|
|
|
|
- hostname: code.$new_domain
|
|
service: http://localhost:${CODE_SERVER_PORT:-8888}
|
|
|
|
- hostname: listmonk.$new_domain
|
|
service: http://localhost:${LISTMONK_PORT:-9001}
|
|
|
|
- hostname: docs.$new_domain
|
|
service: http://localhost:${MKDOCS_PORT:-4000}
|
|
|
|
- hostname: $new_domain
|
|
service: http://localhost:${MKDOCS_SITE_SERVER_PORT:-4002}
|
|
|
|
- hostname: n8n.$new_domain
|
|
service: http://localhost:${N8N_PORT:-5678}
|
|
|
|
- hostname: db.$new_domain
|
|
service: http://localhost:${NOCODB_PORT:-8090}
|
|
|
|
- hostname: git.$new_domain
|
|
service: http://localhost:${GITEA_WEB_PORT:-3030}
|
|
|
|
- hostname: map.$new_domain
|
|
service: http://localhost:${MAP_PORT:-3000}
|
|
|
|
- hostname: influence.$new_domain
|
|
service: http://localhost:${INFLUENCE_PORT:-3333}
|
|
|
|
- hostname: qr.$new_domain
|
|
service: http://localhost:${MINI_QR_PORT:-8089}
|
|
|
|
- hostname: prometheus.$new_domain
|
|
service: http://localhost:${PROMETHEUS_PORT:-9090}
|
|
|
|
- hostname: grafana.$new_domain
|
|
service: http://localhost:${GRAFANA_PORT:-3001}
|
|
|
|
- hostname: alertmanager.$new_domain
|
|
service: http://localhost:${ALERTMANAGER_PORT:-9093}
|
|
|
|
- hostname: gotify.$new_domain
|
|
service: http://localhost:${GOTIFY_PORT:-8889}
|
|
|
|
- hostname: cadvisor.$new_domain
|
|
service: http://localhost:${CADVISOR_PORT:-8080}
|
|
|
|
# Catch-all rule (required)
|
|
- service: http_status:404
|
|
EOL
|
|
|
|
echo "✅ Updated tunnel configuration for domain: $new_domain"
|
|
return 0
|
|
}
|
|
|
|
# Function to load environment variables from .env file
|
|
load_env_vars() {
|
|
if [ -f "$ENV_FILE" ]; then
|
|
# Load variables from .env file, ignoring comments and empty lines
|
|
while IFS= read -r line; do
|
|
if [[ "$line" =~ ^[A-Za-z_][A-Za-z0-9_]*= ]]; then
|
|
export "$line"
|
|
fi
|
|
done < <(grep -E '^[A-Za-z_][A-Za-z0-9_]*=' "$ENV_FILE")
|
|
fi
|
|
}
|
|
|
|
# Function to sync ports from root .env to map .env
|
|
sync_map_ports() {
|
|
echo "Syncing ports from root .env to map configuration..."
|
|
|
|
# Load the current port values from root .env
|
|
local mkdocs_port=$(grep "^MKDOCS_PORT=" "$ENV_FILE" | cut -d'=' -f2)
|
|
local mkdocs_site_port=$(grep "^MKDOCS_SITE_SERVER_PORT=" "$ENV_FILE" | cut -d'=' -f2)
|
|
local map_port=$(grep "^MAP_PORT=" "$ENV_FILE" | cut -d'=' -f2)
|
|
|
|
# Set defaults if not found
|
|
mkdocs_port=${mkdocs_port:-4000}
|
|
mkdocs_site_port=${mkdocs_site_port:-4002}
|
|
map_port=${map_port:-3000}
|
|
|
|
# Update the map's .env with the correct ports
|
|
if grep -q "^PORT=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^PORT=.*|PORT=$map_port|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "PORT=$map_port" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Add/Update MkDocs configuration
|
|
if grep -q "^MKDOCS_URL=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^MKDOCS_URL=.*|MKDOCS_URL=http://localhost:$mkdocs_site_port|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "" >> "$MAP_ENV_FILE"
|
|
echo "# MkDocs Integration" >> "$MAP_ENV_FILE"
|
|
echo "MKDOCS_URL=http://localhost:$mkdocs_site_port" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
if grep -q "^MKDOCS_SEARCH_URL=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^MKDOCS_SEARCH_URL=.*|MKDOCS_SEARCH_URL=http://localhost:$mkdocs_site_port|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "MKDOCS_SEARCH_URL=http://localhost:$mkdocs_site_port" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
if grep -q "^MKDOCS_SITE_SERVER_PORT=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^MKDOCS_SITE_SERVER_PORT=.*|MKDOCS_SITE_SERVER_PORT=$mkdocs_site_port|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "MKDOCS_SITE_SERVER_PORT=$mkdocs_site_port" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
echo "✅ Synced ports to map configuration:"
|
|
echo " - Map Port: $map_port"
|
|
echo " - MkDocs Dev Port: $mkdocs_port"
|
|
echo " - MkDocs Site Port: $mkdocs_site_port"
|
|
echo " - MkDocs URL: http://localhost:$mkdocs_site_port"
|
|
}
|
|
|
|
# Function to update or create the map's .env file with domain settings
|
|
update_map_env() {
|
|
local new_domain=$1
|
|
|
|
# If the map .env file does not exist, create it with defaults
|
|
if [ ! -f "$MAP_ENV_FILE" ]; then
|
|
echo "Map .env file not found at $MAP_ENV_FILE, creating a new one with defaults."
|
|
cat > "$MAP_ENV_FILE" <<EOL
|
|
NOCODB_API_URL=https://db.$new_domain/api/v1
|
|
NOCODB_API_TOKEN=changeme
|
|
|
|
# NocoDB View URL is the URL to your NocoDB view where the map data is stored.
|
|
NOCODB_VIEW_URL=
|
|
|
|
# NOCODB_LOGIN_SHEET is the URL to your NocoDB login sheet.
|
|
NOCODB_LOGIN_SHEET=
|
|
|
|
# NOCODB_SETTINGS_SHEET is the URL to your NocoDB settings sheet.
|
|
NOCODB_SETTINGS_SHEET=
|
|
|
|
# NOCODB_SHIFTS_SHEET is the urls to your shifts sheets.
|
|
NOCODB_SHIFTS_SHEET=
|
|
|
|
# NOCODB_SHIFT_SIGNUPS_SHEET is the URL to your NocoDB shift signups sheet where users can add their own shifts.
|
|
NOCODB_SHIFT_SIGNUPS_SHEET=
|
|
|
|
# Server Configuration
|
|
PORT=3000
|
|
NODE_ENV=production
|
|
|
|
# Session Secret (IMPORTANT: Generate a secure random string for production)
|
|
# You can generate one with: openssl rand -hex 32
|
|
SESSION_SECRET=$(openssl rand -hex 32 2>/dev/null || echo "changeme")
|
|
|
|
# Map Defaults (Edmonton, Alberta, Canada)
|
|
DEFAULT_LAT=53.5461
|
|
DEFAULT_LNG=-113.4938
|
|
DEFAULT_ZOOM=11
|
|
|
|
# Optional: Map Boundaries (prevents users from adding points outside area)
|
|
# BOUND_NORTH=53.7
|
|
# BOUND_SOUTH=53.4
|
|
# BOUND_EAST=-113.3
|
|
# BOUND_WEST=-113.7
|
|
|
|
# Cloudflare Settings
|
|
TRUST_PROXY=true
|
|
COOKIE_DOMAIN=.$new_domain
|
|
|
|
# Update NODE_ENV to production for HTTPS
|
|
NODE_ENV=production
|
|
|
|
# Add allowed origin
|
|
ALLOWED_ORIGINS=https://map.$new_domain,http://localhost:3000
|
|
|
|
# Add allowed origin
|
|
ALLOWED_ORIGINS=https://map.$new_domain,http://localhost:3000
|
|
|
|
# SMTP Configuration
|
|
SMTP_HOST=smtp.insert.here
|
|
SMTP_PORT=insert_port
|
|
SMTP_SECURE=false
|
|
SMTP_USER=changeme@$new_domain
|
|
SMTP_PASS=changeme
|
|
EMAIL_FROM_NAME="$new_domain Map"
|
|
EMAIL_FROM_ADDRESS=changeme@$new_domain
|
|
|
|
# App Configuration
|
|
APP_NAME="$new_domain Map"
|
|
|
|
# Listmonk Configuration
|
|
LISTMONK_API_URL=http://listmonk_app:9000/api
|
|
LISTMONK_PASSWORD=changeme
|
|
LISTMONK_SYNC_ENABLED=true
|
|
LISTMONK_INITIAL_SYNC=false # Set to true to sync existing data
|
|
|
|
EOL
|
|
echo "✅ Created new map .env file at $MAP_ENV_FILE"
|
|
return 0
|
|
fi
|
|
|
|
echo "Updating map .env file with new domain settings..."
|
|
|
|
# Create a backup of the map's .env file
|
|
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
local backup_file="${MAP_ENV_FILE}.backup_${timestamp}"
|
|
cp "$MAP_ENV_FILE" "$backup_file"
|
|
echo "Created backup of map .env at $backup_file"
|
|
|
|
# Update DOMAIN
|
|
if grep -q "^DOMAIN=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^DOMAIN=.*|DOMAIN=$new_domain|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "DOMAIN=$new_domain" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update NOCODB_API_URL to use new domain
|
|
if grep -q "^NOCODB_API_URL=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^NOCODB_API_URL=.*|NOCODB_API_URL=https://db.$new_domain/api/v1|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "NOCODB_API_URL=https://db.$new_domain/api/v1" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Add NOCODB_CUTS_SHEET if missing
|
|
if ! grep -q "^NOCODB_CUTS_SHEET=" "$MAP_ENV_FILE"; then
|
|
echo "NOCODB_CUTS_SHEET=" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update MKDOCS_URL to use new domain
|
|
if grep -q "^MKDOCS_URL=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^MKDOCS_URL=.*|MKDOCS_URL=https://$new_domain|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "MKDOCS_URL=https://$new_domain" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update MKDOCS_SEARCH_URL to use new domain
|
|
if grep -q "^MKDOCS_SEARCH_URL=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^MKDOCS_SEARCH_URL=.*|MKDOCS_SEARCH_URL=https://$new_domain|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "MKDOCS_SEARCH_URL=https://$new_domain" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update COOKIE_DOMAIN
|
|
if grep -q "^COOKIE_DOMAIN=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^COOKIE_DOMAIN=.*|COOKIE_DOMAIN=.$new_domain|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "COOKIE_DOMAIN=.$new_domain" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update ALLOWED_ORIGINS
|
|
local allowed_origins="https://map.$new_domain,http://localhost:3000"
|
|
if grep -q "^ALLOWED_ORIGINS=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^ALLOWED_ORIGINS=.*|ALLOWED_ORIGINS=$allowed_origins|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "ALLOWED_ORIGINS=$allowed_origins" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update EMAIL_FROM_NAME
|
|
if grep -q "^EMAIL_FROM_NAME=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^EMAIL_FROM_NAME=.*|EMAIL_FROM_NAME=\"$new_domain Map\"|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "EMAIL_FROM_NAME=\"$new_domain Map\"" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update EMAIL_FROM_ADDRESS if it contains a domain reference
|
|
if grep -q "^EMAIL_FROM_ADDRESS=" "$MAP_ENV_FILE"; then
|
|
# Only update if it looks like it contains a domain placeholder
|
|
if grep -q "changeme@\|insert_from_address" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^EMAIL_FROM_ADDRESS=.*|EMAIL_FROM_ADDRESS=changeme@$new_domain|" "$MAP_ENV_FILE"
|
|
fi
|
|
else
|
|
echo "EMAIL_FROM_ADDRESS=changeme@$new_domain" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update SMTP_USER if it contains a domain reference
|
|
if grep -q "^SMTP_USER=" "$MAP_ENV_FILE"; then
|
|
# Only update if it looks like it contains a domain placeholder
|
|
if grep -q "changeme@\|@bnkops.ca" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^SMTP_USER=.*|SMTP_USER=changeme@$new_domain|" "$MAP_ENV_FILE"
|
|
fi
|
|
else
|
|
echo "SMTP_USER=changeme@$new_domain" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update APP_NAME
|
|
if grep -q "^APP_NAME=" "$MAP_ENV_FILE"; then
|
|
sed -i "s|^APP_NAME=.*|APP_NAME=\"$new_domain Map\"|" "$MAP_ENV_FILE"
|
|
else
|
|
echo "APP_NAME=\"$new_domain Map\"" >> "$MAP_ENV_FILE"
|
|
fi
|
|
|
|
# Update domain references in NocoDB URLs while preserving the sheet IDs and paths
|
|
# This will update domains like cmlite.org, changeme.org, etc. to the new domain
|
|
sed -i "s|://db\.cmlite\.org/|://db.$new_domain/|g" "$MAP_ENV_FILE"
|
|
sed -i "s|://map\.cmlite\.org|://map.$new_domain|g" "$MAP_ENV_FILE"
|
|
|
|
echo "✅ Updated map .env file with:"
|
|
echo " - NOCODB_API_URL=https://db.$new_domain/api/v1"
|
|
echo " - COOKIE_DOMAIN=.$new_domain"
|
|
echo " - ALLOWED_ORIGINS=$allowed_origins"
|
|
echo " - Updated all NocoDB URLs to use $new_domain domain"
|
|
|
|
# Sync ports to map configuration
|
|
sync_map_ports
|
|
|
|
return 0
|
|
}
|
|
|
|
# Function to check for port conflicts in existing .env file
|
|
check_port_conflicts() {
|
|
echo "Checking for port conflicts in existing configuration..."
|
|
|
|
# Get list of all used ports on system
|
|
local used_ports_list
|
|
used_ports_list=$(get_used_ports)
|
|
|
|
if [ $? -ne 0 ] || [ -z "$used_ports_list" ]; then
|
|
echo "Warning: Could not scan system ports. Skipping conflict check."
|
|
return 1
|
|
fi
|
|
|
|
# Check each configured port
|
|
local -a conflicts=()
|
|
local -a port_vars=(
|
|
"CODE_SERVER_PORT"
|
|
"LISTMONK_PORT"
|
|
"LISTMONK_DB_PORT"
|
|
"MKDOCS_PORT"
|
|
"MKDOCS_SITE_SERVER_PORT"
|
|
"N8N_PORT"
|
|
"NOCODB_PORT"
|
|
"HOMEPAGE_PORT"
|
|
"GITEA_WEB_PORT"
|
|
"GITEA_SSH_PORT"
|
|
"MAP_PORT"
|
|
"INFLUENCE_PORT"
|
|
"MINI_QR_PORT"
|
|
"REDIS_PORT"
|
|
"PROMETHEUS_PORT"
|
|
"GRAFANA_PORT"
|
|
"CADVISOR_PORT"
|
|
"NODE_EXPORTER_PORT"
|
|
"REDIS_EXPORTER_PORT"
|
|
"ALERTMANAGER_PORT"
|
|
"GOTIFY_PORT"
|
|
"MAILHOG_SMTP_PORT"
|
|
"MAILHOG_WEB_PORT"
|
|
)
|
|
|
|
for var in "${port_vars[@]}"; do
|
|
local port_value="${!var}"
|
|
if [ -n "$port_value" ] && ! is_port_available "$port_value" "$used_ports_list"; then
|
|
conflicts+=("$var=$port_value")
|
|
fi
|
|
done
|
|
|
|
if [ ${#conflicts[@]} -gt 0 ]; then
|
|
echo ""
|
|
echo "⚠️ WARNING: Port conflicts detected!"
|
|
echo "The following ports are already in use on your system:"
|
|
for conflict in "${conflicts[@]}"; do
|
|
echo " - $conflict"
|
|
done
|
|
echo ""
|
|
echo "You may need to:"
|
|
echo "1. Stop services using these ports, or"
|
|
echo "2. Edit .env file to use different ports"
|
|
echo ""
|
|
else
|
|
echo "✅ No port conflicts detected!"
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
# Function to get instance identifier
|
|
get_instance_identifier() {
|
|
# Try to get from directory name first
|
|
local dir_name=$(basename "$SCRIPT_DIR")
|
|
local default_instance=""
|
|
|
|
# Extract potential instance name from directory
|
|
if [[ "$dir_name" =~ changemaker\.lite\.(.+)$ ]]; then
|
|
default_instance="${BASH_REMATCH[1]}"
|
|
elif [[ "$dir_name" != "changemaker.lite" ]]; then
|
|
default_instance="$dir_name"
|
|
fi
|
|
|
|
# Send informational messages to stderr so they don't get captured
|
|
echo "" >&2
|
|
echo "=== Instance Configuration ===" >&2
|
|
echo "To run multiple Changemaker instances on the same machine," >&2
|
|
echo "each instance needs a unique identifier for containers and networks." >&2
|
|
echo "" >&2
|
|
|
|
if [ -n "$default_instance" ]; then
|
|
echo "Detected potential instance name from directory: $default_instance" >&2
|
|
read -p "Use this instance identifier? [Y/n]: " use_detected
|
|
if [[ ! "$use_detected" =~ ^[Nn]$ ]]; then
|
|
echo "$default_instance"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
read -p "Enter instance identifier (letters, numbers, hyphens only) [default: main]: " instance_id
|
|
|
|
# Validate and sanitize instance identifier
|
|
if [ -z "$instance_id" ]; then
|
|
instance_id="main"
|
|
fi
|
|
|
|
# Remove invalid characters and convert to lowercase
|
|
instance_id=$(echo "$instance_id" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]//g')
|
|
|
|
if [ -z "$instance_id" ]; then
|
|
instance_id="main"
|
|
fi
|
|
|
|
# Only output the final instance_id to stdout (this gets captured)
|
|
echo "$instance_id"
|
|
}
|
|
|
|
# Function to update docker-compose.yml with unique names
|
|
update_docker_compose_names() {
|
|
local instance_id=$1
|
|
|
|
if [ -z "$instance_id" ] || [ "$instance_id" = "main" ]; then
|
|
echo "Using default container names (no instance suffix)"
|
|
return 0
|
|
fi
|
|
|
|
# Check if docker-compose.yml exists and is not empty
|
|
if [ ! -f "$DOCKER_COMPOSE_FILE" ] || [ ! -s "$DOCKER_COMPOSE_FILE" ]; then
|
|
echo "Error: docker-compose.yml does not exist or is empty at: $DOCKER_COMPOSE_FILE"
|
|
echo "Please ensure docker-compose.yml exists before running this script."
|
|
return 1
|
|
fi
|
|
|
|
echo "Updating docker-compose.yml with instance identifier: $instance_id"
|
|
|
|
# Create a backup of the docker-compose.yml file
|
|
local timestamp=$(date +"%Y%m%d_%H%M%S")
|
|
local backup_file="${DOCKER_COMPOSE_FILE}.backup_${timestamp}"
|
|
cp "$DOCKER_COMPOSE_FILE" "$backup_file"
|
|
echo "Created backup of docker-compose.yml at $backup_file"
|
|
|
|
# Create temporary file for modifications
|
|
local temp_file=$(mktemp)
|
|
|
|
# Verify temp file was created
|
|
if [ ! -f "$temp_file" ]; then
|
|
echo "Error: Could not create temporary file"
|
|
return 1
|
|
fi
|
|
|
|
# Update container names, network names, and volume names
|
|
# Process the file and save to temp file
|
|
sed \
|
|
-e "s/container_name: \([^-]*\)-changemaker$/container_name: \1-changemaker-${instance_id}/g" \
|
|
-e "s/container_name: \([^-]*\)_\([^-]*\)_changemaker$/container_name: \1_\2_changemaker_${instance_id}/g" \
|
|
-e "s/container_name: \([^-]*\)_\([^-]*\)$/container_name: \1_\2_${instance_id}/g" \
|
|
-e "s/container_name: \([^-]*\)$/container_name: \1-${instance_id}/g" \
|
|
-e "s/changemaker-lite:/changemaker-lite-${instance_id}:/g" \
|
|
-e "s/- changemaker-lite$/- changemaker-lite-${instance_id}/g" \
|
|
-e "s/listmonk-data:/listmonk-data-${instance_id}:/g" \
|
|
-e "s/source: listmonk-data$/source: listmonk-data-${instance_id}/g" \
|
|
-e "s/n8n_data:/n8n_data_${instance_id}:/g" \
|
|
-e "s/source: n8n_data$/source: n8n_data_${instance_id}/g" \
|
|
-e "s/nc_data:/nc_data_${instance_id}:/g" \
|
|
-e "s/source: nc_data$/source: nc_data_${instance_id}/g" \
|
|
-e "s/db_data:/db_data_${instance_id}:/g" \
|
|
-e "s/source: db_data$/source: db_data_${instance_id}/g" \
|
|
-e "s/gitea_data:/gitea_data_${instance_id}:/g" \
|
|
-e "s/source: gitea_data$/source: gitea_data_${instance_id}/g" \
|
|
-e "s/mysql_data:/mysql_data_${instance_id}:/g" \
|
|
-e "s/source: mysql_data$/source: mysql_data_${instance_id}/g" \
|
|
-e "s/redis-data:/redis-data-${instance_id}:/g" \
|
|
-e "s/source: redis-data$/source: redis-data-${instance_id}/g" \
|
|
-e "s/prometheus-data:/prometheus-data-${instance_id}:/g" \
|
|
-e "s/source: prometheus-data$/source: prometheus-data-${instance_id}/g" \
|
|
-e "s/grafana-data:/grafana-data-${instance_id}:/g" \
|
|
-e "s/source: grafana-data$/source: grafana-data-${instance_id}/g" \
|
|
"$DOCKER_COMPOSE_FILE" > "$temp_file"
|
|
|
|
# Check if temp file has content
|
|
if [ ! -s "$temp_file" ]; then
|
|
echo "Error: sed operation produced empty file"
|
|
echo "Restoring from backup..."
|
|
cp "$backup_file" "$DOCKER_COMPOSE_FILE"
|
|
rm -f "$temp_file"
|
|
return 1
|
|
fi
|
|
|
|
# Replace the original file only if temp file has content
|
|
mv "$temp_file" "$DOCKER_COMPOSE_FILE"
|
|
|
|
echo "✅ Updated docker-compose.yml with instance-specific names:"
|
|
echo " - Container names: *-${instance_id}"
|
|
echo " - Network name: changemaker-lite-${instance_id}"
|
|
echo " - Volume names: *-${instance_id}"
|
|
|
|
return 0
|
|
}
|
|
|
|
# Function to update .env file with instance identifier
|
|
update_env_instance_config() {
|
|
local instance_id=$1
|
|
|
|
if [ -n "$instance_id" ] && [ "$instance_id" != "main" ]; then
|
|
update_env_var "INSTANCE_ID" "$instance_id"
|
|
update_env_var "COMPOSE_PROJECT_NAME" "changemaker-lite-${instance_id}"
|
|
echo "Updated .env with instance configuration"
|
|
fi
|
|
}
|
|
|
|
# Initialize a new .env file if it doesn't exist
|
|
if [ ! -f "$ENV_FILE" ]; then
|
|
echo "No .env file found. Creating a new one from scratch."
|
|
touch "$ENV_FILE"
|
|
initialize_env_file
|
|
else
|
|
echo "Found existing .env file. Will update values."
|
|
backup_env_file
|
|
|
|
# For existing .env files, also scan ports and suggest alternatives if conflicts exist
|
|
echo ""
|
|
echo "Checking existing port assignments for conflicts..."
|
|
load_env_vars
|
|
check_port_conflicts
|
|
fi
|
|
|
|
# Load existing environment variables
|
|
load_env_vars
|
|
|
|
echo -e "\n\nWelcome to Changemaker Config!\n"
|
|
echo "This script will help you configure your .env file for Changemaker."
|
|
echo "Please provide the following information:"
|
|
|
|
# Get instance identifier and update docker-compose.yml
|
|
echo -e "\n---- Instance Configuration ----"
|
|
instance_identifier=$(get_instance_identifier)
|
|
# Strip any whitespace/newlines from the captured value
|
|
instance_identifier=$(echo "$instance_identifier" | tr -d '\n\r' | xargs)
|
|
|
|
# Only update docker-compose.yml if we have a non-default instance ID
|
|
if [ -n "$instance_identifier" ] && [ "$instance_identifier" != "main" ]; then
|
|
if update_docker_compose_names "$instance_identifier"; then
|
|
echo "✅ Docker Compose configuration updated successfully"
|
|
else
|
|
echo "⚠️ Warning: Failed to update docker-compose.yml"
|
|
echo " Continuing with default configuration..."
|
|
fi
|
|
else
|
|
echo "Using default instance configuration (no modifications to docker-compose.yml)"
|
|
fi
|
|
|
|
update_env_instance_config "$instance_identifier"
|
|
|
|
# Domain configuration
|
|
echo -e "\n---- Domain Configuration ----"
|
|
read -p "Enter your domain name (without protocol, e.g., example.com): " domain_name
|
|
|
|
if [ -z "$domain_name" ]; then
|
|
echo "Domain name cannot be empty. Using default: changeme.org"
|
|
domain_name="changeme.org"
|
|
fi
|
|
|
|
# Local IP configuration for Homepage Local tab
|
|
echo -e "\n---- Local Network Configuration ----"
|
|
echo "For the Homepage dashboard, you can configure the Local tab to use a specific"
|
|
echo "IP address for accessing services on your local network (e.g., Tailscale IP)."
|
|
echo ""
|
|
read -p "Enter local IP address [default: localhost]: " local_ip
|
|
|
|
if [ -z "$local_ip" ]; then
|
|
local_ip="localhost"
|
|
echo "Using default: localhost"
|
|
else
|
|
echo "Using local IP: $local_ip"
|
|
fi
|
|
|
|
echo -e "\nUpdating domain settings in .env file..."
|
|
|
|
# Update main domain settings
|
|
update_env_var "DOMAIN" "$domain_name"
|
|
update_env_var "BASE_DOMAIN" "https://$domain_name"
|
|
update_env_var "HOMEPAGE_VAR_BASE_URL" "https://$domain_name"
|
|
update_env_var "LISTMONK_HOSTNAME" "listmonk.$domain_name"
|
|
update_env_var "N8N_HOST" "n8n.$domain_name"
|
|
update_env_var "CF_DOMAIN" "$domain_name"
|
|
update_env_var "GITEA_DOMAIN" "git.$domain_name"
|
|
update_env_var "GITEA_ROOT_URL" "https://git.$domain_name"
|
|
|
|
# Update cookie and CORS settings
|
|
update_env_var "COOKIE_DOMAIN" ".$domain_name"
|
|
update_env_var "ALLOWED_ORIGINS" "https://map.$domain_name,http://localhost:3000"
|
|
|
|
# Update alert email to use new domain
|
|
update_env_var "ALERT_EMAIL_TO" "admin@$domain_name"
|
|
|
|
echo "Domain settings updated successfully!"
|
|
|
|
# Update the map's .env file
|
|
echo -e "\nUpdating map configuration..."
|
|
update_map_env "$domain_name"
|
|
|
|
# Cloudflare Configuration
|
|
echo -e "\n---- Cloudflare Configuration ----"
|
|
get_cloudflare_credentials
|
|
|
|
read -p "Do you want to configure Cloudflare settings now? [Y/n]: " configure_cf
|
|
|
|
if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then
|
|
# Get Cloudflare API token
|
|
read -p "Enter your Cloudflare API Token: " cf_api_token
|
|
if [ -z "$cf_api_token" ] || [ "$cf_api_token" = "your_cloudflare_api_token" ]; then
|
|
echo "Warning: API token is required for Cloudflare integration"
|
|
cf_api_token="your_cloudflare_api_token"
|
|
fi
|
|
update_env_var "CF_API_TOKEN" "$cf_api_token"
|
|
|
|
# Get Cloudflare Zone ID
|
|
read -p "Enter your Cloudflare Zone ID: " cf_zone_id
|
|
if [ -z "$cf_zone_id" ] || [ "$cf_zone_id" = "your_cloudflare_zone_id" ]; then
|
|
echo "Warning: Zone ID is required for DNS configuration"
|
|
cf_zone_id="your_cloudflare_zone_id"
|
|
fi
|
|
update_env_var "CF_ZONE_ID" "$cf_zone_id"
|
|
|
|
# Get Cloudflare Account ID
|
|
read -p "Enter your Cloudflare Account ID: " cf_account_id
|
|
if [ -z "$cf_account_id" ] || [ "$cf_account_id" = "your_cloudflare_account_id" ]; then
|
|
echo "Warning: Account ID is required for tunnel operations"
|
|
cf_account_id="your_cloudflare_account_id"
|
|
fi
|
|
update_env_var "CF_ACCOUNT_ID" "$cf_account_id"
|
|
|
|
# Note: CF_TUNNEL_ID will be set by start-production.sh when the tunnel is created
|
|
update_env_var "CF_TUNNEL_ID" "will_be_set_by_start_production"
|
|
|
|
echo ""
|
|
echo "Cloudflare configuration saved to .env file."
|
|
echo ""
|
|
echo "To complete the setup and deploy your services:"
|
|
echo "1. Start your services with: docker compose up -d"
|
|
echo "2. Run ./start-production.sh to configure the Cloudflare tunnel"
|
|
echo ""
|
|
else
|
|
echo "Skipping Cloudflare configuration."
|
|
echo "You'll need to configure Cloudflare settings manually before running start-production.sh."
|
|
fi
|
|
|
|
# Update the site_url in mkdocs.yml
|
|
echo -e "\nUpdating site_url in mkdocs.yml..."
|
|
update_mkdocs_yml "$domain_name"
|
|
|
|
# Update service URLs in services.yaml
|
|
echo -e "\nUpdating service URLs in services.yaml..."
|
|
update_services_yaml "$domain_name" "$local_ip"
|
|
|
|
# Update the login URL in main.html
|
|
echo -e "\nUpdating login URL in main.html..."
|
|
update_main_html "$domain_name"
|
|
|
|
# Listmonk Admin Credentials configuration
|
|
echo -e "\n---- Listmonk Admin Credentials ----"
|
|
read -p "Enter Listmonk admin email/username [default: admin@example.com]: " listmonk_user
|
|
read -sp "Enter Listmonk admin password [default: changeMe]: " listmonk_password
|
|
echo # Add new line after password input
|
|
|
|
if [ -z "$listmonk_user" ]; then
|
|
listmonk_user="admin@example.com"
|
|
fi
|
|
|
|
if [ -z "$listmonk_password" ]; then
|
|
listmonk_password="changeMe"
|
|
fi
|
|
|
|
update_env_var "LISTMONK_ADMIN_USER" "$listmonk_user"
|
|
update_env_var "LISTMONK_ADMIN_PASSWORD" "$listmonk_password"
|
|
|
|
echo "Listmonk admin credentials updated."
|
|
|
|
# N8N User Credentials configuration
|
|
echo -e "\n---- N8N Admin Credentials ----"
|
|
read -p "Enter N8N admin email [default: admin@example.com]: " n8n_email
|
|
read -sp "Enter N8N admin password [default: changeMe]: " n8n_password
|
|
echo # Add new line after password input
|
|
|
|
if [ -z "$n8n_email" ]; then
|
|
n8n_email="admin@example.com"
|
|
fi
|
|
|
|
if [ -z "$n8n_password" ]; then
|
|
n8n_password="changeMe"
|
|
fi
|
|
|
|
update_env_var "N8N_USER_EMAIL" "$n8n_email"
|
|
update_env_var "N8N_USER_PASSWORD" "$n8n_password"
|
|
|
|
echo "N8N admin credentials updated."
|
|
|
|
# Generate secure passwords for database and encryption
|
|
echo -e "\n---- Generating Secure Passwords ----"
|
|
echo "Generating secure passwords for database and encryption keys..."
|
|
|
|
# Generate and update database password
|
|
postgres_password=$(generate_password 20)
|
|
update_env_var "POSTGRES_PASSWORD" "$postgres_password"
|
|
|
|
# Generate and update N8N encryption key
|
|
n8n_encryption_key=$(generate_password 32)
|
|
update_env_var "N8N_ENCRYPTION_KEY" "$n8n_encryption_key"
|
|
|
|
# Generate and update NocoDB passwords
|
|
nocodb_jwt_secret=$(generate_password 32)
|
|
update_env_var "NOCODB_JWT_SECRET" "$nocodb_jwt_secret"
|
|
|
|
nocodb_db_password=$(generate_password 20)
|
|
update_env_var "NOCODB_DB_PASSWORD" "$nocodb_db_password"
|
|
|
|
# Generate and update Gitea passwords (these should already exist in the file)
|
|
gitea_db_password=$(generate_password 20)
|
|
update_env_var "GITEA_DB_PASSWD" "$gitea_db_password"
|
|
|
|
gitea_db_root_password=$(generate_password 20)
|
|
update_env_var "GITEA_DB_ROOT_PASSWORD" "$gitea_db_root_password"
|
|
|
|
# Generate and update Grafana admin password
|
|
grafana_admin_password=$(generate_password 20)
|
|
update_env_var "GRAFANA_ADMIN_PASSWORD" "$grafana_admin_password"
|
|
|
|
# Generate and update Gotify admin password
|
|
gotify_admin_password=$(generate_password 20)
|
|
update_env_var "GOTIFY_ADMIN_PASSWORD" "$gotify_admin_password"
|
|
|
|
echo "Secure passwords generated and updated."
|
|
|
|
# Fix container directory permissions before finishing
|
|
fix_container_permissions
|
|
|
|
echo -e "\n✅ Configuration completed successfully!"
|
|
echo "Your .env file has been configured with:"
|
|
echo "- Instance ID: $instance_identifier"
|
|
echo "- Domain: $domain_name"
|
|
echo "- Local IP: $local_ip (for Homepage Local tab)"
|
|
echo "- Cookie Domain: .$domain_name"
|
|
echo "- Allowed Origins: https://map.$domain_name,http://localhost:3000"
|
|
echo "- Map .env updated with domain settings"
|
|
echo "- Listmonk Admin: $listmonk_user"
|
|
echo "- N8N Admin Email: $n8n_email"
|
|
echo "- Secure random passwords for database, encryption, and NocoDB"
|
|
echo "- Grafana Admin Password: Generated (see .env file)"
|
|
echo "- Gotify Admin Password: Generated (see .env file)"
|
|
echo "- Centralized services: Redis, Prometheus, Grafana"
|
|
echo "- Monitoring services: cAdvisor, Node Exporter, Redis Exporter, Alertmanager, Gotify"
|
|
echo "- Email testing: MailHog"
|
|
echo "- Tunnel configuration updated at: $TUNNEL_CONFIG_FILE"
|
|
echo "- Homepage services.yaml configured with Production and Local tabs"
|
|
echo -e "\nYour .env file is located at: $ENV_FILE"
|
|
echo "A backup of your original .env file was created before modifications."
|
|
|
|
echo ""
|
|
echo "======================================"
|
|
echo "Next Steps:"
|
|
echo "======================================"
|
|
echo ""
|
|
if [ -n "$instance_identifier" ] && [ "$instance_identifier" != "main" ]; then
|
|
echo "Instance: $instance_identifier"
|
|
echo ""
|
|
fi
|
|
echo "1. Start services locally:"
|
|
echo " docker compose up -d"
|
|
echo ""
|
|
echo "2. Test all services at:"
|
|
echo " - Homepage: http://localhost:${HOMEPAGE_PORT:-3010}"
|
|
echo " - Code Server: http://localhost:${CODE_SERVER_PORT:-8888}"
|
|
echo " - Listmonk: http://localhost:${LISTMONK_PORT:-9000}"
|
|
echo " - Documentation: http://localhost:${MKDOCS_PORT:-4000}"
|
|
echo " - n8n: http://localhost:${N8N_PORT:-5678}"
|
|
echo " - NocoDB: http://localhost:${NOCODB_PORT:-8090}"
|
|
echo " - Gitea: http://localhost:${GITEA_WEB_PORT:-3030}"
|
|
echo " - Map: http://localhost:${MAP_PORT:-3000}"
|
|
echo " - Influence: http://localhost:${INFLUENCE_PORT:-3333}"
|
|
echo " - Mini QR: http://localhost:${MINI_QR_PORT:-8089}"
|
|
echo ""
|
|
echo " Centralized Services:"
|
|
echo " - Redis: http://localhost:${REDIS_PORT:-6379}"
|
|
echo ""
|
|
echo " Email Testing:"
|
|
echo " - MailHog Web UI: http://localhost:${MAILHOG_WEB_PORT:-8025}"
|
|
echo " - MailHog SMTP: localhost:${MAILHOG_SMTP_PORT:-1025}"
|
|
echo ""
|
|
echo " Monitoring Services (optional monitoring profile):"
|
|
echo " - Prometheus: http://localhost:${PROMETHEUS_PORT:-9090}"
|
|
echo " - Grafana: http://localhost:${GRAFANA_PORT:-3001}"
|
|
echo " - Alertmanager: http://localhost:${ALERTMANAGER_PORT:-9093}"
|
|
echo " - Gotify: http://localhost:${GOTIFY_PORT:-8889}"
|
|
echo " - cAdvisor: http://localhost:${CADVISOR_PORT:-8080}"
|
|
echo " - Node Exporter: http://localhost:${NODE_EXPORTER_PORT:-9100}/metrics"
|
|
echo " - Redis Exporter: http://localhost:${REDIS_EXPORTER_PORT:-9121}/metrics"
|
|
echo ""
|
|
echo " To start with monitoring:"
|
|
echo " docker compose --profile monitoring up -d"
|
|
echo ""
|
|
echo " Monitoring Credentials:"
|
|
echo " - Grafana: admin / (check .env: GRAFANA_ADMIN_PASSWORD)"
|
|
echo " - Gotify: admin / (check .env: GOTIFY_ADMIN_PASSWORD)"
|
|
echo ""
|
|
echo "3. When ready for production:"
|
|
echo " ./start-production.sh"
|
|
echo ""
|
|
echo "======================================" |