Files
proxmox-caddy/setup_caddy.sh
2026-01-02 15:49:19 -08:00

189 lines
5.9 KiB
Bash
Executable File

#!/bin/bash
# --- CONFIGURATION ---
SECRETS_FILES=(
"/mnt/secrets/caddy.env"
"/mnt/secrets/redis.env"
)
CADDY_BIN="/usr/bin/caddy"
SYSTEMD_OVERRIDE_DIR="/etc/systemd/system/caddy.service.d"
GO_VERSION="1.25.5"
# List of modules we REQUIRE (must match the build section below)
REQUIRED_MODULES=(
"github.com/caddy-dns/cloudflare"
"github.com/corazawaf/coraza-caddy/v2"
"github.com/pberkel/caddy-storage-redis"
)
# --- 1. PRE-FLIGHT CHECKS ---
if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root"
exit 1
fi
echo "--- STARTING SETUP ---"
# --- 2. INTELLIGENT MODULE CHECK ---
NEEDS_BUILD=false
if ! command -v caddy &> /dev/null; then
echo "⚠️ Caddy not found. Build required."
NEEDS_BUILD=true
else
# Get list of compiled modules in the current binary
CURRENT_MODULES=$(caddy list-modules --packages)
echo "Checking existing Caddy modules..."
for mod in "${REQUIRED_MODULES[@]}"; do
if [[ "$CURRENT_MODULES" != *"$mod"* ]]; then
echo "⚠️ Missing module: $mod"
NEEDS_BUILD=true
break
fi
done
fi
if [ "$NEEDS_BUILD" = false ]; then
echo "✅ Existing Caddy binary has all required modules. Skipping build."
else
echo "🛠️ Build required. Initializing build environment..."
# --- 3. INSTALL GO (Only if Build Needed) ---
echo "Installing system dependencies..."
apt update && apt install -y debian-keyring debian-archive-keyring apt-transport-https curl git tar gcc
if command -v go &>/dev/null && [[ "$(go version)" == *"go$GO_VERSION"* ]]; then
echo "✅ Go $GO_VERSION is already installed."
else
echo "⬇️ Installing Go $GO_VERSION..."
rm -rf /usr/local/go
rm -f /usr/bin/go
curl -OL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz"
tar -C /usr/local -xzf "go${GO_VERSION}.linux-amd64.tar.gz"
rm "go${GO_VERSION}.linux-amd64.tar.gz"
ln -sf /usr/local/go/bin/go /usr/bin/go
fi
# --- 4. PREPARE XCADDY ---
if ! command -v xcaddy &>/dev/null; then
echo "Installing xcaddy..."
/usr/local/go/bin/go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest
fi
# Locate xcaddy
export PATH=$PATH:/root/go/bin
XCADDY_EXEC=$(which xcaddy 2>/dev/null || echo "$(go env GOPATH)/bin/xcaddy")
# --- 5. BUILD BINARY ---
echo "🧱 Building Caddy with custom modules..."
"$XCADDY_EXEC" build \
--with github.com/caddy-dns/cloudflare \
--with github.com/corazawaf/coraza-caddy/v2 \
--with github.com/gamalan/caddy-tlsredis \
--output ./caddy-custom
if [ ! -f "./caddy-custom" ]; then
echo "CRITICAL ERROR: Build failed."
exit 1
fi
echo "Replacing standard Caddy binary..."
# Ensure standard caddy deps are present
if ! dpkg -s caddy &> /dev/null; then
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list
apt update && apt install -y caddy
fi
systemctl stop caddy
mv ./caddy-custom "$CADDY_BIN"
chmod +x "$CADDY_BIN"
fi
# --- 6. CONFIGURE SYSTEMD SECRETS ---
echo "Configuring Systemd Secrets..."
mkdir -p "$SYSTEMD_OVERRIDE_DIR"
echo "[Service]" > "$SYSTEMD_OVERRIDE_DIR/override.conf"
for SECRETS_FILE in "${SECRETS_FILES[@]}"; do
if [ ! -f "$SECRETS_FILE" ]; then
echo "⚠️ WARNING: Secrets file not found: $SECRETS_FILE"
continue
fi
echo "Reading secrets from $SECRETS_FILE..."
while IFS= read -r line || [ -n "$line" ]; do
# Skip comments/empty lines
[[ "$line" =~ ^#.*$ ]] && continue
[[ -z "${line// }" ]] && continue
# Clean 'export' and whitespace
clean_line="${line//export /}"
clean_line=$(echo "$clean_line" | xargs)
# Inject
echo "Environment=\"$clean_line\"" >> "$SYSTEMD_OVERRIDE_DIR/override.conf"
echo " + Injected: ${clean_line%%=*}"
done < "$SECRETS_FILE"
done
# --- 6.5 SETUP WAF (CORAZA & OWASP CRS) ---
echo "Setting up WAF Rules (OWASP CRS)..."
WAF_DEST="/etc/caddy/coraza"
mkdir -p "$WAF_DEST"
# 1. Download OWASP Core Rule Set (v4.0.0)
# We only download if the rules directory is missing
if [ ! -d "$WAF_DEST/rules" ]; then
echo "Downloading OWASP CRS v4..."
curl -SL https://github.com/coreruleset/coreruleset/archive/refs/tags/v4.0.0.tar.gz -o /tmp/crs.tar.gz
tar -xzf /tmp/crs.tar.gz -C /tmp
# Move rules to destination
mv /tmp/coreruleset-4.0.0/rules "$WAF_DEST/"
# We rename the example setup to the standard name
mv /tmp/coreruleset-4.0.0/crs-setup.conf.example "$WAF_DEST/crs-setup.conf"
rm -rf /tmp/crs.tar.gz /tmp/coreruleset-4.0.0
else
echo "✅ OWASP Rules already present."
fi
# 2. Deploy YOUR Custom WAF Configs
# This copies your 'waf' folder contents into /etc/caddy/coraza/
if [ -d "./waf" ]; then
echo "Copying custom WAF configurations..."
cp -r ./waf/* "$WAF_DEST/"
# Fix permissions
chown -R caddy:caddy "$WAF_DEST"
# Ensure logs directory exists
mkdir -p /var/log/caddy
chown -R caddy:caddy /var/log/caddy
else
echo "WARNING: ./waf folder not found in repo. Skipping custom configs."
fi
if [ -f "./Caddyfile" ]; then
echo "Updating /etc/caddy/Caddyfile..."
cp "./Caddyfile" /etc/caddy/Caddyfile
fi
# --- 7. FINISH ---
echo "Reloading..."
systemctl daemon-reload
systemctl enable caddy
# Only restart if we actually changed something or if service is dead
if [ "$NEEDS_BUILD" = true ] || ! systemctl is-active --quiet caddy; then
systemctl restart caddy
else
# If we didn't rebuild, just reload config to be safe/fast
systemctl reload caddy
fi
echo "Done! Status:"
systemctl status caddy --no-pager