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