mirror of
https://github.com/kossakovsky/n8n-install.git
synced 2026-03-07 14:23:08 +00:00
adds caddy-addon mechanism for custom certificates when let's encrypt is not available. includes setup script with interactive wizard, example configs, and documentation.
352 lines
11 KiB
Bash
Executable File
352 lines
11 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# =============================================================================
|
|
# setup_custom_tls.sh - Configure custom TLS certificates for Caddy
|
|
# =============================================================================
|
|
# Generates caddy-addon/custom-tls.conf for using corporate/internal certificates
|
|
# instead of Let's Encrypt.
|
|
#
|
|
# Usage:
|
|
# bash scripts/setup_custom_tls.sh # Interactive mode
|
|
# bash scripts/setup_custom_tls.sh cert.crt key.key # Non-interactive mode
|
|
#
|
|
# Prerequisites:
|
|
# - Place certificate files in ./certs/ directory
|
|
# - Certificate paths are relative to container (/etc/caddy/certs/)
|
|
# =============================================================================
|
|
|
|
set -euo pipefail
|
|
|
|
source "$(dirname "$0")/utils.sh" && init_paths
|
|
|
|
ADDON_FILE="$PROJECT_ROOT/caddy-addon/custom-tls.conf"
|
|
CERTS_DIR="$PROJECT_ROOT/certs"
|
|
|
|
# =============================================================================
|
|
# FUNCTIONS
|
|
# =============================================================================
|
|
|
|
show_help() {
|
|
cat << EOF
|
|
Setup Custom TLS Certificates for Caddy
|
|
|
|
Usage: $(basename "$0") [OPTIONS] [CERT_FILE] [KEY_FILE]
|
|
|
|
Options:
|
|
-h, --help Show this help message
|
|
--remove Remove custom TLS configuration
|
|
|
|
Arguments:
|
|
CERT_FILE Path to certificate file (relative to ./certs/)
|
|
KEY_FILE Path to private key file (relative to ./certs/)
|
|
|
|
Examples:
|
|
$(basename "$0") # Interactive mode
|
|
$(basename "$0") wildcard.crt wildcard.key # Use specific files
|
|
$(basename "$0") --remove # Remove custom TLS config
|
|
|
|
The script will:
|
|
1. Detect certificate files in ./certs/
|
|
2. Read active services from .env
|
|
3. Generate caddy-addon/custom-tls.conf
|
|
4. Optionally restart Caddy
|
|
|
|
EOF
|
|
}
|
|
|
|
find_certificates() {
|
|
# Find certificate files in certs directory
|
|
local certs=()
|
|
if [[ -d "$CERTS_DIR" ]]; then
|
|
while IFS= read -r -d '' file; do
|
|
certs+=("$(basename "$file")")
|
|
done < <(find "$CERTS_DIR" -maxdepth 1 -type f \( -name "*.crt" -o -name "*.pem" -o -name "*.cer" \) -print0 2>/dev/null)
|
|
fi
|
|
echo "${certs[*]:-}"
|
|
}
|
|
|
|
find_keys() {
|
|
# Find key files in certs directory
|
|
local keys=()
|
|
if [[ -d "$CERTS_DIR" ]]; then
|
|
while IFS= read -r -d '' file; do
|
|
keys+=("$(basename "$file")")
|
|
done < <(find "$CERTS_DIR" -maxdepth 1 -type f \( -name "*.key" -o -name "*-key.pem" \) -print0 2>/dev/null)
|
|
fi
|
|
echo "${keys[*]:-}"
|
|
}
|
|
|
|
get_active_services() {
|
|
# Get list of services with their hostnames from .env
|
|
load_env
|
|
local services=()
|
|
|
|
# Map of service names to their hostname variables
|
|
declare -A service_map=(
|
|
["n8n"]="N8N_HOSTNAME"
|
|
["flowise"]="FLOWISE_HOSTNAME"
|
|
["webui"]="WEBUI_HOSTNAME"
|
|
["grafana"]="GRAFANA_HOSTNAME"
|
|
["prometheus"]="PROMETHEUS_HOSTNAME"
|
|
["portainer"]="PORTAINER_HOSTNAME"
|
|
["langfuse"]="LANGFUSE_HOSTNAME"
|
|
["supabase"]="SUPABASE_HOSTNAME"
|
|
["dify"]="DIFY_HOSTNAME"
|
|
["nocodb"]="NOCODB_HOSTNAME"
|
|
["ragapp"]="RAGAPP_HOSTNAME"
|
|
["ragflow"]="RAGFLOW_HOSTNAME"
|
|
["waha"]="WAHA_HOSTNAME"
|
|
["searxng"]="SEARXNG_HOSTNAME"
|
|
["comfyui"]="COMFYUI_HOSTNAME"
|
|
["welcome"]="WELCOME_HOSTNAME"
|
|
["databasus"]="DATABASUS_HOSTNAME"
|
|
["letta"]="LETTA_HOSTNAME"
|
|
["lightrag"]="LIGHTRAG_HOSTNAME"
|
|
["weaviate"]="WEAVIATE_HOSTNAME"
|
|
["qdrant"]="QDRANT_HOSTNAME"
|
|
["neo4j"]="NEO4J_HOSTNAME"
|
|
["postiz"]="POSTIZ_HOSTNAME"
|
|
["libretranslate"]="LT_HOSTNAME"
|
|
["paddleocr"]="PADDLEOCR_HOSTNAME"
|
|
["docling"]="DOCLING_HOSTNAME"
|
|
)
|
|
|
|
for service in "${!service_map[@]}"; do
|
|
local hostname_var="${service_map[$service]}"
|
|
local hostname="${!hostname_var:-}"
|
|
if [[ -n "$hostname" && "$hostname" != *"yourdomain.com" ]]; then
|
|
services+=("$service:$hostname")
|
|
fi
|
|
done
|
|
|
|
echo "${services[*]:-}"
|
|
}
|
|
|
|
generate_config() {
|
|
local cert_file="$1"
|
|
local key_file="$2"
|
|
local services=("${@:3}")
|
|
|
|
cat > "$ADDON_FILE" << 'HEADER'
|
|
# Custom TLS Configuration
|
|
# Generated by setup_custom_tls.sh
|
|
#
|
|
# This file overrides default Let's Encrypt certificates with custom ones.
|
|
# Regenerate with: make setup-tls
|
|
|
|
# Reusable TLS snippet
|
|
(custom_tls) {
|
|
HEADER
|
|
|
|
echo " tls /etc/caddy/certs/$cert_file /etc/caddy/certs/$key_file" >> "$ADDON_FILE"
|
|
echo "}" >> "$ADDON_FILE"
|
|
echo "" >> "$ADDON_FILE"
|
|
|
|
# Service-specific reverse proxy mappings
|
|
declare -A proxy_map=(
|
|
["n8n"]="n8n:5678"
|
|
["flowise"]="flowise:3001"
|
|
["webui"]="open-webui:8080"
|
|
["grafana"]="grafana:3000"
|
|
["prometheus"]="prometheus:9090"
|
|
["portainer"]="portainer:9000"
|
|
["langfuse"]="langfuse-web:3000"
|
|
["supabase"]="kong:8000"
|
|
["dify"]="nginx:80"
|
|
["nocodb"]="nocodb:8080"
|
|
["ragapp"]="ragapp:8000"
|
|
["ragflow"]="ragflow:80"
|
|
["waha"]="waha:3000"
|
|
["searxng"]="searxng:8080"
|
|
["comfyui"]="comfyui:8188"
|
|
["welcome"]="file_server"
|
|
["databasus"]="databasus:4005"
|
|
["letta"]="letta:8283"
|
|
["lightrag"]="lightrag:9621"
|
|
["weaviate"]="weaviate:8080"
|
|
["qdrant"]="qdrant:6333"
|
|
["neo4j"]="neo4j:7474"
|
|
["postiz"]="postiz:5000"
|
|
["libretranslate"]="libretranslate:5000"
|
|
["paddleocr"]="paddleocr:8080"
|
|
["docling"]="docling:5001"
|
|
)
|
|
|
|
# Services that need basic auth (format: USERNAME_VAR:PASSWORD_HASH_VAR)
|
|
declare -A auth_services=(
|
|
["prometheus"]="PROMETHEUS_USERNAME:PROMETHEUS_PASSWORD_HASH"
|
|
["ragapp"]="RAGAPP_USERNAME:RAGAPP_PASSWORD_HASH"
|
|
["comfyui"]="COMFYUI_USERNAME:COMFYUI_PASSWORD_HASH"
|
|
["welcome"]="WELCOME_USERNAME:WELCOME_PASSWORD_HASH"
|
|
["libretranslate"]="LT_USERNAME:LT_PASSWORD_HASH"
|
|
["paddleocr"]="PADDLEOCR_USERNAME:PADDLEOCR_PASSWORD_HASH"
|
|
["docling"]="DOCLING_USERNAME:DOCLING_PASSWORD_HASH"
|
|
)
|
|
|
|
for service_entry in "${services[@]}"; do
|
|
local service="${service_entry%%:*}"
|
|
local hostname="${service_entry#*:}"
|
|
local proxy="${proxy_map[$service]:-}"
|
|
|
|
[[ -z "$proxy" ]] && continue
|
|
|
|
echo "# $service" >> "$ADDON_FILE"
|
|
echo "$hostname {" >> "$ADDON_FILE"
|
|
echo " import custom_tls" >> "$ADDON_FILE"
|
|
|
|
# Add basic auth if needed
|
|
if [[ -n "${auth_services[$service]:-}" ]]; then
|
|
local auth_config="${auth_services[$service]}"
|
|
local username_var="${auth_config%%:*}"
|
|
local password_hash_var="${auth_config#*:}"
|
|
echo " basic_auth {" >> "$ADDON_FILE"
|
|
echo " {\$${username_var}} {\$${password_hash_var}}" >> "$ADDON_FILE"
|
|
echo " }" >> "$ADDON_FILE"
|
|
fi
|
|
|
|
# Add reverse proxy or file server
|
|
if [[ "$proxy" == "file_server" ]]; then
|
|
echo " root * /srv/welcome" >> "$ADDON_FILE"
|
|
echo " file_server" >> "$ADDON_FILE"
|
|
echo " try_files {path} /index.html" >> "$ADDON_FILE"
|
|
else
|
|
echo " reverse_proxy $proxy" >> "$ADDON_FILE"
|
|
fi
|
|
|
|
echo "}" >> "$ADDON_FILE"
|
|
echo "" >> "$ADDON_FILE"
|
|
done
|
|
|
|
log_success "Generated $ADDON_FILE"
|
|
}
|
|
|
|
remove_config() {
|
|
if [[ -f "$ADDON_FILE" ]]; then
|
|
rm -f "$ADDON_FILE"
|
|
log_success "Removed custom TLS configuration"
|
|
else
|
|
log_info "No custom TLS configuration found"
|
|
fi
|
|
}
|
|
|
|
restart_caddy() {
|
|
if wt_yesno "Restart Caddy" "Do you want to restart Caddy to apply the new configuration?" "yes"; then
|
|
log_info "Restarting Caddy..."
|
|
docker compose -p localai restart caddy
|
|
log_success "Caddy restarted"
|
|
else
|
|
log_info "Skipped Caddy restart. Run manually: docker compose -p localai restart caddy"
|
|
fi
|
|
}
|
|
|
|
# =============================================================================
|
|
# MAIN
|
|
# =============================================================================
|
|
|
|
main() {
|
|
# Handle arguments
|
|
case "${1:-}" in
|
|
-h|--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
--remove)
|
|
remove_config
|
|
restart_caddy
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
# Ensure certs directory exists
|
|
mkdir -p "$CERTS_DIR"
|
|
|
|
local cert_file=""
|
|
local key_file=""
|
|
|
|
# Non-interactive mode
|
|
if [[ $# -ge 2 ]]; then
|
|
cert_file="$1"
|
|
key_file="$2"
|
|
|
|
if [[ ! -f "$CERTS_DIR/$cert_file" ]]; then
|
|
log_error "Certificate not found: $CERTS_DIR/$cert_file"
|
|
exit 1
|
|
fi
|
|
if [[ ! -f "$CERTS_DIR/$key_file" ]]; then
|
|
log_error "Key not found: $CERTS_DIR/$key_file"
|
|
exit 1
|
|
fi
|
|
else
|
|
# Interactive mode
|
|
require_whiptail
|
|
|
|
# Find available certificates
|
|
local certs_arr
|
|
IFS=' ' read -ra certs_arr <<< "$(find_certificates)"
|
|
|
|
if [[ ${#certs_arr[@]} -eq 0 ]]; then
|
|
wt_msg "No Certificates Found" "No certificate files found in ./certs/\n\nPlease place your certificate (.crt, .pem, .cer) and key (.key) files in the certs/ directory first."
|
|
exit 1
|
|
fi
|
|
|
|
# Build menu items for certificates
|
|
local cert_items=()
|
|
for cert in "${certs_arr[@]}"; do
|
|
cert_items+=("$cert" "")
|
|
done
|
|
|
|
cert_file=$(wt_menu "Select Certificate" "Choose your TLS certificate file:" "${cert_items[@]}")
|
|
[[ -z "$cert_file" ]] && exit 1
|
|
|
|
# Find available keys
|
|
local keys_arr
|
|
IFS=' ' read -ra keys_arr <<< "$(find_keys)"
|
|
|
|
if [[ ${#keys_arr[@]} -eq 0 ]]; then
|
|
wt_msg "No Keys Found" "No key files found in ./certs/\n\nPlease place your private key (.key) file in the certs/ directory."
|
|
exit 1
|
|
fi
|
|
|
|
# Build menu items for keys
|
|
local key_items=()
|
|
for key in "${keys_arr[@]}"; do
|
|
key_items+=("$key" "")
|
|
done
|
|
|
|
key_file=$(wt_menu "Select Private Key" "Choose your TLS private key file:" "${key_items[@]}")
|
|
[[ -z "$key_file" ]] && exit 1
|
|
fi
|
|
|
|
log_info "Using certificate: $cert_file"
|
|
log_info "Using key: $key_file"
|
|
|
|
# Get active services
|
|
local services_arr
|
|
IFS=' ' read -ra services_arr <<< "$(get_active_services)"
|
|
|
|
if [[ ${#services_arr[@]} -eq 0 ]]; then
|
|
log_warning "No services with configured hostnames found in .env"
|
|
log_info "Make sure to update *_HOSTNAME variables in .env with your domain"
|
|
exit 1
|
|
fi
|
|
|
|
log_info "Found ${#services_arr[@]} services with configured hostnames"
|
|
|
|
# Generate configuration
|
|
generate_config "$cert_file" "$key_file" "${services_arr[@]}"
|
|
|
|
# Show summary
|
|
echo ""
|
|
log_info "Configuration generated for the following services:"
|
|
for service_entry in "${services_arr[@]}"; do
|
|
local service="${service_entry%%:*}"
|
|
local hostname="${service_entry#*:}"
|
|
echo " - $service: $hostname"
|
|
done
|
|
echo ""
|
|
|
|
# Restart Caddy
|
|
restart_caddy
|
|
}
|
|
|
|
main "$@"
|