← Back to list

Carbonio LetsEncript ssl deploy on ubuntu 24.4

mkdir -p /etc/letsencrypt/cloudflare vi /etc/letsencrypt/cloudflare/credentials.ini

Dururustem · 2026-04-14 13:43 · 0 claps · 4.6 min read
#zextra #carbonio #zimbra #ssl-certificate
Open on Medium ↗
Wiki topics: 🔓 · Open Source 🌱 · Environment & Climate

Carbonio LetsEncript ssl deploy on ubuntu 24.4

mkdir -p /etc/letsencrypt/cloudflare vi /etc/letsencrypt/cloudflare/credentials.ini

dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN

chmod 600 /etc/letsencrypt/cloudflare/credentials.ini

apt install certbot

apt install python3-certbot-dns-cloudflare -y

certbot certonly \ — dns-cloudflare \ — dns-cloudflare-credentials /etc/letsencrypt/cloudflare/credentials.ini \ — dns-cloudflare-propagation-seconds 30 \ -d “example.com” \ -d “*.example.com” \ — email system@example.com \ — agree-tos \ — non-interactive

#!/usr/bin/env bash
#
# carbonio-deploy-if-cert-changed.sh   (Ubuntu 24.04 / yeni Carbonio)
# -----------------------------------------------------------------------------
# 1) Live sertifikanin kalan suresine bakar; <= RENEW_THRESHOLD_DAYS ise
#    zextras kullanicisi ile `certbot renew` calistirir.
# 2) Live ile deploy edilmis sertifikayi fingerprint uzerinden karsilastirir.
# 3) Farkliysa Carbonio'ya deploy eder.
# 4) systemd target'lari ile tum bilesenleri yeniden baslatir
#    (komple sunucu reboot etmeden).
# 5) Her servis icin port uzerinden SHA-256 fingerprint dogrulamasi yapar;
#    eslesmeyen olursa hedefli restart dener; hala olmuyorsa hata kodu ile cikar.
#
# Onerilen cron: 10 3 * * * /opt/scripts/carbonio-deploy-if-cert-changed.sh \
#                              >> /var/log/carbonio-cert-deploy.log 2>&1
# -----------------------------------------------------------------------------

set -euo pipefail

# ---- AYARLAR ----------------------------------------------------------------
DOMAIN="mail.example.com"
LIVE_DIR="/opt/zextras/common/certbot/etc/letsencrypt/live/${DOMAIN}"
LIVE_CERT="${LIVE_DIR}/cert.pem"

# zmcertmgr deploycrt'in fiilen yazdigi dosyalardan birini referans al.
DEPLOYED_PEM="/opt/zextras/conf/nginx.crt"

COMM_KEY_DST="/opt/zextras/ssl/carbonio/commercial/commercial.key"
TMP_DIR="/tmp"

# Certbot
CERTBOT_BIN="/opt/zextras/common/bin/certbot"
RENEW_THRESHOLD_DAYS=5

ISRG_URL="https://letsencrypt.org/certs/isrgrootx1.pem.txt"
LOCK_FILE="/var/lock/carbonio-deploy-if-cert-changed.lock"

# Carbonio systemd target'lari (Ubuntu 24.04)
UMBRELLA_TARGET="carbonio.target"
LDAP_TARGET="carbonio-directory-server.target"
MTA_TARGET="carbonio-mta.target"
PROXY_TARGET="carbonio-proxy.target"
APPSERVER_TARGET="carbonio-appserver.target"

# Dogrulanacak (port|label|openssl-extra) listesi
declare -a VERIFY_TARGETS=(
  "443|HTTPS-proxy|"
  "993|IMAPS|"
  "995|POP3S|"
  "465|SMTPS|"
  "25|SMTP-STARTTLS|-starttls smtp"
  "587|Submission-STARTTLS|-starttls smtp"
  "389|LDAP-STARTTLS|-starttls ldap"
)

# Restart sonrasi dogrulamadan once beklenecek sure (saniye)
SETTLE_SECONDS=30
# -----------------------------------------------------------------------------

