Last active
May 20, 2021 00:21
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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