Explorar el Código

Add it for real

bryan hace 4 años
padre
commit
2598532761
Se han modificado 1 ficheros con 212 adiciones y 0 borrados
  1. 212 0
      acme-cpanel.sh

+ 212 - 0
acme-cpanel.sh

@@ -0,0 +1,212 @@
+#!/usr/bin/env bash
+# This script uses acme.sh to issue and deploy SSL certificates from Let's Encrypt for a list of domains 
+# using the webroot or dns methods
+#
+# See README.md for more details
+#
+# Copyright 2020 Bryan Roessler <bryanroessler@gmail.com>
+#
+# USAGE
+#   ./acme-cpanel.sh [OPTIONS] [FILES...]
+#
+# EXAMPLES
+#   TESTING: ./acme-cpanel-webroot.sh --debug -e me@gmail.com multisites/flatwhitedesign.pw multisites/greengingermultisite.website
+#   PRODUCTION: ./acme-cpanel-webroot.sh --force -e me@gmail.com multisites/flatwhitedesign.pw multisites/greengingermultisite.website
+#
+#   TESTING: ./acme-cpanel-webroot.sh --debug -s multisites
+#   PRODUCTION: ./acme-cpanel-webroot.sh --force -s multisites
+#
+# FILES is a list of files containing first-level DOMAIN names (see domains.txt) on newlines
+# Certificates will automatically be issued and deployed for DOMAIN and www.DOMAIN using the webroot method
+#
+# NOTE: The webroot method does NOT support wildcard domains, Let's Encrypt requires wildcard domains to
+# use DNS challenges, which the CPANEL uapi does not support (use dns_cpaneldns plugin instead)
+
+source functions.sh
+
+unset SITES_DIR USEREMAIL DOMAIN_FILES DOMAIN_GROUPS DEPLOY_CMD_PREFIX ISSUE_CMD_PREFIX DEBUG GROUP
+
+DEBUG="true" # quote this line to stop DEBUG mode and issue certificates for real, or use --force in user options
+METHOD="dns" # set the default method
+
+parse_input() {
+
+    local input
+    declare -g USEREMAIL
+    declare -ag DOMAIN_FILES
+
+    if input=$(getopt -o +m:e:fgs:d -l method:,email:,force,group-by-file,sites-dir:,debug -- "$@"); then
+        eval set -- "$input"
+        while true; do
+            case "$1" in
+                --method|-m)
+                    shift
+                    METHOD="${1,,}"
+                    ;;
+                --email|-e)
+                    shift
+                    USEREMAIL="$1"
+                    ;;
+                --force|-f)
+                    unset DEBUG
+                    ;;
+                --group-by-file|-g)
+                    GROUP="true"
+                    ;;
+                --sites-dir|-s)
+                    shift
+                    SITES_DIR="$1"
+                    ;;
+                --debug|-d)
+                    DEBUG="true"
+                    ;;
+                --)
+                    shift
+                    break
+                    ;;
+            esac
+            shift
+        done
+    else
+        echo "Incorrect options provided"
+        exit 1
+    fi
+
+    # Load domain files from remaining arguments
+    if [[ $# -lt 1 ]]; then
+        [[ -v SITES_DIR && -d "$SITES_DIR" ]] && return 0
+        if [[ -f "domains.txt" ]]; then
+            echo "You have not supplied any domain files, using domains.txt by default"
+            DOMAIN_FILES=("domains.txt")
+        else
+            echo "You must specify a domain list or use domains.txt by default"
+            exit 1
+        fi
+    else
+        DOMAIN_FILES=("$@")
+    fi
+}
+
+
+get_acme() {
+    curl https://get.acme.sh | sh
+    source "$HOME/.bashrc"
+    "$HOME/.acme.sh/acme.sh" --upgrade --auto-upgrade
+}
+
+
+update_email() { [[ -v USEREMAIL ]] && "$HOME/.acme.sh/acme.sh" --update-account --accountemail "${USEREMAIL}"; }
+
+
+command_prefixes() {
+    declare -ag ISSUE_CMD_PREFIX DEPLOY_CMD_PREFIX
+    ISSUE_CMD_PREFIX=("$HOME/.acme.sh/acme.sh" "--issue")
+    [[ "$METHOD" == "dns" ]] && ISSUE_CMD_PREFIX=("${ISSUE_CMD_PREFIX[@]}" "--dns" "dns_cpaneldns")
+    [[ -v DEBUG ]] && ISSUE_CMD_PREFIX=("${ISSUE_CMD_PREFIX[@]}" "--staging") || ISSUE_CMD_PREFIX=("${ISSUE_CMD_PREFIX[@]}" "--force")
+    DEPLOY_CMD_PREFIX=("$HOME/.acme.sh/acme.sh" "--deploy" "--deploy-hook" "cpanel_uapi")
+}
+
+
+get_webroot() {
+    local webroot
+    if ! webroot=$(uapi DomainInfo single_domain_data domain="$1" | grep documentroot); then
+        echo "UAPI call failed" >&2
+    fi
+    if [[ ! -v webroot || "$webroot" == "" ]]; then
+        if [[ -v DEBUG ]]; then
+            webroot="/tmp" # set missing webroot in DEBUG mode for testing
+        else
+            echo "Could not find $1's webroot" >&2
+            exit 1
+        fi
+    fi
+    echo "$webroot"
+}
+
+
+# Either create a single array of all domains (DOMAINS) to issue one-by-one or create an array of array names to issue for a single webroot
+load_domains() {
+    local domain_file
+    declare -ag DOMAIN_GROUPS=()
+
+    if [[ -v SITES_DIR ]]; then
+        for domain_file in "$SITES_DIR"/*; do
+            DOMAIN_GROUPS+=("$(<"$domain_file")")
+        done
+    fi
+
+    for domain_file in "${DOMAIN_FILES[@]}"; do
+        # Load list of domains as space-delimited strings in elements of the DOMAINS array
+        # We can keep these separate or combine them later
+        DOMAIN_GROUPS+=("$(<"$domain_file")")
+    done
+}
+
+
+issue_and_deploy_certs() {
+
+    local domain_root domain domain_group
+    local -a issue_cmd=()
+    local -a deploy_cmd=()
+    
+    if [[ -v GROUP ]]; then
+        for domain_group in "${DOMAIN_GROUPS[@]}"; do
+            unset i
+            for domain in $domain_group; do # we want to split on whitespace
+                [[ "$domain" == "" ]] && continue
+                # Get the webroot from the first domain
+                if [[ ! -v i ]]; then 
+                    local i="set"
+                    domain_root=$(get_webroot "$domain")
+                    issue_cmd=("${ISSUE_CMD_PREFIX[@]}" "-w" "$domain_root")
+                fi
+                issue_cmd+=("-d" "$domain" "-d" "www.$domain")
+            done
+
+            # Issue certificate for entire domain group
+            echo "Running:" "${issue_cmd[@]}"
+            if ! "${issue_cmd[@]}"; then
+                echo "Failed to issue certificate"
+            # Deploy certificates one by one
+            for domain in $domain_group; do
+                deploy_cmd=("${DEPLOY_CMD_PREFIX[@]}" "-w" "$domain_root" "-d" "$domain")
+                echo "Running:" "${deploy_cmd[@]}"
+                "${deploy_cmd[@]}"
+            done
+        done
+    else
+        for domain_group in "${DOMAIN_GROUPS[@]}"; do
+            # Issue and deploy certificates one by one
+            for domain in $domain_group; do # we want to split on whitespace
+                issue_cmd=("${ISSUE_CMD_PREFIX[@]}" "-d" "$domain" "-d" "www.$domain")
+                [[ "$METHOD" == "webroot" ]] && domain_root=$(get_webroot "$domain") && issue_cmd=("${issue_cmd[@]}" "-w" "$domain_root")
+                deploy_cmd=("${DEPLOY_CMD_PREFIX[@]}" "-d" "$domain") # I think we only need to deploy to the domain, not subdomains
+                [[ "$METHOD" == "webroot" ]] && deploy_cmd=("${deploy_cmd[@]}" "-w" "$domain_root")
+                echo "Running:" "${issue_cmd[@]}"
+                if ! "${issue_cmd[@]}"; then
+                    echo "Failed to issue certificate for $domain"
+                    err=1
+                fi
+                echo "Running:" "${deploy_cmd[@]}"
+                if ! "${deploy_cmd[@]}"; then
+                    echo "Failed to deploy certificate for $domain"
+                    err=1
+                fi
+            done
+        done
+    fi
+}
+
+
+main() {
+    parse_input "$@"
+    get_acme
+    update_email
+    command_prefixes
+    load_domains
+    issue_and_deploy_certs
+}
+
+
+main "$@"
+exit "${err:-0}"