#!/bin/bash set -e # --- Configuration --- GREEN="\033[1;32m" RED="\033[1;31m" YELLOW="\033[1;33m" NC="\033[0m" # No Color REPO_URL="https://github.com/fabriziosalmi/caddy-waf.git" REPO_DIR="caddy-waf" GO_VERSION_REQUIRED="1.22.3" GO_VERSION_TARGET="1.23.4" XCADDY_VERSION="latest" # or specify a version like "v0.3.7" GEOLITE2_DB_URL="https://git.io/GeoLite2-Country.mmdb" GEOLITE2_DB_FILE="GeoLite2-Country.mmdb" # --- Helper Functions --- print_success() { echo -e "${GREEN}✅ Success: $1${NC}" } print_warning() { echo -e "${YELLOW}⚠️ Warning: $1${NC}" } print_info() { echo -e "ℹ️ Info: $1${NC}" } print_error() { echo -e "${RED}❌ Error: $1${NC}" echo -e "${RED} $1${NC}" >&2 # Print error to stderr as well exit 1 } check_command_exists() { if ! command -v "$1" &> /dev/null; then return 1 # Command not found else return 0 # Command found fi } ensure_go_installed() { if ! check_command_exists go; then print_info "Go not found. Installing Go $GO_VERSION_TARGET..." install_go else check_go_version fi } ensure_xcaddy_installed() { if ! check_command_exists xcaddy; then print_info "xcaddy not found. Installing xcaddy..." install_xcaddy else print_info "xcaddy is already installed." fi } clone_or_update_repo() { if [ -d "$REPO_DIR" ]; then print_info "$REPO_DIR directory already exists. Pulling latest changes..." cd "$REPO_DIR" || print_error "Could not change directory to $REPO_DIR" git pull origin main || print_error "Failed to pull $REPO_DIR updates." # Specify origin and branch cd .. # Go back to the script's directory else print_info "Cloning $REPO_DIR repository..." git clone "$REPO_URL" "$REPO_DIR" || print_error "Failed to clone repository from $REPO_URL." fi cd "$REPO_DIR" || print_error "Could not change directory to $REPO_DIR after clone/pull" } update_dependencies() { print_info "Running go mod tidy..." go mod tidy || print_error "Failed to run go mod tidy." print_success "Dependencies updated (go mod tidy)." print_info "Fetching Go modules..." go get -v github.com/caddyserver/caddy/v2 github.com/caddyserver/caddy/v2/caddyconfig/caddyfile github.com/caddyserver/caddy/v2/caddyconfig/httpcaddyfile github.com/caddyserver/caddy/v2/modules/caddyhttp github.com/oschwald/maxminddb-golang github.com/fsnotify/fsnotify github.com/fabriziosalmi/caddy-waf || print_error "Failed to fetch Go modules." # Combined go get print_success "Go modules fetched successfully." } download_geolite2_db() { if [ ! -f "$GEOLITE2_DB_FILE" ]; then print_info "Downloading GeoLite2 Country database..." wget -q "$GEOLITE2_DB_URL" -O "$GEOLITE2_DB_FILE" || print_error "Failed to download GeoLite2 database from $GEOLITE2_DB_URL." # Specify output file print_success "GeoLite2 database downloaded." else print_info "GeoLite2 database already exists." fi } build_caddy() { print_info "Building Caddy with caddy-waf module..." xcaddy build --with github.com/fabriziosalmi/caddy-waf=./ || print_error "Failed to build Caddy." print_success "Caddy built successfully." } format_caddyfile() { print_info "Formatting Caddyfile..." ./caddy fmt --overwrite || print_warning "Failed to format Caddyfile (This is a warning, Caddy might still run)." # Warning instead of error print_success "Caddyfile formatted." } run_caddy() { print_info "Starting Caddy server..." ./caddy run || print_error "Failed to start Caddy." # Keep as error, Caddy run failure is critical print_success "Caddy is running." # This line will likely not be reached in a typical run } # --- OS Specific Functions --- install_go_linux() { print_info "Installing Go $GO_VERSION_TARGET for Linux..." GOBIN="/usr/local/go/bin" # Define GOBIN for clarity wget "https://go.dev/dl/go${GO_VERSION_TARGET}.linux-amd64.tar.gz" || print_error "Failed to download Go for Linux." sudo rm -rf /usr/local/go sudo tar -C /usr/local -xzf "go${GO_VERSION_TARGET}.linux-amd64.tar.gz" || print_error "Failed to extract Go for Linux." rm "go${GO_VERSION_TARGET}.linux-amd64.tar.gz" export PATH="$PATH:$GOBIN" # Ensure PATH is updated in current shell print_success "Go $GO_VERSION_TARGET installed successfully on Linux." } install_go_macos() { print_info "Installing Go $GO_VERSION_TARGET for macOS..." curl -LO "https://go.dev/dl/go${GO_VERSION_TARGET}.darwin-amd64.pkg" || print_error "Failed to download Go for macOS." sudo installer -pkg "go${GO_VERSION_TARGET}.darwin-amd64.pkg" -target / || print_error "Failed to install Go package on macOS." rm "go${GO_VERSION_TARGET}.darwin-amd64.pkg" export PATH="$PATH:/usr/local/go/bin" # Ensure PATH is updated in current shell print_success "Go $GO_VERSION_TARGET installed successfully on macOS." } install_xcaddy() { print_info "Installing xcaddy $XCADDY_VERSION..." GOBIN="$(go env GOBIN)" if [ -z "$GOBIN" ]; then GOBIN="$HOME/go/bin" # Default GOBIN if not set fi go install "github.com/caddyserver/xcaddy/cmd/xcaddy@$XCADDY_VERSION" || print_error "Failed to install xcaddy." export PATH="$PATH:$GOBIN" # Ensure PATH is updated in current shell print_success "xcaddy $XCADDY_VERSION installed successfully." } check_go_version() { local version version=$(go version 2>&1 | awk '{print $3}' | sed 's/go//') # Redirect stderr to stdout for error handling if [[ "$version" == *"error"* ]]; then # Check for "error" string in output print_warning "Failed to get Go version. Assuming Go is outdated or not properly installed. Attempting to install Go $GO_VERSION_TARGET." install_go # Attempt reinstall if version check fails return fi if [[ $(printf '%s\n' "$GO_VERSION_REQUIRED" "$version" | sort -V | head -n1) != "$GO_VERSION_REQUIRED" ]]; then print_warning "Go version $version is older than required $GO_VERSION_REQUIRED. Attempting to install Go $GO_VERSION_TARGET." install_go # Attempt reinstall if version is too old else print_info "Go version $version meets requirements ($GO_VERSION_REQUIRED or newer)." fi } install_go() { OS=$(uname -s) if [ "$OS" == "Linux" ]; then install_go_linux elif [ "$OS" == "Darwin" ]; then install_go_macos else print_error "Unsupported OS: $OS" fi check_go_version # Re-check version after install to confirm success } # --- Main Script Execution --- print_info "Starting setup for caddy-waf..." ensure_go_installed ensure_xcaddy_installed clone_or_update_repo update_dependencies download_geolite2_db build_caddy format_caddyfile run_caddy print_success "caddy-waf setup completed!"