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.
Auto setup script: Caddy + acme.sh TLS forward proxy with Basic Auth (Debian/Ubuntu)
#!/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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment