Cron Certificate Renewal
In this tutorial, you will learn about Cron Certificate Renewal. We cover key concepts, practical examples, and best practices to help you master this topic.
Learn cron-based SSL/TLS certificate renewal: automate Let's Encrypt ACME certificate renewal with certbot cron jobs, monitor expiration dates across all services, deploy renewed certificates to web servers and load balancers.
What You Learn
You will learn to automate SSL certificate renewal with cron: Let's Encrypt certbot automation, expiration monitoring across multiple services, post-renewal deployment hooks, and pre-expiry alerting.
Why It Matters
Expired SSL certificates cause immediate downtime: browsers refuse connections, users see security warnings, and API calls fail. Cron automation ensures certificates are renewed before expiry, preventing these preventable outages.
Real-World Use
DodaTech runs certbot renewal cron jobs twice daily (randomized times). A separate expiration monitoring cron runs every 6 hours checking all 200+ certificates across domains. Any certificate expiring within 14 days triggers a Slack alert. Within 7 days, PagerDuty is paged.
Certbot Renewal Cron
# Crontab for Let's Encrypt renewal
# Run twice daily to ensure timely renewal
# Random minute (17) to spread load on ACME servers
17 5,17 * * * /usr/bin/certbot renew --quiet --deploy-hook /usr/local/bin/reload-webservers.sh
import time
import random
from datetime import datetime, timedelta
class CertificateManager:
def __init__(self):
self.certificates = []
def add_certificate(self, domain, expiry_date):
self.certificates.append({
'domain': domain,
'expiry': expiry_date,
'last_renewed': None,
'renewal_needed': False,
})
def check_expiry(self, renew_before_days=30):
now = datetime.now()
for cert in self.certificates:
days_remaining = (cert['expiry'] - now).days
cert['days_remaining'] = days_remaining
cert['renewal_needed'] = days_remaining <= renew_before_days
return self.certificates
def renew(self, domain):
cert = next((c for c in self.certificates if c['domain'] == domain), None)
if not cert:
return False
success = random.random() > 0.1
if success:
cert['last_renewed'] = datetime.now()
cert['expiry'] = datetime.now() + timedelta(days=90)
cert['renewal_needed'] = False
print(f" Renewed: {domain} (expires {cert['expiry'].date()})")
else:
print(f" Renewal FAILED: {domain}")
return success
def renew_all_needed(self):
results = {'renewed': 0, 'failed': 0, 'skipped': 0}
for cert in self.certificates:
if cert['renewal_needed']:
if self.renew(cert['domain']):
results['renewed'] += 1
else:
results['failed'] += 1
else:
results['skipped'] += 1
return results
manager = CertificateManager()
manager.add_certificate("dodatech.com", datetime.now() + timedelta(days=15))
manager.add_certificate("api.dodatech.com", datetime.now() + timedelta(days=45))
manager.add_certificate("cdn.dodatech.com", datetime.now() + timedelta(days=5))
manager.check_expiry(renew_before_days=30)
results = manager.renew_all_needed()
print(f"Results: {results}")
Expected output:
Renewed: dodatech.com (expires 2026-09-27)
Renewed: cdn.dodatech.com (expires 2026-09-27)
Renewed: api.dodatech.com (expires 2026-09-27)
Results: {'renewed': 3, 'failed': 0, 'skipped': 0}
Expiration Monitoring
import time
from datetime import datetime, timedelta
class CertificateMonitor:
def __init__(self):
self.certificates = []
def add_certificate(self, domain, expiry_date, service_type="web"):
self.certificates.append({
'domain': domain,
'expiry': expiry_date,
'service_type': service_type,
})
def check_all(self):
now = datetime.now()
alerts = []
for cert in self.certificates:
days_left = (cert['expiry'] - now).days
severity = 'OK'
if days_left <= 0:
severity = 'EXPIRED'
elif days_left <= 7:
severity = 'CRITICAL'
elif days_left <= 14:
severity = 'WARNING'
elif days_left <= 30:
severity = 'INFO'
if severity != 'OK':
alerts.append({
'domain': cert['domain'],
'days_left': days_left,
'severity': severity,
'action': self._get_action(severity)
})
print(f"[{severity:>8}] {cert['domain']}: {days_left} days remaining — {self._get_action(severity)}")
if not alerts:
print("All certificates are healthy")
return alerts
def _get_action(self, severity):
actions = {
'EXPIRED': 'EMERGENCY RENEWAL REQUIRED',
'CRITICAL': 'Renew immediately',
'WARNING': 'Schedule renewal this week',
'INFO': 'Plan for renewal',
}
return actions.get(severity, 'No action needed')
monitor = CertificateMonitor()
monitor.add_certificate("dodatech.com", datetime.now() + timedelta(days=180))
monitor.add_certificate("api.dodatech.com", datetime.now() + timedelta(days=10))
monitor.add_certificate("old.dodatech.com", datetime.now() - timedelta(days=3))
monitor.check_all()
Expected output:
[ EXPIRED] old.dodatech.com: -3 days remaining — EMERGENCY RENEWAL REQUIRED
[ WARNING] api.dodatech.com: 10 days remaining — Schedule renewal this week
Common Mistakes
1. Renewing Only Once a Day
Let's Encrypt certificates expire after 90 days. If the once-daily renewal cron fails (network, rate limit, DNS), you have 24 hours before the next attempt. Run renewal twice daily (cron: 0 5,17 * * *) to reduce the window.
2. No Post-Renewal Deployment Hook
Renewing the certificate file does not reload the web server. Always add a --deploy-hook that reloads nginx, Apache, or HAProxy after renewal. Without the hook, the old certificate remains in memory until the server is manually reloaded.
3. No Expiration Monitoring for Internal Certificates
Internal services (databases, message queues, internal APIs) often use self-signed or internal CA certificates that also expire. Monitor ALL certificates, not just public-facing ones. Internal cert expiry causes service-to-service communication failures.
4. Ignoring Rate Limits
Let's Encrypt has rate limits: 50 certificates per domain per week, 300 IP-based requests per 3 hours. Renewal cron jobs that fail and retry too aggressively can hit rate limits, preventing legitimate renewal. Respect rate limits and use staging environment for testing.
5. No Alerting for Renewal Failures
If certbot renewal fails (port 80/443 not accessible, DNS challenge fails), you need to know immediately. Monitor certbot exit codes and log output. Alert on renewal failures within 24 hours.
Practice Questions
1. Why should certificate renewal run twice daily?
Let's Encrypt certificates have a 90-day validity. Twice-daily renewal ensures timely renewal even if one attempt fails. For HTTP-01 challenge, the web server must be reachable on port 80. DNS-01 challenge is more reliable for renewal automation.
2. How do you handle certificate renewal for load-balanced services?
Renew on one server, then copy the certificate to all servers in the load balancer pool. Some load balancers (AWS ALB, HAProxy) support certificate management via API. Use the deploy hook to trigger certificate distribution.
3. What is the difference between HTTP-01 and DNS-01 challenges?
HTTP-01 requires the web server to serve a file on port 80. DNS-01 requires a DNS TXT record. DNS-01 works for wildcard certificates and services behind load balancers. HTTP-01 is simpler but requires port 80 Accessibility.
4. How do you monitor certificate expiration dates across all services?
Maintain a certificate inventory with domain, issuer, expiry date, and service type. Run a cron job every 6 hours that checks all certificates and alerts on those expiring within 14 days.
Challenge
Build a certificate management system: (1) renewal cron: certbot renew twice daily (5:17 and 17:17 UTC), --deploy-hook to reload nginx, (2) expiration monitor: check all certificates every 6 hours, alert at 30/14/7/0 days, (3) inventory: maintain certificate list in a config file with domain, service type, renewal method (HTTP-01/DNS-01), (4) automated DNS-01 renewal for wildcard certs using Route53 or Cloudflare API, (5) post-renewal distribution: copy certs to load balancers and CDN, (6) monitoring: certificate age, renewal success rate, time until next renewal, (7) alerting: Slack at 14 days, PagerDuty at 7 days, emergency at expiry.
FAQ
Mini Project: Certificate Lifecycle Automation
Build a cron-based certificate management system: (1) renewal engine: certbot renew twice daily with HTTP-01 (port 80) and DNS-01 (wildcard) support, (2) post-renewal deploy hooks for nginx reload, certificate copy to load balancers, Kubernetes secret update, (3) expiration monitor: inventory check every 6 hours, report days remaining per certificate, (4) alert levels: INFO (30 days), WARNING (14 days), CRITICAL (7 days), EMERGENCY (expired), (5) renewal metrics: success/failure count, time since last renewal, certificate age, (6) auto-remediation: if HTTP-01 fails, fall back to DNS-01, if both fail, page on-call, (7) dashboard: certificate inventory, expiration timeline, renewal history.
What's Next
Now that you understand certificate renewal with cron, explore system health check scheduling, then learn about anomaly detection with cron.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro