Files
baiyue-logistics-chat/deploy/prepare-gray-tls.sh
T

92 lines
3.9 KiB
Bash

#!/usr/bin/env bash
set +x
set -Eeuo pipefail
umask 022
root=${1:?}
release=${2:?}
[[ "$root" == /*/gray-logistics-chat && "$root" != *..* ]] || exit 2
[[ "$release" == "$root"/releases/* && "$release" != *..* ]] || exit 2
[[ "$(cat "$root/.project")" == baiyue-logistics-chat-gray ]] || exit 2
while IFS='=' read -r name value; do
case "$name" in
CHAT_ROOT|CHAT_RELEASE|CHAT_DOMAIN|CHAT_PROXY_DIR|CHAT_TLS_CERT|CHAT_TLS_KEY|CHAT_CERTBOT_IMAGE|CHAT_CERTBOT_IMAGE_ID|SOURCE_COMMIT)
[[ "$value" =~ ^[A-Za-z0-9_./:-]+$ ]] || exit 2
printf -v "$name" '%s' "$value" ;;
esac
done < "$release/release.env"
[[ "$CHAT_ROOT" == "$root" && "$CHAT_RELEASE" == "$release" ]] || exit 2
[[ "$CHAT_TLS_CERT" == "$root/tls/config/live/$CHAT_DOMAIN/fullchain.pem" ]] || exit 2
[[ "$CHAT_TLS_KEY" == "$root/tls/config/live/$CHAT_DOMAIN/privkey.pem" ]] || exit 2
[[ "$CHAT_CERTBOT_IMAGE" =~ ^baiyue-logistics-chat-certbot:[a-f0-9]{12}-b[0-9]+$ ]] || exit 2
loaded_id=$(awk -F= '$1 == "CERTBOT_IMAGE_ID" {print $2}' "$release/loaded-image-ids.env")
[[ "$loaded_id" =~ ^sha256:[a-f0-9]{64}$ ]] || exit 2
[[ "$(docker image inspect --format '{{.Id}}' "$CHAT_CERTBOT_IMAGE")" == "$loaded_id" ]] || { echo 'Loaded certificate image changed.' >&2; exit 2; }
[[ "$(docker image inspect --format '{{index .Config.Labels "org.opencontainers.image.revision"}}' "$CHAT_CERTBOT_IMAGE")" == "$SOURCE_COMMIT" ]] || exit 2
site="$CHAT_PROXY_DIR/baiyue-logistics-chat-gray.conf"
if [[ -f "$site" ]]; then
head -n 1 "$site" | grep -Fq 'Managed for baiyue-logistics-chat-gray' || exit 2
else
for candidate in "$CHAT_PROXY_DIR/"*.conf; do
[[ -f "$candidate" ]] || continue
if grep -Fq "$CHAT_DOMAIN" "$candidate"; then echo 'Domain already belongs to another site.' >&2; exit 2; fi
done
cat > "$release/bootstrap.conf" <<BOOTSTRAP
# Managed for baiyue-logistics-chat-gray; HTTP certificate bootstrap only.
server {
listen 80;
server_name $CHAT_DOMAIN;
location ^~ /.well-known/acme-challenge/ {
root /var/lib/baiyue-logistics-chat-acme;
try_files \$uri =404;
}
location / { return 404; }
}
BOOTSTRAP
install -m 644 "$release/bootstrap.conf" "$site"
if ! nginx -t; then rm -f -- "$site"; exit 2; fi
nginx -s reload
fi
install -d -m 755 /var/lib/baiyue-logistics-chat-acme
install -d -m 700 "$root/tls" "$root/tls/config" "$root/tls/work" "$root/tls/logs"
if [[ ! -f "$CHAT_TLS_CERT" ]] || ! openssl x509 -in "$CHAT_TLS_CERT" -checkend 604800 -noout >/dev/null; then
docker run --rm --name baiyue-logistics-chat-certbot-issue \
-v "$root/tls/config:/etc/letsencrypt" -v "$root/tls/work:/var/lib/letsencrypt" \
-v "$root/tls/logs:/var/log/letsencrypt" -v /var/lib/baiyue-logistics-chat-acme:/webroot \
"$CHAT_CERTBOT_IMAGE" certonly --non-interactive --webroot -w /webroot \
--cert-name "$CHAT_DOMAIN" -d "$CHAT_DOMAIN" --agree-tos --register-unsafely-without-email
fi
openssl x509 -in "$CHAT_TLS_CERT" -checkhost "$CHAT_DOMAIN" -noout >/dev/null
install -m 700 "$release/renew-tls.sh" "$root/tls/renew.sh"
unit=/etc/systemd/system/baiyue-logistics-chat-tls-renew.service
timer=/etc/systemd/system/baiyue-logistics-chat-tls-renew.timer
for file in "$unit" "$timer"; do
if [[ -e "$file" ]]; then head -n 1 "$file" | grep -Fq 'Managed for baiyue-logistics-chat-gray' || exit 2; fi
done
cat > "$unit" <<UNIT
# Managed for baiyue-logistics-chat-gray
[Unit]
Description=Renew logistics chat gray certificate
After=docker.service
Requires=docker.service
[Service]
Type=oneshot
ExecStart=/bin/bash $root/tls/renew.sh $root $CHAT_DOMAIN $CHAT_CERTBOT_IMAGE
UNIT
cat > "$timer" <<TIMER
# Managed for baiyue-logistics-chat-gray
[Unit]
Description=Daily logistics chat gray certificate renewal
[Timer]
OnCalendar=daily
RandomizedDelaySec=6h
Persistent=true
[Install]
WantedBy=timers.target
TIMER
chmod 644 "$unit" "$timer"
systemctl daemon-reload
systemctl enable --now baiyue-logistics-chat-tls-renew.timer
printf 'Gray certificate is ready; dedicated renewal timer enabled.\n'