Skip to content

Instantly share code, notes, and snippets.

@pirate
Last active May 20, 2021 00:21
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pirate/c36cf8a8608d54a97f7ebb7ef6d562e1 to your computer and use it in GitHub Desktop.
Save pirate/c36cf8a8608d54a97f7ebb7ef6d562e1 to your computer and use it in GitHub Desktop.
SSL certificate generation script supporting openssl, mkcert, and letsencrypt with manual/standalone/webroot/cloudflare-dns/digitalocean-dns.
#!/usr/bin/env bash
# set -o xtrace
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
SCRIPTNAME="$0"
HELP_TEXT="
Generate SSL certificate and Diffie-helman parameters for a given [domain].
Usage:
$SCRIPTNAME [domain] [mkcert|openssl|letsencryt] [standalone|webroot|cloudflare|digitalocean|manual]
Examples:
$SCRIPTNAME example.l
$SCRIPTNAME example.l mkcert
$SCRIPTNAME example.com openssl
$SCRIPTNAME example.com letsencrypt
$SCRIPTNAME example.com letsencrypt digitalocean
"
### Config
REPO_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && cd .. && pwd )"
CERTS_DIR="$REPO_DIR/data/certs"
TMP_DIR="$REPO_DIR/data/tmp/letsencrypt"
DH_SIZE=2048
METHOD=openssl
CREDENTIALS_FILE="$REPO_DIR/env/secrets.env"
SSL_EMAIL="ssl@zalad.io"
WEBROOT_DIR=/var/www/html
### OpenSSL
function openssl_cert {
DOMAIN="$1"
echo "[+] Generating self-signed cert for $DOMAIN using openssl..."
openssl req \
-new \
-newkey rsa:4096 \
-x509 \
-sha256 \
-days 365 \
-nodes \
-out "$CERTS_DIR/$DOMAIN.crt" \
-keyout "$CERTS_DIR/$DOMAIN.key" \
-subj "/C=US/ST=NY/L=New York/O=Monadical/OU=Engineering/CN=$DOMAIN"
}
function openssl_dhparam {
echo "[+] Generating $DH_SIZE bit Diffie-helman parameter file..."
openssl dhparam -out "$CERTS_DIR/$DOMAIN.dh" "$DH_SIZE"
}
### Letsencrypt
function letsencrypt_install {
echo "[+] Installing letsencrypt..."
if brew --version > /dev/null; then
python3 --version > /dev/null || brew install python3
pip3 --quiet install certbot \
certbot-nginx \
certbot-dns-digitalocean \
certbot-dns-cloudflare
else
apt-get install software-properties-common
add-apt-repository -y -n universe
add-apt-repository -y -n ppa:certbot/certbot
apt update -qq
apt install -y \
certbot \
python3-certbot-nginx \
python3-certbot-dns-digitalocean \
python3-certbot-dns-cloudflare
fi
}
function letsencrypt_cert {
DOMAIN="$1"; PROVIDER="${2:-cloudflare}"
letsencrypt_install
echo "[+] Generating live SSL cert for $DOMAIN using letsencrypt + $PROVIDER..."
CMD=(
certbot
certonly
--agree-tos
-m "$SSL_EMAIL"
--non-interactive
--config-dir "$TMP_DIR"
--work-dir "$TMP_DIR"
--logs-dir "$TMP_DIR"
--domain "$DOMAIN"
)
CONTENT_BEFORE=$(cat "$TMP_DIR/live/$DOMAIN/privkey.pem")
if [[ "$CONTENT_BEFORE" ]]; then
CMD+=(--keep-until-expiring)
else
CMD+=(--force-renewal)
fi
if [[ "$PROVIDER" == "standalone" ]] || [[ "$PROVIDER" == "manual" ]]; then
CMD+=("--$PROVIDER")
elif [[ "$PROVIDER" == "webroot" ]]; then
CMD+=("--webroot" "--webroot-path=$WEBROOT_DIR")
else
CMD+=("--dns-$PROVIDER" "--dns-$PROVIDER-credentials=$CREDENTIALS_FILE")
fi
if eval "${CMD[*]}"; then
echo "[i] Certbot returned exit status=$?"
fi
CONTENT_AFTER=$(cat "$TMP_DIR/live/$DOMAIN/privkey.pem")
if [[ ! "$CONTENT_AFTER" ]]; then
echo "[X] Generated certificate was not found in $TMP_DIR/live/$DOMAIN"
exit 1
elif [[ "$CONTENT_BEFORE" != "$CONTENT_AFTER" ]]; then
cp -L "$TMP_DIR/live/$DOMAIN/fullchain.pem" "$CERTS_DIR/$DOMAIN.crt"
cp -L "$TMP_DIR/live/$DOMAIN/privkey.pem" "$CERTS_DIR/$DOMAIN.key"
echo "[$(date +"%Y-%m-%d %H:%M")] Renewed SSL certificate succesfully."
else
echo "[$(date +"%Y-%m-%d %H:%M")] SSL certificate already up-to-date."
fi
}
### MKCert
function mkcert_install {
echo "[+] Installing mkcert (https://github.com/FiloSottile/mkcert)..."
if brew --version > /dev/null; then
brew install mkcert
fi
}
function mkcert_cert {
DOMAIN="$1"
mkcert_install
echo "[+] Generating self-signed cert for $DOMAIN using mkcert..."
cd /tmp || exit 1
mkcert "$DOMAIN"
mv "$DOMAIN.pem" "$CERTS_DIR/$DOMAIN.crt"
mv "$DOMAIN-key.pem" "$CERTS_DIR/$DOMAIN.key"
}
function main {
DOMAIN="$1"
METHOD="${2:-openssl}"
LETSENCRYPT_PROVIDER="${3:-cloudflare}"
if [[ ! "$DOMAIN" ]]; then
echo "$HELP_TEXT"
exit 2
fi
mkdir -p "$CERTS_DIR"
DOMAIN_IP="$(dig -4 +short "$DOMAIN" A)"
PUBLIC_IP="$(curl --silent https://diagnostic.opendns.com/myip)"
if [[ "$DOMAIN_IP" == "$PUBLIC_IP" ]]; then
echo "[√] Domain $DOMAIN DNS A record resolves to my IP $DOMAIN_IP."
else
if [[ "$DOMAIN_IP" ]]; then
echo "[!] Warning: Domain $DOMAIN DNS A record resolves to $DOMAIN_IP (this server's IP is $PUBLIC_IP)!"
else
if [[ "$METHOD" != "openssl" ]] && [[ "$METHOD" != "mkcert" ]]; then
echo "[!] Warning: Domain $DOMAIN DNS A record is not set up yet!"
fi
fi
fi
if [[ "$METHOD" == "mkcert" ]]; then
mkcert_cert "$DOMAIN"
elif [[ "$METHOD" == "openssl" ]]; then
openssl_cert "$DOMAIN"
else
letsencrypt_cert "$DOMAIN" "$LETSENCRYPT_PROVIDER"
fi
if [[ ! "$(cat "$CERTS_DIR/$DOMAIN.dh")" ]]; then
openssl_dhparam
fi
echo
echo "[√] Done. Your new certificates can be found here:"
echo " $CERTS_DIR"
echo
ls -l "$CERTS_DIR"
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment