|
@@ -0,0 +1,201 @@
|
|
|
+#!/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 method
|
|
|
+# See README for more details
|
|
|
+#
|
|
|
+# Copyright 2020 Bryan Roessler <bryanroessler@gmail.com>
|
|
|
+#
|
|
|
+# USAGE
|
|
|
+# ./acme-cpanel-webroot.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)
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+parse_input() {
|
|
|
+
|
|
|
+ local input
|
|
|
+ declare -g USEREMAIL
|
|
|
+ declare -ag DOMAIN_FILES
|
|
|
+
|
|
|
+ if input=$(getopt -o +e:fks:d -l email:,force,keep-grouping,sites-dir:,debug -- "$@"); then
|
|
|
+ eval set -- "$input"
|
|
|
+ while true; do
|
|
|
+ case "$1" in
|
|
|
+ --email|-e)
|
|
|
+ shift
|
|
|
+ USEREMAIL="$1"
|
|
|
+ ;;
|
|
|
+ --force|-f)
|
|
|
+ unset DEBUG
|
|
|
+ ;;
|
|
|
+ --keep-grouping|-k)
|
|
|
+ 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" "--force")
|
|
|
+ [[ -v DEBUG ]] && ISSUE_CMD_PREFIX=("$HOME/.acme.sh/acme.sh" "--issue" "--staging")
|
|
|
+ DEPLOY_CMD_PREFIX=("$HOME/.acme.sh/acme.sh" "--deploy" "--deploy-hook" "cpanel_uapi")
|
|
|
+ [[ -v DEBUG ]] && DEPLOY_CMD_PREFIX=("$HOME/.acme.sh/acme.sh" "--deploy" "--deploy-hook" "cpanel_uapi")
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+# 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
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+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"
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+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[@]}"
|
|
|
+ "${issue_cmd[@]}"
|
|
|
+ # 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
|
|
|
+ domain_root=$(get_webroot "$domain")
|
|
|
+ issue_cmd=("${ISSUE_CMD_PREFIX[@]}" "-w" "$domain_root" "-d" "$domain" "-d" "www.$domain")
|
|
|
+ deploy_cmd=("${DEPLOY_CMD_PREFIX[@]}" "-w" "$domain_root" "-d" "$domain") # I think we only need to deploy to the domain, not subdomains
|
|
|
+ echo "Running:" "${issue_cmd[@]}"
|
|
|
+ if ! "${issue_cmd[@]}"; then
|
|
|
+ echo "Certificate issue failed for $domain"
|
|
|
+ exit_err=1
|
|
|
+ fi
|
|
|
+ echo "Running:" "${deploy_cmd[@]}"
|
|
|
+ if ! "${deploy_cmd[@]}"; then
|
|
|
+ echo "Certificate deployment failed for $domain"
|
|
|
+ exit_err=1
|
|
|
+ fi
|
|
|
+ done
|
|
|
+ done
|
|
|
+ fi
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+main() {
|
|
|
+ parse_input "$@"
|
|
|
+ get_acme
|
|
|
+ update_email
|
|
|
+ command_prefixes
|
|
|
+ load_domains
|
|
|
+ issue_and_deploy_certs
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+main "$@"
|
|
|
+exit "${exit_err:-0}"
|