#!/usr/bin/env bash # Obtain Let's Encrypt SSL certificates for all domains # Runs certbot on VMID 105 (Nginx) for all configured domains set -euo pipefail # Load IP configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true # 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}[⚠]${NC} $1"; } log_error() { echo -e "${RED}[✗]${NC} $1"; } PROXMOX_HOST="${PROXMOX_HOST:-192.168.11.11}" VMID_NGINX=105 EMAIL="${SSL_EMAIL:-nsatoshi2007@hotmail.com}" # Cloudflare credentials for DNS-01: token OR email+key (Certbot uses one method per file) SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" if [ -f "$PROJECT_ROOT/.env" ]; then set +euo pipefail source "$PROJECT_ROOT/.env" 2>/dev/null || true set -euo pipefail fi echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🔒 SSL Certificate Acquisition" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" log_info "Proxmox Host: $PROXMOX_HOST" log_info "Nginx VMID: $VMID_NGINX" log_info "Email: $EMAIL" echo "" # Check if certbot is installed log_info "Checking certbot installation..." certbot_check=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- which certbot 2>/dev/null || echo 'not found'") if [ "$certbot_check" = "not found" ]; then log_warn "Certbot not found, installing..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- apt update && apt install -y certbot python3-certbot-nginx python3-certbot-dns-cloudflare" else # Ensure DNS plugin is installed log_info "Ensuring certbot DNS plugin is installed..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- apt install -y python3-certbot-dns-cloudflare 2>/dev/null || true" fi # Setup Cloudflare credentials for DNS-01 (Certbot uses ONE method per file: token OR email+key) if [ -z "${CLOUDFLARE_API_TOKEN:-}" ] && { [ -z "${CLOUDFLARE_EMAIL:-}" ] || [ -z "${CLOUDFLARE_API_KEY:-}" ]; }; then log_error "Set CLOUDFLARE_API_TOKEN or (CLOUDFLARE_EMAIL + CLOUDFLARE_API_KEY) in .env" log_info "See: docs/04-configuration/CLOUDFLARE_CREDENTIALS_BOTH_METHODS.md" exit 1 fi log_info "Setting up Cloudflare DNS credentials..." if [ -n "${CLOUDFLARE_API_TOKEN:-}" ]; then CRED_FILE=$(mktemp) echo "dns_cloudflare_api_token = $CLOUDFLARE_API_TOKEN" > "$CRED_FILE" elif [ -n "${CLOUDFLARE_EMAIL:-}" ] && [ -n "${CLOUDFLARE_API_KEY:-}" ]; then CRED_FILE=$(mktemp) echo "dns_cloudflare_email = $CLOUDFLARE_EMAIL" > "$CRED_FILE" echo "dns_cloudflare_api_key = $CLOUDFLARE_API_KEY" >> "$CRED_FILE" fi ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- bash -c 'mkdir -p /etc/cloudflare && cat > /etc/cloudflare/credentials.ini'" < "$CRED_FILE" ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- chmod 600 /etc/cloudflare/credentials.ini" rm -f "$CRED_FILE" log_success "Cloudflare credentials configured" # Domains to obtain certificates for DOMAINS=( # RPC Services "rpc.public-0138.defi-oracle.io" "rpc-http-pub.d-bis.org" "rpc-ws-pub.d-bis.org" "rpc-http-prv.d-bis.org" "rpc-ws-prv.d-bis.org" # Explorer "explorer.d-bis.org" # DBIS Services "dbis-admin.d-bis.org" "dbis-api.d-bis.org" "dbis-api-2.d-bis.org" "secure.d-bis.org" # MIM4U "mim4u.org:www.mim4u.org" "secure.mim4u.org" "training.mim4u.org" # Sankofa/Phoenix "sankofa.nexus:www.sankofa.nexus" "phoenix.sankofa.nexus:www.phoenix.sankofa.nexus" "the-order.sankofa.nexus" ) success_count=0 fail_count=0 for domain_entry in "${DOMAINS[@]}"; do # Handle domains with multiple names (separated by :) IFS=':' read -ra DOMAIN_ARRAY <<< "$domain_entry" domain_list="" primary_domain="" for domain in "${DOMAIN_ARRAY[@]}"; do if [ -z "$domain_list" ]; then domain_list="$domain" primary_domain="$domain" else domain_list="$domain_list -d $domain" fi done log_info "Obtaining certificate for: $primary_domain" # Try HTTP-01 first (faster if it works) log_info " Trying HTTP-01 challenge..." result=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- certbot --nginx -d $domain_list --non-interactive --agree-tos --email $EMAIL 2>&1" || echo "FAILED") # If HTTP-01 fails, try DNS-01 with longer propagation time if echo "$result" | grep -q "NXDOMAIN\|DNS problem\|Failed to authenticate\|no valid A records"; then log_warn " HTTP-01 failed, trying DNS-01 challenge..." result=$(ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- certbot certonly --dns-cloudflare \ --dns-cloudflare-credentials /etc/cloudflare/credentials.ini \ --dns-cloudflare-propagation-seconds 120 \ -d $domain_list \ --non-interactive --agree-tos --email $EMAIL 2>&1" || echo "FAILED") # If DNS-01 succeeds, update nginx config manually if echo "$result" | grep -q "Congratulations\|Successfully"; then log_info " Updating Nginx configuration..." ssh -o StrictHostKeyChecking=no root@"$PROXMOX_HOST" \ "pct exec $VMID_NGINX -- certbot --nginx -d $domain_list --non-interactive --cert-name $primary_domain 2>&1" || true fi fi if echo "$result" | grep -q "Congratulations\|Successfully"; then log_success "Certificate obtained: $primary_domain" ((success_count++)) elif echo "$result" | grep -q "already exists"; then log_warn "Certificate already exists: $primary_domain" ((success_count++)) else log_error "Failed to obtain certificate: $primary_domain" echo "$result" | grep -i "error\|failed" | head -3 ((fail_count++)) fi echo "" done echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" log_info "Summary: $success_count succeeded, $fail_count failed" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "" if [ $fail_count -gt 0 ]; then log_warn "Some certificates failed - check that:" echo " 1. DNS records point to $PUBLIC_IP" echo " 2. ER605 NAT rule is configured" echo " 3. Nginx is listening on port 80" echo " 4. Port 80 is accessible from internet" exit 1 fi