Add automatic Caddy configuration for services during installation

Implemented automatic Caddy reverse proxy configuration that runs
BEFORE each service is started, with backup, reload, and formatting.

1. **New configure_caddy_for_service() Function:**
   - Detects if Caddy is installed (skips if not)
   - Prompts user if they want to configure reverse proxy
   - Asks for domain/subdomain (e.g., photos.example.com)
   - Backs up Caddyfile with timestamp
   - Checks for existing configuration and offers to overwrite
   - Adds service block with security headers and fail2ban logging
   - Reloads Caddy configuration
   - Formats Caddyfile with `caddy fmt --overwrite`
   - Final reload after formatting
   - Shows final access URL (https://...)

2. **Configuration Sequence:**
   - Service docker-compose.yml created
   - Service .env configured
   - Caddy configuration added (if Caddy installed)
   - Caddy reloaded and formatted
   - Service containers started
   - All happens before `docker compose up -d`

3. **Integrated into Services:**
   - Immich (photos.example.com)
   - AudioBookshelf (audiobooks.example.com)
   - Emby (emby.example.com)
   - ActualBudget (budget.example.com)
   - Mealie (recipes.example.com)
   - Jellyfin (jellyfin.example.com)
   - Uptime Kuma (uptime.example.com)

4. **Caddy Configuration Includes:**
   - Automatic HTTPS via Let's Encrypt
   - Security headers (HSTS, X-Content-Type-Options, etc.)
   - JSON logging for fail2ban
   - Proper reverse_proxy to localhost:PORT

5. **Backup & Safety:**
   - Caddyfile backed up to: Caddyfile.backup.YYYYMMDD-HHMMSS
   - Existing configs detected and user can choose to overwrite
   - Reload errors show backup file path for restoration

6. **Commands Used:**
   - `docker exec caddy caddy reload --config /etc/caddy/Caddyfile`
   - `docker exec caddy caddy fmt --overwrite /etc/caddy/Caddyfile`

This addresses user request:
"new/reconfigured services are add to the Caddyfile as part of the
install/reconfigure before they are attempt to be brought up, as a
part of the install/reconfigure of the service? (With backup of
Caddyfile and docker exec -w /etc/caddy caddy caddy reload &&
docker exec -w /etc/caddy caddy caddy fmt --overwrite after each
addition to Caddyfile?)"
This commit is contained in:
Claude
2026-01-12 17:08:11 +00:00
parent 52a9617ffe
commit 671a59bf12
+153
View File
@@ -1341,6 +1341,138 @@ prompt_text() {
eval "$varname='$response'"
}
# ============================================================================
# CADDY CONFIGURATION HELPER
# ============================================================================
configure_caddy_for_service() {
local SERVICE_NAME="$1"
local SERVICE_PORT="$2"
local DEFAULT_SUBDOMAIN="$3"
local EXTRA_CONFIG="${4:-}" # Optional extra Caddy directives
# Check if Caddy is installed
if [ ! -d "$DOCKER_DIR/caddy" ]; then
return 0 # Caddy not installed, skip configuration
fi
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " CADDY REVERSE PROXY CONFIGURATION"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
echo "Caddy is installed. You can configure reverse proxy for $SERVICE_NAME."
echo ""
local CONFIGURE_CADDY=""
prompt_yn "Configure Caddy reverse proxy for $SERVICE_NAME? (y/n):" "n" CONFIGURE_CADDY
if [ "$CONFIGURE_CADDY" != "y" ] && [ "$CONFIGURE_CADDY" != "Y" ]; then
echo " Skipping Caddy configuration."
echo " Access $SERVICE_NAME at: http://localhost:$SERVICE_PORT"
return 0
fi
# Get domain/subdomain
echo ""
echo "Enter the full domain for $SERVICE_NAME:"
echo " Examples: $DEFAULT_SUBDOMAIN.example.com, $DEFAULT_SUBDOMAIN.yourdomain.com"
echo ""
local SERVICE_DOMAIN=""
prompt_text "Domain:" "" SERVICE_DOMAIN
if [ -z "$SERVICE_DOMAIN" ]; then
echo " ⚠ No domain provided, skipping Caddy configuration."
return 0
fi
# Backup Caddyfile
local CADDY_DIR="$DOCKER_DIR/caddy"
local CADDYFILE="$CADDY_DIR/Caddyfile"
local BACKUP_FILE="$CADDY_DIR/Caddyfile.backup.$(date +%Y%m%d-%H%M%S)"
if [ -f "$CADDYFILE" ]; then
echo " Backing up Caddyfile to: $(basename $BACKUP_FILE)"
cp "$CADDYFILE" "$BACKUP_FILE"
else
echo " Creating new Caddyfile"
touch "$CADDYFILE"
fi
# Check if service already configured
if grep -q "^${SERVICE_DOMAIN}" "$CADDYFILE" 2>/dev/null; then
echo "$SERVICE_DOMAIN already exists in Caddyfile"
local OVERWRITE=""
prompt_yn "Overwrite existing configuration? (y/n):" "n" OVERWRITE
if [ "$OVERWRITE" != "y" ] && [ "$OVERWRITE" != "Y" ]; then
echo " Keeping existing configuration."
return 0
fi
# Remove existing configuration
sed -i "/^${SERVICE_DOMAIN}/,/^}/d" "$CADDYFILE"
fi
# Add service configuration to Caddyfile
echo " Adding $SERVICE_NAME configuration to Caddyfile..."
cat >> "$CADDYFILE" << CADDY_BLOCK
# $SERVICE_NAME
$SERVICE_DOMAIN {
reverse_proxy localhost:$SERVICE_PORT
# Security headers
header {
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
X-Content-Type-Options "nosniff"
X-Frame-Options "SAMEORIGIN"
Referrer-Policy "strict-origin-when-cross-origin"
}
# Logging for fail2ban
log {
output file /var/log/caddy/${SERVICE_DOMAIN}.log
format json
}
$EXTRA_CONFIG
}
CADDY_BLOCK
echo " ✓ Configuration added to Caddyfile"
# Reload Caddy
echo " Reloading Caddy configuration..."
if docker exec caddy caddy reload --config /etc/caddy/Caddyfile 2>/dev/null; then
echo " ✓ Caddy reloaded successfully"
else
echo " ⚠ Failed to reload Caddy (will retry after formatting)"
fi
# Format Caddyfile
echo " Formatting Caddyfile..."
if docker exec caddy caddy fmt --overwrite /etc/caddy/Caddyfile 2>/dev/null; then
echo " ✓ Caddyfile formatted"
else
echo " ⚠ Failed to format Caddyfile"
fi
# Final reload after formatting
echo " Final reload..."
if docker exec caddy caddy reload --config /etc/caddy/Caddyfile 2>/dev/null; then
echo " ✓ Caddy configuration active"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " $SERVICE_NAME is now accessible at:"
echo " https://$SERVICE_DOMAIN"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
else
echo " ⚠ Failed final reload. Check Caddy logs:"
echo " docker logs caddy"
echo " You can restore from backup: $BACKUP_FILE"
fi
echo ""
}
# ============================================================================
# SHOW CURRENT INSTALLATION STATUS
# ============================================================================
@@ -2667,6 +2799,9 @@ IMMICH_ENV
[ -n "$EXTERNAL_LIBRARY" ] && echo " External: $EXTERNAL_LIBRARY"
echo ""
# Configure Caddy reverse proxy before starting
configure_caddy_for_service "Immich" "2283" "photos"
# Ask to start container
prompt_yn "Start Immich now? (y/n):" "y" START_IMMICH
if [ "$START_IMMICH" = "y" ] || [ "$START_IMMICH" = "Y" ]; then
@@ -2751,6 +2886,9 @@ ABS_ENV
echo ""
echo "✓ Audiobookshelf configured at $ABS_DIR"
# Configure Caddy reverse proxy before starting
configure_caddy_for_service "AudioBookshelf" "13378" "audiobooks"
prompt_yn "Start Audiobookshelf now? (y/n):" "y" START_ABS
if [ "$START_ABS" = "y" ] || [ "$START_ABS" = "Y" ]; then
docker compose up -d 2>/dev/null && echo " ✓ Audiobookshelf started" || echo " ⚠ Failed to start"
@@ -2818,6 +2956,9 @@ EMBY_ENV
echo ""
echo "✓ Emby configured at $EMBY_DIR"
# Configure Caddy reverse proxy before starting
configure_caddy_for_service "Emby" "8096" "emby"
prompt_yn "Start Emby now? (y/n):" "y" START_EMBY
if [ "$START_EMBY" = "y" ] || [ "$START_EMBY" = "Y" ]; then
docker compose up -d 2>/dev/null && echo " ✓ Emby started" || echo " ⚠ Failed to start"
@@ -3264,6 +3405,9 @@ AB_COMPOSE
echo " ✓ ActualBudget configured at $AB_DIR"
# Configure Caddy reverse proxy before starting
configure_caddy_for_service "ActualBudget" "5006" "budget"
prompt_yn "Start ActualBudget now? (y/n):" "y" START_AB
if [ "$START_AB" = "y" ] || [ "$START_AB" = "Y" ]; then
docker compose up -d 2>/dev/null && echo " ✓ ActualBudget started" || echo " ⚠ Failed to start ActualBudget"
@@ -4183,6 +4327,9 @@ MEALIE_COMPOSE
echo ""
echo "✓ Mealie configured at $MEALIE_DIR"
# Configure Caddy reverse proxy before starting
configure_caddy_for_service "Mealie" "9925" "recipes"
prompt_yn "Start Mealie now? (y/n):" "y" START_MEALIE
if [ "$START_MEALIE" = "y" ] || [ "$START_MEALIE" = "Y" ]; then
docker compose up -d 2>/dev/null && echo " ✓ Mealie started" || echo " ⚠ Failed to start"
@@ -4413,6 +4560,9 @@ JELLYFIN_ENV
echo ""
echo "✓ Jellyfin configured at $JELLYFIN_DIR"
# Configure Caddy reverse proxy before starting
configure_caddy_for_service "Jellyfin" "8096" "jellyfin"
prompt_yn "Start Jellyfin now? (y/n):" "y" START_JELLYFIN
if [ "$START_JELLYFIN" = "y" ] || [ "$START_JELLYFIN" = "Y" ]; then
docker compose up -d 2>/dev/null && echo " ✓ Jellyfin started" || echo " ⚠ Failed to start"
@@ -4942,6 +5092,9 @@ UPTIME_COMPOSE
echo ""
echo "✓ Uptime Kuma configured at $UPTIME_DIR"
# Configure Caddy reverse proxy before starting
configure_caddy_for_service "Uptime Kuma" "3001" "uptime"
prompt_yn "Start Uptime Kuma now? (y/n):" "y" START_UPTIME
if [ "$START_UPTIME" = "y" ] || [ "$START_UPTIME" = "Y" ]; then
docker compose up -d 2>/dev/null && echo " ✓ Uptime Kuma started" || echo " ⚠ Failed to start"