Refactor code for improved readability and performance
This commit is contained in:
268
scripts/setup-letsencrypt-tunnel.sh
Executable file
268
scripts/setup-letsencrypt-tunnel.sh
Executable file
@@ -0,0 +1,268 @@
|
||||
#!/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
|
||||
|
||||
Reference in New Issue
Block a user