#!/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 <&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