Commit fe8361c849

fe8361c849ca5ef2e1ef744718369976176c6107

parent: fff6fb16e4

Verified · cmc ci/build: success ci/test: failure ci/vuln: success

cmc <hello@cleberg.net> · 2026-09-01 05:00 UTC

monitor: read the ACME cache where it actually is, and report the soonest expiry

The cert check pointed at /var/lib/gitbay/autocert; the cache is
/var/lib/gitbay/acme, so it reported n/a on every run. Invisible until the
previous commit made the monitor log its reading.

It also took whichever name sorted first, which says nothing about the one
about to lapse. It now reports the soonest expiry across the cache and
alerts under 21 days, inside Let's Encrypt's 30-day renewal window, so a
stalled renewal surfaces while there is still time to act.

Verified on bay1: reports gitbay.org at 81 days, the soonest of 8 certs,
where the old script said n/a.

Ref #28

Layout: unified · split

deploy/cloud-init.yaml +24 −6
@@ -67,13 +67,28 @@ write_files:
67 set -eu 67 set -eu
68 disk=$(df -P /var/lib/gitbay | awk 'NR==2{print $5}') 68 disk=$(df -P /var/lib/gitbay | awk 'NR==2{print $5}')
69 svc=$(systemctl is-active gitbayd || true) 69 svc=$(systemctl is-active gitbayd || true)
70 # Days until the ACME cert expires, if autocert cached one. 70 # Soonest ACME cert expiry. Reporting whichever name sorted first said
71 cert=/var/lib/gitbay/autocert 71 # nothing about the one actually about to lapse, and the cache is under
72 # acme/, so this read autocert/ and reported n/a forever.
73 cert=/var/lib/gitbay/acme
72 exp="n/a" 74 exp="n/a"
75 days=""
73 if [ -d "$cert" ]; then 76 if [ -d "$cert" ]; then
74 f=$(ls -1 "$cert" 2>/dev/null | grep -v acme_account | head -1 || true) 77 soonest=""
75 if [ -n "$f" ]; then 78 for f in "$cert"/*; do
76 exp=$(openssl x509 -enddate -noout -in "$cert/$f" 2>/dev/null | cut -d= -f2 || echo n/a) 79 [ -f "$f" ] || continue
80 case "${f##*/}" in acme_account*) continue ;; esac
81 end=$(openssl x509 -enddate -noout -in "$f" 2>/dev/null | cut -d= -f2 || true)
82 [ -n "$end" ] || continue
83 secs=$(date -u -d "$end" +%s 2>/dev/null || true)
84 [ -n "$secs" ] || continue
85 if [ -z "$soonest" ] || [ "$secs" -lt "$soonest" ]; then
86 soonest="$secs"
87 exp="$end"
88 fi
89 done
90 if [ -n "$soonest" ]; then
91 days=$(( (soonest - $(date -u +%s)) / 86400 ))
77 fi 92 fi
78 fi 93 fi
79 alert="" 94 alert=""
@@ -84,9 +99,12 @@ write_files:
84 if [ "$pct" -ge 85 ]; then 99 if [ "$pct" -ge 85 ]; then
85 alert="${alert}disk ${disk}; " 100 alert="${alert}disk ${disk}; "
86 fi 101 fi
102 if [ -n "$days" ] && [ "$days" -lt 21 ]; then
103 alert="${alert}cert expires in ${days}d; "
104 fi
87 # journald always gets the reading, so an unset webhook cannot make a 105 # journald always gets the reading, so an unset webhook cannot make a
88 # sick host look like a quiet one. 106 # sick host look like a quiet one.
89 echo "disk=$disk service=$svc cert_expires=$exp" 107 echo "disk=$disk service=$svc cert_expires=$exp${days:+ cert_days=$days}"
90 url_file=/etc/gitbay/monitor.url 108 url_file=/etc/gitbay/monitor.url
91 if [ -f "$url_file" ]; then 109 if [ -f "$url_file" ]; then
92 body=$(printf '{"disk":"%s","service":"%s","cert_expires":"%s","alert":"%s"}' "$disk" "$svc" "$exp" "$alert") 110 body=$(printf '{"disk":"%s","service":"%s","cert_expires":"%s","alert":"%s"}' "$disk" "$svc" "$exp" "$alert")