#!/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."