Files
proxmox/scripts/setup-letsencrypt-tunnel.sh

269 lines
9.6 KiB
Bash
Executable File

#!/usr/bin/env bash
# Complete Let's Encrypt setup using Cloudflare Tunnel
# Falls back to public IP, then DNS-01 if needed
set -e
VMID=2500
DOMAIN="rpc-core.d-bis.org"
NAME="rpc-core"
IP="192.168.11.250"
PUBLIC_IP="45.49.67.248"
PROXMOX_HOST="192.168.11.10"
TUNNEL_VMID=102
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
log_info "Let's Encrypt Setup - Cloudflare Tunnel Method"
log_info "Domain: $DOMAIN"
echo ""
# Load .env
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [ -f "$SCRIPT_DIR/../.env" ]; then
source "$SCRIPT_DIR/../.env" 2>/dev/null
fi
# Step 1: Configure Cloudflare Tunnel
log_info "Step 1: Configuring Cloudflare Tunnel route..."
# Get tunnel ID from token
if [ -n "$CLOUDFLARE_TUNNEL_TOKEN" ]; then
TUNNEL_ID=$(echo "$CLOUDFLARE_TUNNEL_TOKEN" | base64 -d 2>/dev/null | python3 -c "import sys, json; data=json.load(sys.stdin); print(data.get('a', ''))" 2>/dev/null || echo "")
if [ -z "$TUNNEL_ID" ]; then
# Fallback: use account ID as tunnel ID (they're often the same)
TUNNEL_ID="${CLOUDFLARE_ACCOUNT_ID:-52ad57a71671c5fc009edf0744658196}"
fi
log_info "Tunnel ID: $TUNNEL_ID"
else
TUNNEL_ID="${CLOUDFLARE_ACCOUNT_ID:-52ad57a71671c5fc009edf0744658196}"
log_warn "Using account ID as tunnel ID: $TUNNEL_ID"
fi
# Check if tunnel is running
if sshpass -p 'L@kers2010' ssh -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \
"pct exec $TUNNEL_VMID -- systemctl is-active cloudflared >/dev/null 2>&1"; then
log_success "Cloudflare Tunnel is running"
else
log_warn "Cloudflare Tunnel may not be running on VMID $TUNNEL_VMID"
fi
# Configure tunnel route via API
if [ -n "$CLOUDFLARE_API_KEY" ] && [ -n "$CLOUDFLARE_EMAIL" ] && [ -n "$CLOUDFLARE_ACCOUNT_ID" ] && [ -n "$TUNNEL_ID" ]; then
log_info "Configuring tunnel route via API..."
# Get current tunnel config
TUNNEL_CONFIG=$(curl -s -X GET "https://api.cloudflare.com/client/v4/accounts/$CLOUDFLARE_ACCOUNT_ID/cfd_tunnel/$TUNNEL_ID/configurations" \
-H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
-H "X-Auth-Key: $CLOUDFLARE_API_KEY" \
-H "Content-Type: application/json")
# Check if route already exists in config
if echo "$TUNNEL_CONFIG" | grep -q "$DOMAIN"; then
log_info "Tunnel route already exists for $DOMAIN"
else
log_info "Adding tunnel route: $DOMAIN → http://$IP:443"
log_warn "Tunnel route configuration via API is complex - using manual method"
log_info "Please configure in Cloudflare Dashboard:"
log_info " Zero Trust → Networks → Tunnels → Your Tunnel → Configure"
log_info " Add Public Hostname: rpc-core.d-bis.org → http://$IP:443"
log_info ""
log_info "Continuing with DNS setup (tunnel route can be added manually)..."
fi
else
log_warn "Missing credentials for tunnel API configuration"
fi
# Step 2: Update DNS to use Tunnel (CNAME)
log_info ""
log_info "Step 2: Updating DNS to use Cloudflare Tunnel..."
# Delete existing A record if exists
if [ -f "$SCRIPT_DIR/create-dns-record-rpc-core.sh" ]; then
log_info "Checking existing DNS record..."
EXISTING_RECORD=$(curl -s -X GET "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records?name=$DOMAIN" \
-H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
-H "X-Auth-Key: $CLOUDFLARE_API_KEY" \
-H "Content-Type: application/json")
if echo "$EXISTING_RECORD" | grep -q '"id"'; then
RECORD_ID=$(echo "$EXISTING_RECORD" | grep -o '"id":"[^"]*' | head -1 | cut -d'"' -f4)
log_info "Deleting existing A record..."
curl -s -X DELETE "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records/$RECORD_ID" \
-H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
-H "X-Auth-Key: $CLOUDFLARE_API_KEY" \
-H "Content-Type: application/json" >/dev/null
fi
fi
# Create CNAME to tunnel
if [ -z "$TUNNEL_ID" ]; then
log_error "Tunnel ID not found. Cannot create CNAME."
exit 1
fi
TUNNEL_TARGET="${TUNNEL_ID}.cfargotunnel.com"
log_info "Creating CNAME: $NAME$TUNNEL_TARGET"
CNAME_RESPONSE=$(curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records" \
-H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
-H "X-Auth-Key: $CLOUDFLARE_API_KEY" \
-H "Content-Type: application/json" \
--data "{
\"type\": \"CNAME\",
\"name\": \"$NAME\",
\"content\": \"$TUNNEL_TARGET\",
\"ttl\": 1,
\"proxied\": true
}")
if echo "$CNAME_RESPONSE" | grep -q '"success":true'; then
log_success "CNAME record created (proxied)"
else
log_error "Failed to create CNAME record"
log_info "Response: $CNAME_RESPONSE"
exit 1
fi
# Step 3: Wait for tunnel route to be active
log_info ""
log_info "Step 3: Waiting for tunnel route to be active (10 seconds)..."
sleep 10
# Step 4: Wait for DNS propagation
log_info ""
log_info "Step 4: Waiting for DNS propagation (30 seconds)..."
sleep 30
# Step 5: Try Let's Encrypt HTTP-01 through tunnel
log_info ""
log_info "Step 5: Attempting Let's Encrypt HTTP-01 challenge through tunnel..."
CERTBOT_OUTPUT=$(sshpass -p 'L@kers2010' ssh -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \
"pct exec $VMID -- certbot --nginx \
--non-interactive \
--agree-tos \
--email admin@d-bis.org \
-d $DOMAIN \
--redirect 2>&1" || echo "FAILED")
if echo "$CERTBOT_OUTPUT" | grep -q "Successfully received certificate\|Congratulations"; then
log_success "Certificate obtained via HTTP-01 through tunnel!"
exit 0
else
log_warn "HTTP-01 through tunnel failed"
log_info "Trying fallback: Public IP method..."
fi
# Fallback: Try with public IP
log_info ""
log_info "Fallback: Trying with public IP $PUBLIC_IP..."
# Update DNS to point to public IP
log_info "Updating DNS to point to public IP..."
PUBLIC_IP_RESPONSE=$(curl -s -X PUT "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records/$RECORD_ID" \
-H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
-H "X-Auth-Key: $CLOUDFLARE_API_KEY" \
-H "Content-Type: application/json" \
--data "{
\"type\": \"A\",
\"name\": \"$NAME\",
\"content\": \"$PUBLIC_IP\",
\"ttl\": 1,
\"proxied\": false
}" 2>/dev/null || curl -s -X POST "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records" \
-H "X-Auth-Email: $CLOUDFLARE_EMAIL" \
-H "X-Auth-Key: $CLOUDFLARE_API_KEY" \
-H "Content-Type: application/json" \
--data "{
\"type\": \"A\",
\"name\": \"$NAME\",
\"content\": \"$PUBLIC_IP\",
\"ttl\": 1,
\"proxied\": false
}")
if echo "$PUBLIC_IP_RESPONSE" | grep -q '"success":true'; then
log_success "DNS updated to public IP"
sleep 30
CERTBOT_OUTPUT=$(sshpass -p 'L@kers2010' ssh -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \
"pct exec $VMID -- certbot --nginx \
--non-interactive \
--agree-tos \
--email admin@d-bis.org \
-d $DOMAIN \
--redirect 2>&1" || echo "FAILED")
if echo "$CERTBOT_OUTPUT" | grep -q "Successfully received certificate\|Congratulations"; then
log_success "Certificate obtained via HTTP-01 with public IP!"
exit 0
else
log_warn "HTTP-01 with public IP failed"
fi
else
log_warn "Failed to update DNS to public IP"
fi
# Final fallback: DNS-01 challenge
log_info ""
log_info "Final fallback: Using DNS-01 challenge..."
# Install DNS plugin
sshpass -p 'L@kers2010' ssh -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \
"pct exec $VMID -- apt-get install -y -qq python3-certbot-dns-cloudflare" || {
log_error "Failed to install certbot-dns-cloudflare"
exit 1
}
# Create credentials file
sshpass -p 'L@kers2010' ssh -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \
"pct exec $VMID -- bash -c '
mkdir -p /etc/cloudflare
cat > /etc/cloudflare/credentials.ini <<EOF
dns_cloudflare_api_token = ${CLOUDFLARE_API_TOKEN:-}
dns_cloudflare_email = $CLOUDFLARE_EMAIL
dns_cloudflare_api_key = $CLOUDFLARE_API_KEY
EOF
chmod 600 /etc/cloudflare/credentials.ini
'"
# Try DNS-01
log_info "Obtaining certificate via DNS-01 challenge..."
CERTBOT_OUTPUT=$(sshpass -p 'L@kers2010' ssh -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \
"pct exec $VMID -- certbot certonly --dns-cloudflare \
--dns-cloudflare-credentials /etc/cloudflare/credentials.ini \
--non-interactive \
--agree-tos \
--email admin@d-bis.org \
-d $DOMAIN 2>&1" || echo "FAILED")
if echo "$CERTBOT_OUTPUT" | grep -q "Successfully received certificate\|Congratulations"; then
log_success "Certificate obtained via DNS-01 challenge!"
# Update Nginx manually
log_info "Updating Nginx configuration..."
sshpass -p 'L@kers2010' ssh -o StrictHostKeyChecking=no root@${PROXMOX_HOST} \
"pct exec $VMID -- bash -c '
sed -i \"s|ssl_certificate /etc/nginx/ssl/rpc.crt;|ssl_certificate /etc/letsencrypt/live/$DOMAIN/fullchain.pem;|\" /etc/nginx/sites-available/rpc-core
sed -i \"s|ssl_certificate_key /etc/nginx/ssl/rpc.key;|ssl_certificate_key /etc/letsencrypt/live/$DOMAIN/privkey.pem;|\" /etc/nginx/sites-available/rpc-core
nginx -t && systemctl reload nginx
'"
log_success "Nginx updated with Let's Encrypt certificate!"
exit 0
else
log_error "All methods failed"
log_info "Output: $CERTBOT_OUTPUT"
exit 1
fi