From d78ac7ac26ff70f66437ab3ac8a47e9f530c69df Mon Sep 17 00:00:00 2001 From: Christopher Berger Date: Thu, 28 May 2026 02:12:53 +0000 Subject: [PATCH] Add '{deploy-staged-cert.sh}' Add script for deploying staged certificates from Nginx Proxy Manager. Uses '{push-mailcow-cert.sh}' --- deploy-staged-cert.sh | 57 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 deploy-staged-cert.sh diff --git a/deploy-staged-cert.sh b/deploy-staged-cert.sh new file mode 100644 index 0000000..5e18c19 --- /dev/null +++ b/deploy-staged-cert.sh @@ -0,0 +1,57 @@ +#!/usr/bin/env bash +# +# deploy-staged-cert.sh (runs on the mailcow VM) +# Validates the cert pushed from Nginx Proxy Manager and deploys it into mailcow, +# reloading postfix/dovecot/nginx only when the cert actually changed. + +set -euo pipefail + +# ---- CONFIG --------------------------------------------------------------- +STAGING="/home/certsync/incoming" +MAILCOW_DIR="/opt/mailcow-dockerized" +MAILCOW_SSL_DIR="${MAILCOW_DIR}/data/assets/ssl/mail.wittenberger.us" +EXPECTED_CN="mail.wittenberger.us" # guard against deploying the wrong cert +# --------------------------------------------------------------------------- + +SRC_CERT="${STAGING}/fullchain.pem" +SRC_KEY="${STAGING}/privkey.pem" +DST_CERT="${MAILCOW_SSL_DIR}/cert.pem" +DST_KEY="${MAILCOW_SSL_DIR}/key.pem" + +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } + +[[ -r "${SRC_CERT}" && -r "${SRC_KEY}" ]] || { log "No staged cert to deploy."; exit 0; } +[[ -d "${MAILCOW_SSL_DIR}" ]] || { log "ERROR: ssl dir missing: ${MAILCOW_SSL_DIR}"; exit 1; } + +# 1) verfiy cert/key match. +cert_pub=$(openssl x509 -in "${SRC_CERT}" -noout -pubkey 2>/dev/null | openssl md5) +key_pub=$(openssl pkey -in "${SRC_KEY}" -pubout 2>/dev/null | openssl md5) +[[ -n "${cert_pub}" && "${cert_pub}" == "${key_pub}" ]] || { log "ERROR: staged cert/key mismatch — aborting."; exit 1; } + +# 2) verify cert is actually be for the mail host (covers CN or SAN). +if ! openssl x509 -noout -text -in "${SRC_CERT}" | grep -q "${EXPECTED_CN}"; then + log "ERROR: staged cert does not cover ${EXPECTED_CN} — aborting." + exit 1 +fi + +# 3) only deploy on change. +new_fp=$(openssl x509 -noout -fingerprint -sha256 -in "${SRC_CERT}") +cur_fp="" +[[ -r "${DST_CERT}" ]] && cur_fp=$(openssl x509 -noout -fingerprint -sha256 -in "${DST_CERT}" 2>/dev/null || true) + +if [[ "${new_fp}" == "${cur_fp}" ]]; then + log "Cert unchanged; nothing to do." + exit 0 +fi + +log "Deploying new cert into mailcow." +install -m 0644 "${SRC_CERT}" "${DST_CERT}.tmp" && mv -f "${DST_CERT}.tmp" "${DST_CERT}" +install -m 0600 "${SRC_KEY}" "${DST_KEY}.tmp" && mv -f "${DST_KEY}.tmp" "${DST_KEY}" + +cd "${MAILCOW_DIR}" +log "Reloading postfix, dovecot, nginx." +docker compose exec -T postfix-mailcow postfix reload || log "WARN: postfix reload failed" +docker compose exec -T dovecot-mailcow dovecot reload || log "WARN: dovecot reload failed" +docker compose exec -T nginx-mailcow nginx -s reload || log "WARN: nginx reload failed" + +log "Done." \ No newline at end of file