A CLI-first git forge.

cli forge git self-hosted

https://gitbay.org

Commit fe8361c849

fe8361c849ca5ef2e1ef744718369976176c6107

parent: fff6fb16e4

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

cmc <hello@cleberg.net> · 2026-09-01T05:00:34Z

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
deploy/cloud-init.yaml +24 −6
@@ -67,13 +67,28 @@ write_files:
6767 set -eu
6868 disk=$(df -P /var/lib/gitbay | awk 'NR==2{print $5}')
6969 svc=$(systemctl is-active gitbayd || true)
70 # Days until the ACME cert expires, if autocert cached one.
71 cert=/var/lib/gitbay/autocert
70 # Soonest ACME cert expiry. Reporting whichever name sorted first said
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
7274 exp="n/a"
75 days=""
7376 if [ -d "$cert" ]; then
74 f=$(ls -1 "$cert" 2>/dev/null | grep -v acme_account | head -1 || true)
75 if [ -n "$f" ]; then
76 exp=$(openssl x509 -enddate -noout -in "$cert/$f" 2>/dev/null | cut -d= -f2 || echo n/a)
77 soonest=""
78 for f in "$cert"/*; do
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 ))
7792 fi
7893 fi
7994 alert=""
@@ -84,9 +99,12 @@ write_files:
8499 if [ "$pct" -ge 85 ]; then
85100 alert="${alert}disk ${disk}; "
86101 fi
102 if [ -n "$days" ] && [ "$days" -lt 21 ]; then
103 alert="${alert}cert expires in ${days}d; "
104 fi
87105 # journald always gets the reading, so an unset webhook cannot make a
88106 # 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}"
90108 url_file=/etc/gitbay/monitor.url
91109 if [ -f "$url_file" ]; then
92110 body=$(printf '{"disk":"%s","service":"%s","cert_expires":"%s","alert":"%s"}' "$disk" "$svc" "$exp" "$alert")