log() { echo "[$(date -u '+%Y-%m-%d %H:%M:%S UTC')] $*"; }

# ---- Lock + on kontroller --------------------------------------------------
exec 9>"$LOCK_FILE"
flock -n 9 || { log "Baska bir kopya calisiyor, cikiliyor."; exit 0; }

if [[ $EUID -ne 0 ]]; then
  log "HATA: Bu script root olarak calismali."
  exit 1
fi

[[ -f "$LIVE_CERT"    ]] || { log "HATA: Live cert yok: $LIVE_CERT"; exit 1; }
[[ -f "$DEPLOYED_PEM" ]] || { log "HATA: Deployed cert yok: $DEPLOYED_PEM"; exit 1; }
[[ -x "$CERTBOT_BIN"  ]] || { log "HATA: certbot bulunamadi: $CERTBOT_BIN"; exit 1; }

# ---- Yardimci fonksiyonlar -------------------------------------------------
fp_of_file() {
  openssl x509 -in "$1" -noout -fingerprint -sha256 2>/dev/null \
    | awk -F= '{print $2}' | tr -d ':'
}

fp_of_port() {
  local port="$1" extra="$2"
  echo | timeout 8 openssl s_client ${extra} -connect "127.0.0.1:${port}" \
    -servername "$DOMAIN" 2>/dev/null \
    | openssl x509 -noout -fingerprint -sha256 2>/dev/null \
    | awk -F= '{print $2}' | tr -d ':'
}

dates_of_port() {
  local port="$1" extra="$2"
  echo | timeout 8 openssl s_client ${extra} -connect "127.0.0.1:${port}" \
    -servername "$DOMAIN" 2>/dev/null \
    | openssl x509 -noout -dates -subject 2>/dev/null
}

restart_target() {
  local tgt="$1"
  if systemctl list-unit-files "$tgt" --quiet 2>/dev/null | grep -q "$tgt"; then
    log "  systemctl restart $tgt"
    systemctl restart "$tgt" || { log "  HATA: $tgt restart edilemedi"; return 1; }
  else
    log "  $tgt bulunamadi, atlaniyor"
  fi
  return 0
}

# ---- 1) Sure kontrolu + gerekirse certbot renew ----------------------------
NOT_AFTER_EPOCH=$(date -d "$(openssl x509 -in "$LIVE_CERT" -noout -enddate | cut -d= -f2)" +%s)
NOW_EPOCH=$(date -u +%s)
DAYS_LEFT=$(( (NOT_AFTER_EPOCH - NOW_EPOCH) / 86400 ))

log "Live cert son gecerlilik: $(date -d "@${NOT_AFTER_EPOCH}" -u '+%Y-%m-%d %H:%M:%S UTC')  (${DAYS_LEFT} gun kaldi)"

if (( DAYS_LEFT <= RENEW_THRESHOLD_DAYS )); then
  log "Esik (${RENEW_THRESHOLD_DAYS} gun) altinda. zextras ile certbot renew calistiriliyor..."
  if su - zextras -c "${CERTBOT_BIN} renew --non-interactive"; then
    log "certbot renew tamamlandi."
  else
    log "UYARI: certbot renew basarisiz. Yine de deploy karsilastirmasina devam ediliyor."
  fi
else
  log "Sure yeterli (${DAYS_LEFT} > ${RENEW_THRESHOLD_DAYS}). certbot renew atlandi."
fi

# ---- 2) Fingerprint karsilastirmasi ----------------------------------------
LIVE_FP=$(fp_of_file "$LIVE_CERT")
DEPLOYED_FP=$(fp_of_file "$DEPLOYED_PEM")

[[ -n "${LIVE_FP:-}"     ]] || { log "HATA: Live fingerprint okunamadi";     exit 1; }
[[ -n "${DEPLOYED_FP:-}" ]] || { log "HATA: Deployed fingerprint okunamadi"; exit 1; }

log "LIVE     FP: $LIVE_FP"
log "DEPLOYED FP: $DEPLOYED_FP"

if [[ "$LIVE_FP" == "$DEPLOYED_FP" ]]; then
  log "Sertifika ayni, deploy gerekmez. Cikiliyor."
  exit 0
