2017-10-02 01:43:15 +02:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
usage() {
|
2017-11-16 01:03:20 +01:00
|
|
|
cat <<EOF >&2
|
2018-10-20 10:11:46 +02:00
|
|
|
Usage: $0 --email=admin@example.com [--method={webroot|standalone}] \
|
|
|
|
[--no-zulip-conf] hostname.example.com [another.example.com]
|
2017-11-16 01:03:20 +01:00
|
|
|
EOF
|
|
|
|
exit 1
|
2017-10-02 01:43:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if [ "$EUID" -ne 0 ]; then
|
|
|
|
echo "Error: This script must be run as root" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
2017-11-16 00:19:54 +01:00
|
|
|
method=webroot
|
2018-10-20 10:11:46 +02:00
|
|
|
args="$(getopt -o '' --long help,email:,method:,deploy-hook:,no-zulip-conf,agree-tos -n "$0" -- "$@")"
|
2017-10-02 01:43:15 +02:00
|
|
|
eval "set -- $args"
|
|
|
|
while true; do
|
|
|
|
case "$1" in
|
|
|
|
--email)
|
|
|
|
EMAIL="$2"
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
;;
|
2017-11-16 00:19:54 +01:00
|
|
|
--method)
|
|
|
|
method="$2"
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
;;
|
2018-07-22 20:56:24 +02:00
|
|
|
--deploy-hook)
|
|
|
|
deploy_hook=(--deploy-hook "$2")
|
|
|
|
shift
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
--agree-tos)
|
|
|
|
agree_tos=--agree-tos
|
|
|
|
shift
|
|
|
|
;;
|
2017-11-15 00:48:22 +01:00
|
|
|
--no-zulip-conf)
|
|
|
|
no_zulip_conf=1
|
|
|
|
shift
|
|
|
|
;;
|
2017-10-02 01:43:15 +02:00
|
|
|
--help)
|
|
|
|
show_help=1
|
|
|
|
shift
|
|
|
|
;;
|
|
|
|
--)
|
2018-10-20 10:11:46 +02:00
|
|
|
shift
|
2017-10-02 01:43:15 +02:00
|
|
|
break
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
2018-10-20 10:11:46 +02:00
|
|
|
# Parse the remaining arguments as Subject Alternative Names to pass to certbot
|
|
|
|
HOSTNAMES=()
|
|
|
|
for arg; do
|
|
|
|
HOSTNAMES+=(-d "$arg")
|
|
|
|
done
|
|
|
|
DOMAIN=$1
|
|
|
|
|
2017-10-02 01:43:15 +02:00
|
|
|
if [ -n "$show_help" ]; then
|
|
|
|
usage
|
|
|
|
fi
|
|
|
|
|
2018-08-03 02:14:48 +02:00
|
|
|
if [ -z "$DOMAIN" ] || [ -z "$EMAIL" ]; then
|
2017-11-16 01:04:54 +01:00
|
|
|
usage
|
|
|
|
fi
|
|
|
|
|
2017-11-16 00:19:54 +01:00
|
|
|
case "$method" in
|
|
|
|
standalone)
|
|
|
|
method_args=(--standalone)
|
|
|
|
;;
|
|
|
|
webroot)
|
2018-08-03 02:14:48 +02:00
|
|
|
method_args=(--webroot '--webroot-path=/var/lib/zulip/certbot-webroot/')
|
2017-11-16 00:19:54 +01:00
|
|
|
;;
|
|
|
|
*)
|
|
|
|
usage
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2017-11-15 22:27:48 +01:00
|
|
|
set -x
|
|
|
|
|
2017-11-10 19:32:55 +01:00
|
|
|
CERTBOT_PATH="/usr/local/sbin/certbot-auto"
|
2017-10-02 01:43:15 +02:00
|
|
|
# For reference https://certbot.eff.org/all-instructions/#debian-other-nginx
|
2017-11-15 00:14:52 +01:00
|
|
|
wget -q https://dl.eff.org/certbot-auto -O "$CERTBOT_PATH"
|
2017-11-10 19:32:55 +01:00
|
|
|
chmod a+x "$CERTBOT_PATH"
|
2017-10-02 01:43:15 +02:00
|
|
|
|
2018-03-29 02:07:54 +02:00
|
|
|
# First, we install the OS packages with --quiet, to suppress `apt`
|
|
|
|
# prompting the user for input. This can't be part of the same
|
|
|
|
# invocation as gets the certs, since `certonly --quiet --force-interactive`
|
|
|
|
# rejects the Certbot ToS, causing Certbot to fail.
|
|
|
|
"$CERTBOT_PATH" --os-packages-only --quiet
|
2018-01-22 23:42:04 +01:00
|
|
|
# We don't use --no-interactive, because certbot needs to ask the user
|
|
|
|
# to agree to the Let's Encrypt Subscriber Agreement (aka ToS).
|
|
|
|
# Passing --force-interactive suppresses a warning, but also brings up
|
|
|
|
# an annoying prompt we stifle with --no-eff-email.
|
2018-07-22 20:56:24 +02:00
|
|
|
"$CERTBOT_PATH" certonly "${method_args[@]}" \
|
2018-10-20 10:11:46 +02:00
|
|
|
"${HOSTNAMES[@]}" -m "$EMAIL" \
|
2019-02-23 00:50:38 +01:00
|
|
|
$agree_tos \
|
2018-07-22 20:56:24 +02:00
|
|
|
"${deploy_hook[@]}" \
|
|
|
|
--force-interactive --no-eff-email
|
2017-10-02 01:43:15 +02:00
|
|
|
|
2017-11-15 00:12:26 +01:00
|
|
|
symlink_with_backup() {
|
|
|
|
if [ -e "$2" ]; then
|
|
|
|
# If the user is setting up our automatic certbot-management on a
|
|
|
|
# system that already has certs for Zulip, use some extra caution
|
|
|
|
# to keep the old certs available.
|
|
|
|
mv -f --backup=numbered "$2" "$2".setup-certbot || true
|
|
|
|
fi
|
|
|
|
ln -nsf "$1" "$2"
|
|
|
|
}
|
|
|
|
|
2018-08-03 02:14:48 +02:00
|
|
|
if [ ${#deploy_hook} -eq 0 ]; then
|
2018-07-22 20:56:24 +02:00
|
|
|
# If no deploy hook was specified, assume we're deploying to the default
|
|
|
|
# location Zulip wants.
|
|
|
|
CERT_DIR=/etc/letsencrypt/live/"$DOMAIN"
|
|
|
|
symlink_with_backup "$CERT_DIR"/privkey.pem /etc/ssl/private/zulip.key
|
|
|
|
symlink_with_backup "$CERT_DIR"/fullchain.pem /etc/ssl/certs/zulip.combined-chain.crt
|
|
|
|
fi
|
2017-10-02 01:43:15 +02:00
|
|
|
|
2017-11-16 00:19:54 +01:00
|
|
|
case "$method" in
|
|
|
|
webroot)
|
|
|
|
service nginx reload
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
|
2017-11-15 00:48:22 +01:00
|
|
|
if [ -z "$no_zulip_conf" ]; then
|
|
|
|
crudini --set /etc/zulip/zulip.conf certbot auto_renew yes
|
|
|
|
fi
|
|
|
|
|
2017-10-02 01:43:15 +02:00
|
|
|
echo "Certbot SSL certificate configuration succeeded."
|