Автообновление — это хорошо, но что если certbot не сможет обновить сертификат (например, DNS недоступен или API Cloudflare вернул ошибку)? Нужен независимый мониторинг, который заблаговременно предупредит об истечении.
Мы написали скрипт, который проверяет все сертификаты снаружи (через реальное TLS-подключение) и изнутри (файлы на диске):
#!/bin/bash
# /opt/scripts/check-ssl-expiry.sh
# Проверяет SSL-сертификаты всех доменов и алертит при приближении срока
DOMAINS=(
"mebel-store.ru"
"stroydom-kazan.ru"
"kazan-flowers.ru"
"auto-parts-kzn.ru"
"beauty-salon-kazan.ru"
"restoran-kazanochka.ru"
# ... все 45 доменов
)
WARN_DAYS=21 # Предупреждение за 21 день
CRIT_DAYS=7 # Критический алерт за 7 дней
BOT_TOKEN="YOUR_BOT_TOKEN"
CHAT_ID="YOUR_CHAT_ID"
LOGFILE="/var/log/ssl-check.log"
echo "[$(date '+%Y-%m-%d %H:%M:%S')] SSL check started" >> "$LOGFILE"
for domain in "${DOMAINS[@]}"; do
# Получаем дату истечения через TLS-подключение
EXPIRY=$(echo | openssl s_client -servername "$domain" -connect "$domain":443 2>/dev/null \
| openssl x509 -noout -enddate 2>/dev/null | cut -d= -f2)
if [ -z "$EXPIRY" ]; then
MSG="SSL CHECK FAILED: $domain — не удалось подключиться"
echo "[$(date)] $MSG" >> "$LOGFILE"
curl -s "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" -d text="$MSG" > /dev/null
continue
fi
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
if [ $DAYS_LEFT -lt 0 ]; then
MSG="SSL EXPIRED: $domain истёк $((DAYS_LEFT * -1)) дней назад!"
curl -s "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" -d text="$MSG" > /dev/null
elif [ $DAYS_LEFT -lt $CRIT_DAYS ]; then
MSG="SSL CRITICAL: $domain истекает через $DAYS_LEFT дней ($EXPIRY)"
curl -s "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" -d text="$MSG" > /dev/null
elif [ $DAYS_LEFT -lt $WARN_DAYS ]; then
MSG="SSL WARNING: $domain истекает через $DAYS_LEFT дней ($EXPIRY)"
curl -s "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
-d chat_id="${CHAT_ID}" -d text="$MSG" > /dev/null
fi
echo "[$(date)] $domain: $DAYS_LEFT дней" >> "$LOGFILE"
done
echo "[$(date '+%Y-%m-%d %H:%M:%S')] SSL check completed" >> "$LOGFILE"
# Добавляем в cron (ежедневная проверка в 9:00)
echo '0 9 * * * root /opt/scripts/check-ssl-expiry.sh' | sudo tee /etc/cron.d/ssl-check
sudo chmod 644 /etc/cron.d/ssl-check
Для более продвинутого мониторинга мы развернули blackbox_exporter — компонент Prometheus для проверки внешних эндпоинтов:
# Установка blackbox_exporter
wget https://github.com/prometheus/blackbox_exporter/releases/download/v0.25.0/blackbox_exporter-0.25.0.linux-amd64.tar.gz
tar xvf blackbox_exporter-0.25.0.linux-amd64.tar.gz
sudo mv blackbox_exporter-0.25.0.linux-amd64/blackbox_exporter /usr/local/bin/
# Конфигурация blackbox_exporter
sudo tee /etc/blackbox_exporter/config.yml > /dev/null <<'EOF'
modules:
http_2xx_ssl:
prober: http
timeout: 10s
http:
valid_http_versions: ["HTTP/1.1", "HTTP/2.0"]
valid_status_codes: [200, 301, 302]
method: GET
tls_config:
insecure_skip_verify: false
fail_if_ssl: false
fail_if_not_ssl: true
EOF
# Systemd unit
sudo tee /etc/systemd/system/blackbox-exporter.service > /dev/null <<'EOF'
[Unit]
Description=Blackbox Exporter
After=network.target
[Service]
ExecStart=/usr/local/bin/blackbox_exporter --config.file=/etc/blackbox_exporter/config.yml
Restart=always
User=nobody
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now blackbox-exporter
Конфигурация Prometheus для сбора SSL-метрик:
# Добавляем в /etc/prometheus/prometheus.yml
- job_name: 'ssl-monitoring'
metrics_path: /probe
params:
module: [http_2xx_ssl]
static_configs:
- targets:
- https://mebel-store.ru
- https://stroydom-kazan.ru
- https://kazan-flowers.ru
- https://auto-parts-kzn.ru
- https://beauty-salon-kazan.ru
# ... все 45 доменов
relabel_configs:
- source_labels: [__address__]
target_label: __param_target
- source_labels: [__param_target]
target_label: instance
- target_label: __address__
replacement: localhost:9115 # blackbox_exporter
# Алерты для SSL в Prometheus
# /etc/prometheus/rules/ssl_alerts.yml
groups:
- name: ssl
rules:
- alert: SSLCertExpiringSoon
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 21
for: 1h
labels:
severity: warning
annotations:
summary: "SSL сертификат {{ $labels.instance }} истекает менее чем через 21 день"
description: "Осталось {{ $value | humanizeDuration }}"
- alert: SSLCertExpireCritical
expr: probe_ssl_earliest_cert_expiry - time() < 86400 * 7
for: 10m
labels:
severity: critical
annotations:
summary: "SSL сертификат {{ $labels.instance }} истекает менее чем через 7 дней!"
- alert: SSLCertExpired
expr: probe_ssl_earliest_cert_expiry - time() < 0
for: 1m
labels:
severity: critical
annotations:
summary: "SSL сертификат {{ $labels.instance }} ИСТЁК!"
- alert: SSLProbeFailure
expr: probe_success{job="ssl-monitoring"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Не удалось подключиться к {{ $labels.instance }} по HTTPS"