fi

log "Sertifika farkli! Deploy islemi basliyor..."

# ---- 3) Dosya hazirligi ----------------------------------------------------
for f in "$LIVE_DIR/privkey.pem" "$LIVE_DIR/cert.pem" "$LIVE_DIR/fullchain.pem"; do
  [[ -f "$f" ]] || { log "HATA: Kaynak dosya yok: $f"; exit 1; }
done

cp -fL "$LIVE_DIR/privkey.pem"   "$COMM_KEY_DST"
chown zextras:zextras            "$COMM_KEY_DST"
chmod 600                        "$COMM_KEY_DST"

cp -fL "$LIVE_DIR/cert.pem"      "$TMP_DIR/commercial.pem"
chown zextras:zextras            "$TMP_DIR/commercial.pem"

cp -fL "$LIVE_DIR/fullchain.pem" "$TMP_DIR/fullchain.pem"
chown zextras:zextras            "$TMP_DIR/fullchain.pem"

wget --no-check-certificate -q -O "$TMP_DIR/ISRG-X1.pem" "$ISRG_URL" \
  || { log "HATA: ISRG Root indirilemedi"; exit 1; }

cat "$TMP_DIR/fullchain.pem" "$TMP_DIR/ISRG-X1.pem" > "$TMP_DIR/zextras_ca.pem"
chown zextras:zextras "$TMP_DIR/zextras_ca.pem"

# ---- 4) Deploy -------------------------------------------------------------
su - zextras -c "cd /tmp && /opt/zextras/bin/zmcertmgr verifycrt comm \
  /opt/zextras/ssl/carbonio/commercial/commercial.key \
  /tmp/commercial.pem \
  /tmp/zextras_ca.pem"

su - zextras -c "cd /tmp && /opt/zextras/bin/zmcertmgr deploycrt comm \
  /tmp/commercial.pem \
  /tmp/zextras_ca.pem"

# mailboxd.pem deploycrt tarafindan guncellenMEZ; tutarlilik icin elle senkronla
cp -fL "$LIVE_DIR/fullchain.pem" /opt/zextras/mailboxd/etc/mailboxd.pem
chown zextras:zextras            /opt/zextras/mailboxd/etc/mailboxd.pem
chmod 644                        /opt/zextras/mailboxd/etc/mailboxd.pem

# ---- 5) TUM Carbonio bilesenlerini yeniden baslat --------------------------
# Onerilen: umbrella target'i restart et -- tum alt target'lari (ldap, mta,
# proxy, appserver) systemd dogru bagimlilik sirasinda yeniden baslatir.
# Bu, sunucu reboot'una en yakin temiz yontemdir.
log "Tum Carbonio bilesenleri yeniden baslatiliyor (${UMBRELLA_TARGET})..."

if systemctl list-unit-files "$UMBRELLA_TARGET" --quiet 2>/dev/null | grep -q "$UMBRELLA_TARGET"; then
  if systemctl restart "$UMBRELLA_TARGET"; then
    log "${UMBRELLA_TARGET} restart tamamlandi."
  else
    log "UYARI: ${UMBRELLA_TARGET} restart hata verdi. Tek tek deniyorum..."
    restart_target "$LDAP_TARGET"      || true
    restart_target "$MTA_TARGET"       || true
    restart_target "$PROXY_TARGET"     || true
    restart_target "$APPSERVER_TARGET" || true
  fi
else
  log "${UMBRELLA_TARGET} bulunamadi. Alt target'lar tek tek restart ediliyor..."
  restart_target "$LDAP_TARGET"      || true
  restart_target "$MTA_TARGET"       || true
  restart_target "$PROXY_TARGET"     || true
  restart_target "$APPSERVER_TARGET" || true
fi

# ---- 6) Settle bekle -------------------------------------------------------
log "Servislerin oturmasi icin ${SETTLE_SECONDS} sn bekleniyor..."
sleep "$SETTLE_SECONDS"

# ---- 7) Port bazinda fingerprint dogrulamasi -------------------------------
log "Port bazinda fingerprint dogrulamasi:"

