Skip to content

Instantly share code, notes, and snippets.

@madeye
Created February 16, 2026 01:09
Show Gist options
  • Select an option

  • Save madeye/9a578ad8c9b8166f999719aa7784aa6f to your computer and use it in GitHub Desktop.

Select an option

Save madeye/9a578ad8c9b8166f999719aa7784aa6f to your computer and use it in GitHub Desktop.

Revisions

  1. madeye created this gist Feb 16, 2026.
    176 changes: 176 additions & 0 deletions setup-caddy-proxy.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,176 @@
    #!/usr/bin/env bash
    #
    # Auto setup script: Caddy + acme.sh TLS forward proxy with authentication
    # Usage: sudo bash setup-caddy-proxy.sh
    #
    # Required environment variables:
    # DOMAIN - Your domain (e.g. proxy.example.com)
    # EMAIL - Email for acme.sh registration
    # PROXY_USER - Proxy basic auth username
    # PROXY_PASS - Proxy basic auth password
    # CF_Token - Cloudflare API token (or set vars for your DNS provider)
    # CF_Zone_ID - Cloudflare Zone ID (or set vars for your DNS provider)
    #
    # Optional:
    # DNS_PROVIDER - acme.sh DNS plugin name (default: dns_cf)
    # USE_NAIVE - Set to "yes" to use klzgrad/forwardproxy naive branch (default: yes)
    #

    set -euo pipefail

    # ── Colors ───────────────────────────────────────────────────────────────────
    RED='\033[0;31m'
    GREEN='\033[0;32m'
    YELLOW='\033[1;33m'
    NC='\033[0m'

    info() { echo -e "${GREEN}[INFO]${NC} $*"; }
    warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
    error() { echo -e "${RED}[ERROR]${NC} $*"; exit 1; }

    # ── Pre-flight checks ───────────────────────────────────────────────────────
    [[ $EUID -ne 0 ]] && error "This script must be run as root (or with sudo)."

    for var in DOMAIN EMAIL PROXY_USER PROXY_PASS CF_Token CF_Zone_ID; do
    [[ -z "${!var:-}" ]] && error "Environment variable $var is required but not set."
    done

    DNS_PROVIDER="${DNS_PROVIDER:-dns_cf}"
    USE_NAIVE="${USE_NAIVE:-yes}"

    info "Domain: $DOMAIN"
    info "Email: $EMAIL"
    info "Proxy user: $PROXY_USER"
    info "DNS provider: $DNS_PROVIDER"
    info "Naive branch: $USE_NAIVE"
    echo

    # ── Step 1: Install dependencies ────────────────────────────────────────────
    info "Installing system dependencies..."
    apt update -qq
    apt install -y -qq curl git golang > /dev/null 2>&1

    # ── Step 2: Install acme.sh ─────────────────────────────────────────────────
    if [[ ! -f "$HOME/.acme.sh/acme.sh" ]]; then
    info "Installing acme.sh..."
    curl -fsSL https://get.acme.sh | sh -s email="$EMAIL"
    else
    info "acme.sh already installed, skipping."
    fi

    # ── Step 3: Issue certificate ────────────────────────────────────────────────
    info "Issuing TLS certificate for $DOMAIN via $DNS_PROVIDER..."
    export CF_Token CF_Zone_ID

    "$HOME/.acme.sh/acme.sh" --issue --dns "$DNS_PROVIDER" -d "$DOMAIN" --force || {
    warn "Certificate may already exist. Continuing..."
    }

    mkdir -p /etc/caddy/certs

    "$HOME/.acme.sh/acme.sh" --install-cert -d "$DOMAIN" \
    --cert-file /etc/caddy/certs/cert.pem \
    --key-file /etc/caddy/certs/key.pem \
    --fullchain-file /etc/caddy/certs/fullchain.pem \
    --reloadcmd "systemctl restart caddy || true"

    info "Certificate installed to /etc/caddy/certs/"

    # ── Step 4: Build Caddy with forwardproxy ────────────────────────────────────
    info "Installing xcaddy..."
    GOBIN=/usr/local/bin go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

    info "Building Caddy with forwardproxy plugin (this may take a few minutes)..."
    BUILD_DIR=$(mktemp -d)
    cd "$BUILD_DIR"

    if [[ "$USE_NAIVE" == "yes" ]]; then
    /usr/local/bin/xcaddy build \
    --with github.com/caddyserver/forwardproxy=github.com/klzgrad/forwardproxy@naive
    else
    /usr/local/bin/xcaddy build \
    --with github.com/caddyserver/forwardproxy
    fi

    mv caddy /usr/bin/caddy
    chmod +x /usr/bin/caddy
    cd /
    rm -rf "$BUILD_DIR"

    info "Caddy built and installed: $(/usr/bin/caddy version)"

    # ── Step 5: Create camouflage page ──────────────────────────────────────────
    mkdir -p /var/www/html
    cat > /var/www/html/index.html <<'HTMLEOF'
    <!DOCTYPE html>
    <html><head><meta charset="utf-8"><title>Welcome</title></head>
    <body><h1>It works!</h1><p>This is the default web page for this server.</p></body>
    </html>
    HTMLEOF

    # ── Step 6: Write Caddyfile ─────────────────────────────────────────────────
    info "Writing Caddyfile..."
    cat > /etc/caddy/Caddyfile <<EOF
    {
    order forward_proxy before file_server
    admin off
    }
    :443, ${DOMAIN} {
    tls /etc/caddy/certs/fullchain.pem /etc/caddy/certs/key.pem
    forward_proxy {
    basic_auth ${PROXY_USER} ${PROXY_PASS}
    hide_ip
    hide_via
    probe_resistance secret.localhost
    }
    file_server {
    root * /var/www/html
    }
    }
    EOF

    info "Caddyfile written to /etc/caddy/Caddyfile"

    # ── Step 7: Create systemd service ──────────────────────────────────────────
    info "Creating systemd service..."
    cat > /etc/systemd/system/caddy.service <<'EOF'
    [Unit]
    Description=Caddy
    After=network.target network-online.target
    Requires=network-online.target
    [Service]
    Type=notify
    User=root
    ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
    ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile
    TimeoutStopSec=5s
    LimitNOFILE=1048576
    LimitNPROC=512
    [Install]
    WantedBy=multi-user.target
    EOF

    systemctl daemon-reload
    systemctl enable --now caddy

    info "Caddy service started."

    # ── Done ─────────────────────────────────────────────────────────────────────
    echo
    echo -e "${GREEN}══════════════════════════════════════════════════════════════${NC}"
    echo -e "${GREEN} Setup complete!${NC}"
    echo -e "${GREEN}══════════════════════════════════════════════════════════════${NC}"
    echo
    echo " Proxy URL: https://${PROXY_USER}:${PROXY_PASS}@${DOMAIN}:443"
    echo
    echo " Test with:"
    echo " curl -x https://${PROXY_USER}:${PROXY_PASS}@${DOMAIN}:443 https://httpbin.org/ip"
    echo
    echo " Logs:"
    echo " journalctl -u caddy -f"
    echo