diff --git a/push-mailcow-cert.sh b/push-mailcow-cert.sh new file mode 100644 index 0000000..2b00850 --- /dev/null +++ b/push-mailcow-cert.sh @@ -0,0 +1,48 @@ +#!/usr/bin/env bash +# +# push-mailcow-cert.sh (runs on Nginx Proxy Manager host) +# Pushes the npm-5 (mail.wittenberger.us) cert to the mailcow VM when it changes. +# +# Requires: an SSH key for a dedicated push user on the mailcow VM (see notes). + +set -euo pipefail + +# ---- CONFIG --------------------------------------------------------------- +NPM_CERT_DIR="/etc/nginx/letsencrypt/live/npm-5" # mail.wittenberger.us cert +MAILCOW_HOST="" # ssh host/alias or IP of mailcow VM +MAILCOW_SSH_USER="certsync" # dedicated low-priv user on mailcow VM +SSH_KEY="/root/.ssh/mailcow_certsync" # private key for that user +REMOTE_STAGING="/home/certsync/incoming" # staging dir on mailcow VM +# --------------------------------------------------------------------------- + +SRC_CERT="${NPM_CERT_DIR}/fullchain.pem" +SRC_KEY="${NPM_CERT_DIR}/privkey.pem" + +log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"; } + +[[ -r "${SRC_CERT}" ]] || { log "ERROR: cert not readable: ${SRC_CERT}"; exit 1; } +[[ -r "${SRC_KEY}" ]] || { log "ERROR: key not readable: ${SRC_KEY}"; exit 1; } + +# Track last-pushed fingerprint locally so it only pushes on change. +STATE_FILE="/var/lib/mailcow-cert-push/last_fp" +mkdir -p "$(dirname "${STATE_FILE}")" + +new_fp=$(openssl x509 -noout -fingerprint -sha256 -in "${SRC_CERT}") +cur_fp="" +[[ -r "${STATE_FILE}" ]] && cur_fp=$(cat "${STATE_FILE}") + +if [[ "${new_fp}" == "${cur_fp}" ]]; then + log "Cert unchanged; nothing to push." + exit 0 +fi + +log "Cert changed — pushing to ${MAILCOW_HOST}." + +# rsync both files into the staging dir. Trailing dot files copied with perms. +rsync -azL --chmod=F600 \ + -e "ssh -i ${SSH_KEY} -o StrictHostKeyChecking=accept-new" \ + "${SRC_CERT}" "${SRC_KEY}" \ + "${MAILCOW_SSH_USER}@${MAILCOW_HOST}:${REMOTE_STAGING}/" + +echo "${new_fp}" > "${STATE_FILE}" +log "Push complete." \ No newline at end of file