diff --git a/CHANGELOG.md b/CHANGELOG.md index d2f898a..69da850 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## [Unreleased] +## [1.2.2] - 2026-01-24 + +### Fixed +- **Custom TLS** - Fix duplicate hostname error when using custom certificates. Changed architecture from generating separate site blocks to using a shared TLS snippet that all services import. + ## [1.2.1] - 2026-01-16 ### Added diff --git a/Caddyfile b/Caddyfile index 5b81dc4..dd9173c 100644 --- a/Caddyfile +++ b/Caddyfile @@ -3,30 +3,38 @@ email {$LETSENCRYPT_EMAIL} } +# Import TLS snippet (must be before service blocks) +# Default: Let's Encrypt automatic certificates +# Custom: Run 'make setup-tls' to use your own certificates +import /etc/caddy/addons/tls-snippet.conf + # N8N {$N8N_HOSTNAME} { - # For domains, Caddy will automatically use Let's Encrypt - # For localhost/port addresses, HTTPS won't be enabled + import service_tls reverse_proxy n8n:5678 } # Open WebUI {$WEBUI_HOSTNAME} { + import service_tls reverse_proxy open-webui:8080 } # Flowise {$FLOWISE_HOSTNAME} { + import service_tls reverse_proxy flowise:3001 } # Dify {$DIFY_HOSTNAME} { + import service_tls reverse_proxy nginx:80 } # RAGApp {$RAGAPP_HOSTNAME} { + import service_tls basic_auth { {$RAGAPP_USERNAME} {$RAGAPP_PASSWORD_HASH} } @@ -35,37 +43,38 @@ # RAGFlow {$RAGFLOW_HOSTNAME} { + import service_tls reverse_proxy ragflow:80 } # Langfuse {$LANGFUSE_HOSTNAME} { + import service_tls reverse_proxy langfuse-web:3000 } -# # Ollama API -# {$OLLAMA_HOSTNAME} { -# reverse_proxy ollama:11434 -# } - # Supabase {$SUPABASE_HOSTNAME} { + import service_tls reverse_proxy kong:8000 } # Grafana {$GRAFANA_HOSTNAME} { + import service_tls reverse_proxy grafana:3000 } # WAHA (WhatsApp HTTP API) {$WAHA_HOSTNAME} { + import service_tls reverse_proxy waha:3000 } # Prometheus {$PROMETHEUS_HOSTNAME} { - basic_auth { + import service_tls + basic_auth { {$PROMETHEUS_USERNAME} {$PROMETHEUS_PASSWORD_HASH} } reverse_proxy prometheus:9090 @@ -73,16 +82,19 @@ # Portainer {$PORTAINER_HOSTNAME} { + import service_tls reverse_proxy portainer:9000 } # Postiz {$POSTIZ_HOSTNAME} { + import service_tls reverse_proxy postiz:5000 } # Temporal UI (workflow orchestration for Postiz) {$TEMPORAL_UI_HOSTNAME} { + import service_tls basic_auth { {$TEMPORAL_UI_USERNAME} {$TEMPORAL_UI_PASSWORD_HASH} } @@ -91,31 +103,37 @@ # Databasus {$DATABASUS_HOSTNAME} { + import service_tls reverse_proxy databasus:4005 } # Letta {$LETTA_HOSTNAME} { + import service_tls reverse_proxy letta:8283 } # LightRAG (Graph-based RAG with Knowledge Extraction) {$LIGHTRAG_HOSTNAME} { + import service_tls reverse_proxy lightrag:9621 } # Weaviate {$WEAVIATE_HOSTNAME} { + import service_tls reverse_proxy weaviate:8080 } # Qdrant {$QDRANT_HOSTNAME} { + import service_tls reverse_proxy qdrant:6333 } # ComfyUI {$COMFYUI_HOSTNAME} { + import service_tls basic_auth { {$COMFYUI_USERNAME} {$COMFYUI_PASSWORD_HASH} } @@ -124,6 +142,7 @@ # LibreTranslate (Self-hosted Translation API) {$LT_HOSTNAME} { + import service_tls basic_auth { {$LT_USERNAME} {$LT_PASSWORD_HASH} } @@ -132,21 +151,25 @@ # Neo4j {$NEO4J_HOSTNAME} { + import service_tls reverse_proxy neo4j:7474 } # Neo4j Bolt Protocol (wss) https://{$NEO4J_HOSTNAME}:7687 { + import service_tls reverse_proxy neo4j:7687 } # NocoDB {$NOCODB_HOSTNAME} { + import service_tls reverse_proxy nocodb:8080 } # PaddleOCR (PaddleX Basic Serving) {$PADDLEOCR_HOSTNAME} { + import service_tls basic_auth { {$PADDLEOCR_USERNAME} {$PADDLEOCR_PASSWORD_HASH} } @@ -155,6 +178,7 @@ https://{$NEO4J_HOSTNAME}:7687 { # Docling (Document Conversion API) {$DOCLING_HOSTNAME} { + import service_tls basic_auth { {$DOCLING_USERNAME} {$DOCLING_PASSWORD_HASH} } @@ -174,6 +198,7 @@ http://{$WELCOME_HOSTNAME} { # HTTPS block for direct access {$WELCOME_HOSTNAME} { + import service_tls basic_auth { {$WELCOME_USERNAME} {$WELCOME_PASSWORD_HASH} } @@ -184,8 +209,9 @@ http://{$WELCOME_HOSTNAME} { import /etc/caddy/addons/*.conf -# # SearXNG +# SearXNG {$SEARXNG_HOSTNAME} { + import service_tls @protected not remote_ip 127.0.0.0/8 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 100.64.0.0/10 basic_auth @protected { diff --git a/caddy-addon/README.md b/caddy-addon/README.md index ab0e317..a8df302 100644 --- a/caddy-addon/README.md +++ b/caddy-addon/README.md @@ -15,6 +15,23 @@ All `.conf` files in this directory are automatically imported via `import /etc/ For corporate/internal deployments where Let's Encrypt is not available, you can use your own certificates. +### How It Works + +The main `Caddyfile` imports a TLS snippet that all service blocks use: + +```caddy +# In Caddyfile (top) +import /etc/caddy/addons/tls-snippet.conf + +# In each service block +{$N8N_HOSTNAME} { + import service_tls # <-- Uses the snippet + reverse_proxy n8n:5678 +} +``` + +By default, the snippet is empty (Let's Encrypt is used). When you run `make setup-tls`, the snippet is updated with your certificate paths. + ### Quick Setup 1. Place your certificates in the `certs/` directory: @@ -28,42 +45,22 @@ For corporate/internal deployments where Let's Encrypt is not available, you can make setup-tls ``` -3. Restart Caddy: - ```bash - docker compose -p localai restart caddy - ``` +3. The script will: + - Update `caddy-addon/tls-snippet.conf` with your certificate paths + - Optionally restart Caddy to apply changes -### Manual Setup +### Reset to Let's Encrypt -1. Copy the example file: - ```bash - cp caddy-addon/custom-tls.conf.example caddy-addon/custom-tls.conf - ``` +To switch back to automatic Let's Encrypt certificates: -2. Edit `custom-tls.conf` with your hostnames and certificate paths - -3. Place certificates in `certs/` directory - -4. Restart Caddy: - ```bash - docker compose -p localai restart caddy - ``` - -## How Site Override Works - -When you define a site block in an addon file with the same hostname as the main Caddyfile, Caddy will use **both** configurations. To completely override a site, use the exact same hostname. - -Example: To override `n8n.yourdomain.com` with a custom certificate: - -``` -# caddy-addon/custom-tls.conf -n8n.internal.company.com { - tls /etc/caddy/certs/wildcard.crt /etc/caddy/certs/wildcard.key - reverse_proxy n8n:5678 -} +```bash +make setup-tls --remove ``` -Make sure your `.env` file has `N8N_HOSTNAME=n8n.internal.company.com`. +Or run directly: +```bash +bash scripts/setup_custom_tls.sh --remove +``` ## File Structure @@ -71,8 +68,9 @@ Make sure your `.env` file has `N8N_HOSTNAME=n8n.internal.company.com`. caddy-addon/ ├── .gitkeep # Keeps directory in git ├── README.md # This file -├── custom-tls.conf.example # Example for custom certificates -└── custom-tls.conf # Your custom config (gitignored) +├── tls-snippet.conf.example # Template for TLS snippet (tracked in git) +├── tls-snippet.conf # Your TLS config (gitignored, auto-created) +└── *.conf # Your custom addons (gitignored) certs/ ├── .gitkeep # Keeps directory in git @@ -80,11 +78,24 @@ certs/ └── wildcard.key # Your private key (gitignored) ``` +## Adding Custom Addons + +You can create additional `.conf` files for custom Caddy configurations. They will be automatically loaded after the main Caddyfile. + +Example: `caddy-addon/custom-headers.conf` +```caddy +# Add custom headers to all responses +(custom_headers) { + header X-Custom-Header "My Value" +} +``` + ## Important Notes -- Files in `caddy-addon/*.conf` are gitignored (preserved during updates) +- `tls-snippet.conf.example` is tracked in git (template with default Let's Encrypt behavior) +- `tls-snippet.conf` is gitignored and auto-created from template (preserved during updates) +- Other `*.conf` files are also gitignored (preserved during updates) - Files in `certs/` are gitignored (certificates are not committed) -- Example files (`*.example`) are tracked in git - Caddy validates configuration on startup - check logs if it fails: ```bash docker compose -p localai logs caddy diff --git a/caddy-addon/custom-tls.conf.example b/caddy-addon/custom-tls.conf.example deleted file mode 100644 index e2a161b..0000000 --- a/caddy-addon/custom-tls.conf.example +++ /dev/null @@ -1,114 +0,0 @@ -# Custom TLS Configuration for Corporate/Internal Certificates -# -# This file provides examples for using your own TLS certificates instead of Let's Encrypt. -# Copy this file to custom-tls.conf and modify as needed. -# -# Prerequisites: -# 1. Place your certificate files in the ./certs/ directory -# 2. Update .env hostnames to match your internal domain -# 3. Restart Caddy: docker compose -p localai restart caddy - -# ============================================================================= -# Option 1: Reusable TLS snippet (recommended for wildcard certificates) -# ============================================================================= -# Define once, import in each service block - -(custom_tls) { - tls /etc/caddy/certs/wildcard.crt /etc/caddy/certs/wildcard.key -} - -# Then for each service you want to override: -# -# n8n.internal.company.com { -# import custom_tls -# reverse_proxy n8n:5678 -# } -# -# flowise.internal.company.com { -# import custom_tls -# reverse_proxy flowise:3001 -# } - -# ============================================================================= -# Option 2: Individual service configuration -# ============================================================================= -# Use when you have different certificates for different services - -# n8n.internal.company.com { -# tls /etc/caddy/certs/n8n.crt /etc/caddy/certs/n8n.key -# reverse_proxy n8n:5678 -# } - -# ============================================================================= -# Option 3: Internal CA with auto-reload -# ============================================================================= -# Caddy can auto-reload certificates when they change - -# n8n.internal.company.com { -# tls /etc/caddy/certs/cert.pem /etc/caddy/certs/key.pem { -# # Optional: specify CA certificate for client verification -# # client_auth { -# # mode require_and_verify -# # trusted_ca_cert_file /etc/caddy/certs/ca.pem -# # } -# } -# reverse_proxy n8n:5678 -# } - -# ============================================================================= -# Full Example: All common services with wildcard certificate -# ============================================================================= -# Uncomment and modify the hostnames to match your .env configuration - -# # N8N -# n8n.internal.company.com { -# import custom_tls -# reverse_proxy n8n:5678 -# } - -# # Flowise -# flowise.internal.company.com { -# import custom_tls -# reverse_proxy flowise:3001 -# } - -# # Open WebUI -# webui.internal.company.com { -# import custom_tls -# reverse_proxy open-webui:8080 -# } - -# # Grafana -# grafana.internal.company.com { -# import custom_tls -# reverse_proxy grafana:3000 -# } - -# # Portainer -# portainer.internal.company.com { -# import custom_tls -# reverse_proxy portainer:9000 -# } - -# # Langfuse -# langfuse.internal.company.com { -# import custom_tls -# reverse_proxy langfuse-web:3000 -# } - -# # Supabase -# supabase.internal.company.com { -# import custom_tls -# reverse_proxy kong:8000 -# } - -# # Welcome Page (with basic auth preserved) -# welcome.internal.company.com { -# import custom_tls -# basic_auth { -# {$WELCOME_USERNAME} {$WELCOME_PASSWORD_HASH} -# } -# root * /srv/welcome -# file_server -# try_files {path} /index.html -# } diff --git a/caddy-addon/tls-snippet.conf.example b/caddy-addon/tls-snippet.conf.example new file mode 100644 index 0000000..23b5f3c --- /dev/null +++ b/caddy-addon/tls-snippet.conf.example @@ -0,0 +1,10 @@ +# TLS Configuration Snippet +# Imported by all service blocks in the main Caddyfile. +# +# Default: Empty (uses Let's Encrypt automatic certificates) +# Custom: Overwritten by 'make setup-tls' with your certificate paths +# Reset: Run 'make setup-tls --remove' to restore Let's Encrypt + +(service_tls) { + # Default: Let's Encrypt automatic certificates (empty = no override) +} diff --git a/scripts/06_run_services.sh b/scripts/06_run_services.sh index 6586526..96a8707 100755 --- a/scripts/06_run_services.sh +++ b/scripts/06_run_services.sh @@ -32,6 +32,23 @@ require_file "$PROJECT_ROOT/docker-compose.yml" "docker-compose.yml file not fou require_file "$PROJECT_ROOT/Caddyfile" "Caddyfile not found in project root. Reverse proxy might not work." require_file "$PROJECT_ROOT/start_services.py" "start_services.py file not found in project root." +# Remove legacy custom-tls.conf that causes duplicate host errors +# This is needed for users upgrading from older versions +# TODO: Remove this cleanup block after v3.0 release (all users migrated) +OLD_TLS_CONFIG="$PROJECT_ROOT/caddy-addon/custom-tls.conf" +if [[ -f "$OLD_TLS_CONFIG" ]]; then + log_warning "Removing obsolete custom-tls.conf (causes duplicate host errors)" + rm -f "$OLD_TLS_CONFIG" +fi + +# Ensure TLS snippet exists (auto-create from template if missing) +TLS_SNIPPET="$PROJECT_ROOT/caddy-addon/tls-snippet.conf" +TLS_TEMPLATE="$PROJECT_ROOT/caddy-addon/tls-snippet.conf.example" +if [[ ! -f "$TLS_SNIPPET" ]] && [[ -f "$TLS_TEMPLATE" ]]; then + cp "$TLS_TEMPLATE" "$TLS_SNIPPET" + log_info "Created tls-snippet.conf from template (Let's Encrypt mode)" +fi + # Check if Docker daemon is running if ! docker info > /dev/null 2>&1; then log_error "Docker daemon is not running. Please start Docker and try again." diff --git a/scripts/setup_custom_tls.sh b/scripts/setup_custom_tls.sh index 8250a0a..7175628 100755 --- a/scripts/setup_custom_tls.sh +++ b/scripts/setup_custom_tls.sh @@ -2,12 +2,13 @@ # ============================================================================= # setup_custom_tls.sh - Configure custom TLS certificates for Caddy # ============================================================================= -# Generates caddy-addon/custom-tls.conf for using corporate/internal certificates +# Updates caddy-addon/tls-snippet.conf to use 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 +# bash scripts/setup_custom_tls.sh --remove # Reset to Let's Encrypt # # Prerequisites: # - Place certificate files in ./certs/ directory @@ -18,13 +19,27 @@ set -euo pipefail source "$(dirname "$0")/utils.sh" && init_paths -ADDON_FILE="$PROJECT_ROOT/caddy-addon/custom-tls.conf" +SNIPPET_FILE="$PROJECT_ROOT/caddy-addon/tls-snippet.conf" +SNIPPET_EXAMPLE="$PROJECT_ROOT/caddy-addon/tls-snippet.conf.example" CERTS_DIR="$PROJECT_ROOT/certs" +# Legacy file that causes duplicate host errors (must be cleaned up on migration) +# TODO: Remove OLD_CONFIG and cleanup_legacy_config() after v3.0 release (all users migrated) +OLD_CONFIG="$PROJECT_ROOT/caddy-addon/custom-tls.conf" + # ============================================================================= # FUNCTIONS # ============================================================================= +cleanup_legacy_config() { + # Remove old custom-tls.conf that causes duplicate host errors + # This is needed for users upgrading from older versions + if [[ -f "$OLD_CONFIG" ]]; then + log_warning "Removing obsolete custom-tls.conf (causes duplicate host errors)" + rm -f "$OLD_CONFIG" + fi +} + show_help() { cat << EOF Setup Custom TLS Certificates for Caddy @@ -33,7 +48,7 @@ Usage: $(basename "$0") [OPTIONS] [CERT_FILE] [KEY_FILE] Options: -h, --help Show this help message - --remove Remove custom TLS configuration + --remove Reset to Let's Encrypt automatic certificates Arguments: CERT_FILE Path to certificate file (relative to ./certs/) @@ -42,13 +57,12 @@ Arguments: Examples: $(basename "$0") # Interactive mode $(basename "$0") wildcard.crt wildcard.key # Use specific files - $(basename "$0") --remove # Remove custom TLS config + $(basename "$0") --remove # Reset to Let's Encrypt 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 +2. Update caddy-addon/tls-snippet.conf with your certificate paths +3. Optionally restart Caddy EOF } @@ -75,157 +89,53 @@ find_keys() { 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") +ensure_snippet_exists() { + # Create tls-snippet.conf from example if it doesn't exist + # This ensures the file survives git updates (it's gitignored) + if [[ ! -f "$SNIPPET_FILE" ]]; then + if [[ -f "$SNIPPET_EXAMPLE" ]]; then + cp "$SNIPPET_EXAMPLE" "$SNIPPET_FILE" + log_info "Created tls-snippet.conf from template" + else + # Fallback: create default content directly + remove_config fi - done - - echo "${services[*]:-}" + fi } 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 + cat > "$SNIPPET_FILE" << EOF +# TLS Configuration Snippet +# Generated by setup_custom_tls.sh on $(date -Iseconds) +# Using custom certificates instead of Let's Encrypt. +# Reset to Let's Encrypt: make setup-tls --remove -# Reusable TLS snippet -(custom_tls) { -HEADER +(service_tls) { + tls /etc/caddy/certs/$cert_file /etc/caddy/certs/$key_file +} +EOF - 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" + log_success "Generated $SNIPPET_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 + cat > "$SNIPPET_FILE" << 'EOF' +# TLS Configuration Snippet +# Imported by all service blocks in the main Caddyfile. +# +# Default: Empty (uses Let's Encrypt automatic certificates) +# Custom: Overwritten by 'make setup-tls' with your certificate paths +# Reset: Run 'make setup-tls --remove' to restore Let's Encrypt + +(service_tls) { + # Default: Let's Encrypt automatic certificates (empty = no override) +} +EOF + + log_success "Reset to Let's Encrypt (automatic certificates)" } restart_caddy() { @@ -250,12 +160,19 @@ main() { exit 0 ;; --remove) + cleanup_legacy_config remove_config restart_caddy exit 0 ;; esac + # Clean up legacy config that causes duplicate hosts + cleanup_legacy_config + + # Ensure snippet file exists (survives git updates) + ensure_snippet_exists + # Ensure certs directory exists mkdir -p "$CERTS_DIR" @@ -319,29 +236,12 @@ main() { 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[@]}" + generate_config "$cert_file" "$key_file" - # 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 + log_info "Custom TLS configured successfully!" + log_info "All services will use: /etc/caddy/certs/$cert_file" echo "" # Restart Caddy