#!/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/docs/mkdocs.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 local escaped_value=$(echo "$value" | sed 's/[\/&]/\\&/g') if grep -q "^$key=" "$ENV_FILE"; then sed -i "s/^$key=.*/$key=$escaped_value/" "$ENV_FILE" echo "Updated $key in .env file" else echo "$key=$escaped_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 initialize the .env file with default values initialize_env_file() { echo "Initializing new .env file with default values..." 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 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 SILEX_PORT=6805 # Domain Configuration BASE_DOMAIN=https://changeme.org DOMAIN=changeme.org LISTMONK_HOSTNAME=listmonk.changeme.org N8N_HOST=n8n.changeme.org SILEX_HOST=silex.changeme.org # 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 # Database Configuration (PostgreSQL for Listmonk) POSTGRES_USER=listmonk POSTGRES_PASSWORD=changeMe POSTGRES_DB=listmonk # 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_PORT=8090 NOCODB_JWT_SECRET=changeMe NOCODB_DB_NAME=nocodb NOCODB_DB_USER=noco NOCODB_DB_PASSWORD=changeMe # Listmonk SMTP Configuration LISTMONK_SMTP_HOST=smtp.example.com LISTMONK_SMTP_PORT=587 LISTMONK_SMTP_AUTH_PROTOCOL=plain LISTMONK_SMTP_USERNAME=your-smtp-username LISTMONK_SMTP_PASSWORD=your-smtp-password LISTMONK_SMTP_HELLO_HOSTNAME=listmonk.changeme.org LISTMONK_SMTP_TLS_ENABLED=true LISTMONK_SMTP_TLS_SKIP_VERIFY=false LISTMONK_SMTP_MAX_CONNS=10 LISTMONK_SMTP_MAX_MSG_RETRIES=2 LISTMONK_SMTP_IDLE_TIMEOUT=10s LISTMONK_SMTP_WAIT_TIMEOUT=5s LISTMONK_SMTP_EMAIL_HEADERS=List-Unsubscribe-Post=List-Unsubscribe=One-Click EOL echo "New .env file created with default values." } # 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 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 check if a port is in use check_port() { local port=$1 if command -v ss >/dev/null 2>&1; then ss -tuln | grep -q ":$port " elif command -v netstat >/dev/null 2>&1; then netstat -tuln | grep -q ":$port " else # Fallback to lsof if available if command -v lsof >/dev/null 2>&1; then lsof -i ":$port" >/dev/null 2>&1 else echo "Warning: Cannot check port availability. Please ensure ports are free manually." return 1 fi fi } # Function to check all service ports for conflicts check_port_conflicts() { echo "Checking for port conflicts..." local ports_to_check=( "${CODE_SERVER_PORT:-8888}:Code Server" "${LISTMONK_PORT:-9000}:Listmonk" "${LISTMONK_DB_PORT:-5432}:Listmonk Database" "${MKDOCS_PORT:-4000}:MkDocs" "${MKDOCS_SITE_SERVER_PORT:-4001}:MkDocs Site Server" "${N8N_PORT:-5678}:N8N" "${NOCODB_PORT:-8090}:NocoDB" "${HOMEPAGE_PORT:-3010}:Homepage" "${SILEX_PORT:-6805}:Silex" ) local conflicts_found=false for port_info in "${ports_to_check[@]}"; do local port=$(echo "$port_info" | cut -d: -f1) local service=$(echo "$port_info" | cut -d: -f2) if check_port "$port"; then echo "⚠️ Port conflict detected: $port is already in use (assigned to $service)" conflicts_found=true else echo "✅ Port $port is available for $service" fi done if [ "$conflicts_found" = true ]; then echo "" echo "Port conflicts detected! Please choose alternative ports or stop conflicting services." read -p "Do you want to configure alternative ports? [Y/n]: " configure_ports if [[ "$configure_ports" =~ ^[Nn]$ ]]; then echo "Configuration cancelled. Please resolve port conflicts and try again." exit 1 else configure_alternative_ports fi else echo "✅ All ports are available!" fi } # Function to configure alternative ports configure_alternative_ports() { echo "" echo "---- Port Configuration ----" # Code Server if check_port "${CODE_SERVER_PORT:-8888}"; then read -p "Enter alternative port for Code Server [current: ${CODE_SERVER_PORT:-8888}]: " new_code_port if [ ! -z "$new_code_port" ]; then update_env_var "CODE_SERVER_PORT" "$new_code_port" fi fi # Listmonk if check_port "${LISTMONK_PORT:-9000}"; then read -p "Enter alternative port for Listmonk [current: ${LISTMONK_PORT:-9000}]: " new_listmonk_port if [ ! -z "$new_listmonk_port" ]; then update_env_var "LISTMONK_PORT" "$new_listmonk_port" fi fi # Listmonk DB if check_port "${LISTMONK_DB_PORT:-5432}"; then read -p "Enter alternative port for Listmonk Database [current: ${LISTMONK_DB_PORT:-5432}]: " new_db_port if [ ! -z "$new_db_port" ]; then update_env_var "LISTMONK_DB_PORT" "$new_db_port" fi fi # MkDocs if check_port "${MKDOCS_PORT:-4000}"; then read -p "Enter alternative port for MkDocs [current: ${MKDOCS_PORT:-4000}]: " new_mkdocs_port if [ ! -z "$new_mkdocs_port" ]; then update_env_var "MKDOCS_PORT" "$new_mkdocs_port" fi fi # MkDocs Site Server if check_port "${MKDOCS_SITE_SERVER_PORT:-4001}"; then read -p "Enter alternative port for MkDocs Site Server [current: ${MKDOCS_SITE_SERVER_PORT:-4001}]: " new_site_port if [ ! -z "$new_site_port" ]; then update_env_var "MKDOCS_SITE_SERVER_PORT" "$new_site_port" fi fi # N8N if check_port "${N8N_PORT:-5678}"; then read -p "Enter alternative port for N8N [current: ${N8N_PORT:-5678}]: " new_n8n_port if [ ! -z "$new_n8n_port" ]; then update_env_var "N8N_PORT" "$new_n8n_port" fi fi # NocoDB if check_port "${NOCODB_PORT:-8090}"; then read -p "Enter alternative port for NocoDB [current: ${NOCODB_PORT:-8090}]: " new_nocodb_port if [ ! -z "$new_nocodb_port" ]; then update_env_var "NOCODB_PORT" "$new_nocodb_port" fi fi # Homepage if check_port "${HOMEPAGE_PORT:-3010}"; then read -p "Enter alternative port for Homepage [current: ${HOMEPAGE_PORT:-3010}]: " new_homepage_port if [ ! -z "$new_homepage_port" ]; then update_env_var "HOMEPAGE_PORT" "$new_homepage_port" fi fi # Silex if check_port "${SILEX_PORT:-6805}"; then read -p "Enter alternative port for Silex [current: ${SILEX_PORT:-6805}]: " new_silex_port if [ ! -z "$new_silex_port" ]; then update_env_var "SILEX_PORT" "$new_silex_port" fi fi echo "Port configuration completed." } # 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 fi 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:" # 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 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 "LISTMONK_HOSTNAME" "listmonk.$domain_name" update_env_var "N8N_HOST" "n8n.$domain_name" update_env_var "SILEX_HOST" "silex.$domain_name" update_env_var "CF_DOMAIN" "$domain_name" echo "Domain settings updated successfully!" # Cloudflare Configuration echo -e "\n---- Cloudflare Configuration ----" echo "To use the DNS setup script, you'll need Cloudflare credentials." echo "You can find these values in your Cloudflare dashboard:" echo " - API Token: https://dash.cloudflare.com/profile/api-tokens" echo " (Create a token with Zone:DNS:Edit and Access:Apps:Edit permissions)" echo " - Zone ID: On your domain's overview page" echo " - Tunnel ID: In the Zero Trust dashboard under Access > Tunnels" echo "" read -p "Do you want to configure Cloudflare settings now? [Y/n]: " configure_cf if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then echo "" echo "Please enter your Cloudflare credentials:" # CF API Token read -p "Enter your Cloudflare API Token: " cf_api_token if [ ! -z "$cf_api_token" ]; then # Basic validation for API token format if [[ "$cf_api_token" =~ ^[A-Za-z0-9_-]{40}$ ]]; then update_env_var "CF_API_TOKEN" "$cf_api_token" echo "✅ Cloudflare API Token updated" else echo "⚠️ Warning: API Token format seems incorrect (should be 40 characters)" update_env_var "CF_API_TOKEN" "$cf_api_token" fi else echo "⚠️ Cloudflare API Token left unchanged" fi # CF Zone ID read -p "Enter your Cloudflare Zone ID: " cf_zone_id if [ ! -z "$cf_zone_id" ]; then # Basic validation for Zone ID format if [[ "$cf_zone_id" =~ ^[a-f0-9]{32}$ ]]; then update_env_var "CF_ZONE_ID" "$cf_zone_id" echo "✅ Cloudflare Zone ID updated" else echo "⚠️ Warning: Zone ID format seems incorrect (should be 32 hex characters)" update_env_var "CF_ZONE_ID" "$cf_zone_id" fi else echo "⚠️ Cloudflare Zone ID left unchanged" fi # CF Tunnel ID read -p "Enter your Cloudflare Tunnel ID: " cf_tunnel_id if [ ! -z "$cf_tunnel_id" ]; then # Basic validation for Tunnel ID format (UUID) if [[ "$cf_tunnel_id" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ ]]; then update_env_var "CF_TUNNEL_ID" "$cf_tunnel_id" echo "✅ Cloudflare Tunnel ID updated" else echo "⚠️ Warning: Tunnel ID format seems incorrect (should be UUID format)" update_env_var "CF_TUNNEL_ID" "$cf_tunnel_id" fi else echo "⚠️ Cloudflare Tunnel ID left unchanged" fi echo "" echo "Cloudflare configuration completed!" echo "You can now run './add-cname-records.sh' to set up DNS records." else echo "Skipping Cloudflare configuration. You can run this script again later to configure it." fi # Update the site_url in mkdocs.yml echo -e "\nUpdating site_url in mkdocs.yml..." update_mkdocs_yml "$domain_name" # Check for port conflicts echo -e "\n---- Checking Port Availability ----" check_port_conflicts # Listmonk Admin Credentials configuration echo -e "\n---- Listmonk Admin Credentials ----" read -p "Enter Listmonk admin username [default: admin]: " listmonk_user read -sp "Enter Listmonk admin password [default: strongpassword]: " listmonk_password echo # Add new line after password input if [ -z "$listmonk_user" ]; then listmonk_user="admin" fi if [ -z "$listmonk_password" ]; then listmonk_password="strongpassword" 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." # SMTP Configuration echo -e "\n---- SMTP Configuration ----" echo "Configure SMTP settings for sending emails through Listmonk." read -p "Do you want to configure SMTP settings now? [Y/n]: " configure_smtp if [[ ! "$configure_smtp" =~ ^[Nn]$ ]]; then echo "" echo "Please enter your SMTP server details:" read -p "SMTP Host (e.g., smtp.gmail.com, smtp.sendgrid.net): " smtp_host read -p "SMTP Port [default: 587]: " smtp_port read -p "SMTP Username/Email: " smtp_username read -sp "SMTP Password: " smtp_password echo read -p "Hello Hostname [default: ${LISTMONK_HOSTNAME:-listmonk.changeme.org}]: " smtp_hello read -p "Enable TLS? [Y/n]: " smtp_tls # Set defaults if [ -z "$smtp_port" ]; then smtp_port="587" fi if [ -z "$smtp_hello" ]; then smtp_hello="${LISTMONK_HOSTNAME:-listmonk.changeme.org}" fi if [[ "$smtp_tls" =~ ^[Nn]$ ]]; then smtp_tls_enabled="false" else smtp_tls_enabled="true" fi # Update SMTP settings in .env if [ ! -z "$smtp_host" ]; then update_env_var "LISTMONK_SMTP_HOST" "$smtp_host" fi update_env_var "LISTMONK_SMTP_PORT" "$smtp_port" if [ ! -z "$smtp_username" ]; then update_env_var "LISTMONK_SMTP_USERNAME" "$smtp_username" fi if [ ! -z "$smtp_password" ]; then update_env_var "LISTMONK_SMTP_PASSWORD" "$smtp_password" fi update_env_var "LISTMONK_SMTP_HELLO_HOSTNAME" "$smtp_hello" update_env_var "LISTMONK_SMTP_TLS_ENABLED" "$smtp_tls_enabled" update_env_var "LISTMONK_SMTP_AUTH_PROTOCOL" "plain" update_env_var "LISTMONK_SMTP_TLS_SKIP_VERIFY" "false" update_env_var "LISTMONK_SMTP_MAX_CONNS" "10" update_env_var "LISTMONK_SMTP_MAX_MSG_RETRIES" "2" update_env_var "LISTMONK_SMTP_IDLE_TIMEOUT" "10s" update_env_var "LISTMONK_SMTP_WAIT_TIMEOUT" "5s" echo "✅ SMTP configuration completed!" else echo "Skipping SMTP configuration. You can configure this later in the Listmonk admin interface." fi # 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" echo "Secure passwords generated and updated." echo -e "\n✅ Configuration completed successfully!" echo "Your .env file has been configured with:" echo "- Domain: $domain_name" echo "- Listmonk Admin: $listmonk_user" echo "- N8N Admin Email: $n8n_email" echo "- Secure random passwords for database, encryption, and NocoDB" if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then echo "- Cloudflare credentials for DNS management" fi echo -e "\nYour .env file is located at: $ENV_FILE" echo "A backup of your original .env file was created before modifications." echo -e "\nNext steps:" echo "1. Run 'docker-compose up -d' to start your services" if [[ ! "$configure_cf" =~ ^[Nn]$ ]]; then echo "2. Run './add-cname-records.sh' to set up DNS records and access policies" fi