ALL_OK=1
declare -a FAILED_PORTS=()

for entry in "${VERIFY_TARGETS[@]}"; do
  IFS='|' read -r port label extra <<< "$entry"
  port_fp=$(fp_of_port "$port" "$extra" || true)
  if [[ -z "$port_fp" ]]; then
    log "  [$label :$port] BAGLANTI YOK / cert okunamadi (servis kapali olabilir, atlaniyor)"
    continue
  fi
  if [[ "$port_fp" == "$LIVE_FP" ]]; then
    log "  [$label :$port] OK"
  else
    log "  [$label :$port] HATALI: port=$port_fp"
    log "    $(dates_of_port "$port" "$extra")"
    FAILED_PORTS+=("$entry")
    ALL_OK=0
  fi
done

# ---- 8) Eslesmeyenler icin ikinci tur hedefli restart ----------------------
if (( ALL_OK == 0 )); then
  log "Eslesmeyen portlar var. Hedefli ikinci tur restart deneniyor..."

  # Eslesmeyen portlara gore hangi target'lari restart edecegimizi belirle
  declare -A NEED_RESTART=()
  for entry in "${FAILED_PORTS[@]}"; do
    IFS='|' read -r port _ _ <<< "$entry"
    case "$port" in
      25|465|587)  NEED_RESTART["$MTA_TARGET"]=1 ;;
      443)         NEED_RESTART["$PROXY_TARGET"]=1 ;;
      993|995)     NEED_RESTART["$APPSERVER_TARGET"]=1 ;;
      389)         NEED_RESTART["$LDAP_TARGET"]=1 ;;
    esac
  done

  for tgt in "${!NEED_RESTART[@]}"; do
    log "  -> $tgt"
    restart_target "$tgt" || true
  done

  log "Ikinci settle bekleyisi: ${SETTLE_SECONDS} sn..."
  sleep "$SETTLE_SECONDS"

  log "Yeniden dogrulama:"
  ALL_OK=1
  for entry in "${FAILED_PORTS[@]}"; do
    IFS='|' read -r port label extra <<< "$entry"
    port_fp=$(fp_of_port "$port" "$extra" || true)
    if [[ "$port_fp" == "$LIVE_FP" ]]; then
      log "  [$label :$port] OK"
    else
      log "  [$label :$port] HALA HATALI"
      ALL_OK=0
    fi
  done
fi

# ---- 9) Sonuc --------------------------------------------------------------
NEW_DEPLOYED_FP=$(fp_of_file "$DEPLOYED_PEM")
log "Yeni DEPLOYED FP: $NEW_DEPLOYED_FP"

if (( ALL_OK == 1 )); then
  log "BASARILI: Tum servisler yeni sertifikayi serve ediyor."
  exit 0
else
  log "KRITIK: Bazi servisler hala eski sertifikayi serve ediyor!"
  log "        Onerilen: 'systemctl stop ${UMBRELLA_TARGET} && systemctl start ${UMBRELLA_TARGET}'"
  log "        veya son care olarak sunucu reboot."
  # Opsiyonel uyari kanali (mail/webhook) buraya eklenebilir.
  # echo "Carbonio cert deploy basarisiz: $DOMAIN" | mail -s "ALERT" admin@example.com
  exit 2
fi

chmod u+x /opt/scripts/carbonio-deploy-if-cert-changed.sh

crontab -e

10 3 * * * /opt/scripts/carbonio-deploy-if-cert-changed.sh >> /var/log/carbonio-cert-deploy.log 2>&1

메타데이터
post_id
9c99b0e52f6d
slug
carbonio-letsencript-ssl-deploy-on-ubuntu-24-4-9c99b0e52f6d
url
https://medium.com/@dururustem68/carbonio-letsencript-ssl-deploy-on-ubuntu-24-4-9c99b0e52f6d
canonical_url
https://medium.com/@dururustem68/carbonio-letsencript-ssl-deploy-on-ubuntu-24-4-9c99b0e52f6d
author_url
https://medium.com/@dururustem68
status
ok
fetched_at
2026-07-16 00:55:23