#!/usr/bin/env bash # # ACME-DNS Docker Setup Script (Production Hardened) # Generates validated, secure configuration for joohoi/acme-dns # https://github.com/joohoi/acme-dns # set -euo pipefail IFS=$'\n\t' # ====================== # CONFIGURATION (EDIT THESE) # ====================== SETUP_DIR="/var/tmp/acme-dns-setup" MAIN_DOMAIN="example.com" # Your registered domain (e.g., yoursite.com) ACME_DNS_SUBDOMAIN="auth" # Creates auth.yoursite.com ACME_DNS_FQDN="${ACME_DNS_SUBDOMAIN}.${MAIN_DOMAIN}" PUBLIC_IP="1.2.3.4" # Public server IP (MUST be reachable on UDP/TCP 53) ADMIN_EMAIL="admin@${MAIN_DOMAIN}" # SOA contact (converted to DNS format) LE_NOTIFICATION_EMAIL="admin@${MAIN_DOMAIN}" # Let's Encrypt expiry notices # API Configuration API_PORT="443" # 443 required for letsencrypt modes API_TLS_MODE="letsencryptstaging" # none | letsencrypt | letsencryptstaging | cert CUSTOM_TLS_CERT_PRIVKEY="/etc/acme-dns/certs/privkey.pem" CUSTOM_TLS_CERT_FULLCHAIN="/etc/acme-dns/certs/fullchain.pem" # Operational DNS_PORT="53" # MUST be 53 for public DNS delegation LOG_LEVEL="info" # error | warning | info | debug # ====================== # VALIDATION & SAFETY # ====================== validate_domain() { local domain="$1" # Basic domain validation (RFC 1035 compliant pattern) if [[ ! "$domain" =~ ^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z]{2,})+$ ]]; then echo "❌ ERROR: Invalid domain format: '${domain}'" >&2 echo " Must be a valid domain (e.g., example.com)" >&2 exit 1 fi } if ! command -v docker &>/dev/null; then echo "❌ ERROR: Docker not found. Install Docker first." >&2 exit 1 fi # Critical placeholder validation if [[ "${MAIN_DOMAIN}" == "example.com" || "${PUBLIC_IP}" == "1.2.3.4" ]]; then echo -e "\n⚠️ \033[1;31mCRITICAL WARNING\033[0m: Using default placeholder values!" >&2 echo " Edit CONFIGURATION section BEFORE proceeding." >&2 read -p "Continue anyway? (y/N): " -r || exit 1 [[ ! "$REPLY" =~ ^[Yy]$ ]] && echo "Aborted." && exit 1 fi # Validate domains validate_domain "${MAIN_DOMAIN}" validate_domain "${ACME_DNS_FQDN}" # Port conflict detection (precise regex to avoid false positives like port 530) for port in "${DNS_PORT}" "${API_PORT}"; do if ss -tuln 2>/dev/null | awk -v p=":${port}$" '$4 ~ p {exit 1} END {exit 0}'; then echo "⚠️ WARNING: Host port ${port} is in use!" >&2 echo " acme-dns requires exclusive access to these ports." >&2 read -p "Continue? (y/N): " -r || exit 1 [[ ! "$REPLY" =~ ^[Yy]$ ]] && exit 1 fi done # ====================== # CONFIG GENERATION (TOML-SAFE) # ====================== generate_config() { local nsadmin="${ADMIN_EMAIL//@/.}" # SOA format: admin@domain.com → admin.domain.com cat <&2 exit 1 fi read -p "⚠️ This will CREATE/OVERWRITE ${SETUP_DIR}. Confirm? (y/N): " -r || exit 1 [[ ! "$REPLY" =~ ^[Yy]$ ]] && echo "Aborted by user." && exit 0 # Atomic directory setup rm -rf "${SETUP_DIR}" 2>/dev/null || true mkdir -p "${SETUP_DIR}"/{config,data} docker pull joohoi/acme-dns:latest >/dev/null 2>&1 generate_config >"${SETUP_DIR}/config/config.cfg" generate_docker_compose >"${SETUP_DIR}/docker-compose.yml" # ====================== # ACTIONABLE DEPLOYMENT GUIDE # ====================== cat <