As of today, the maximum validity period for a publicly trusted SSL/TLS certificate is 200 days. If you're still renewing certificates manually — logging into a portal, generating a CSR, waiting for approval, uploading the new cert — you're already on borrowed time. In a year it drops to 100 days. By 2029 it'll be 47.
This isn't a surprise announcement. The CA/Browser Forum passed the ballot that set this roadmap back in 2025, with Apple as its primary driver. The argument is sound: shorter lifespans mean faster propagation of revocations, less exposure from compromised keys, and a forcing function for automation that the industry has needed for years. The fact that it's uncomfortable for organisations that haven't automated is the point.
The timeline
The validity reductions follow a fixed schedule:
- March 2026 — Maximum validity drops to 200 days (down from 398)
- March 2027 — Maximum validity drops to 100 days
- March 2029 — Maximum validity drops to 47 days
Domain Control Validation (DCV) reuse periods reduce on the same schedule. At 47 days, a certificate has to be reissued roughly every 6 weeks. Manual renewal at that cadence is not a workflow — it's a full-time job waiting for something to go wrong at 2am.
Why this matters now
Organisations that deployed certificates with 398-day validity in early 2025 will be hitting their first 200-day renewals shortly. Many have never had to think about renewal frequency before. A certificate that used to be a once-a-year task becomes a several-times-a-year task, and then — at 47 days — a continuous background process that has to be reliable without human involvement.
The practical consequences of getting this wrong are significant. An expired certificate on a public-facing service kills revenue, triggers browser warnings that destroy user trust, and — in regulated industries — can constitute a compliance incident. Manual processes introduce exactly the kind of human-error risk that automation eliminates.
Automating with Let's Encrypt
Let's Encrypt was built around automation from day 1. It uses the ACME protocol (RFC 8555), issues certificates free of charge, and limits validity to 90 days — which means anyone using Let's Encrypt has already been forced to automate. If you're not on Let's Encrypt but want a low-cost path to automated renewal, it's the obvious starting point.
Certbot on RHEL / Rocky / AlmaLinux
Certbot is the canonical ACME client. On RHEL 9 and compatible distributions running Nginx, install via EPEL and the official Snap or the certbot RPM:
# Enable EPEL and install Certbot with the Nginx plugin
dnf install -y epel-release
dnf install -y certbot python3-certbot-nginx
# Issue a certificate (handles Nginx configuration automatically)
certbot --nginx -d example.com -d www.example.com
# Test renewal without making changes
certbot renew --dry-run
Certbot installs a systemd timer on RHEL 8+ that runs certbot renew twice daily. Certificates are only actually renewed when they have fewer than 30 days remaining. Check the timer is active:
systemctl status certbot.timer
systemctl enable --now certbot.timer
On RHEL 7 or where systemd timers aren't in use, the installer falls back to a cron job in /etc/cron.d/certbot.
Certbot with DNS challenge
If your infrastructure doesn't give Certbot direct access to your web server, the DNS challenge is more flexible — it proves domain ownership via a DNS TXT record rather than an HTTP request:
certbot certonly \
--manual \
--preferred-challenges dns \
-d example.com \
-d *.example.com
For fully automated DNS challenges with Route 53, install the DNS plugin:
dnf install -y python3-certbot-dns-route53
certbot certonly \
--dns-route53 \
-d example.com \
-d *.example.com
This approach works well in pipelines — you can run renewal as a scheduled GitHub Actions workflow or an AWS Lambda function triggered by EventBridge.
acme.sh as a lightweight alternative
For environments where you want something less opinionated than Certbot, acme.sh is a pure shell script ACME client with broad DNS provider support and no external dependencies beyond curl and openssl, which are present on all RHEL variants:
# Install
curl https://get.acme.sh | sh
source ~/.bashrc
# Issue with DNS validation via Route 53
export AWS_ACCESS_KEY_ID="your-key"
export AWS_SECRET_ACCESS_KEY="your-secret"
acme.sh --issue --dns dns_aws -d example.com -d *.example.com
# Install certificate to Nginx and reload on renewal
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.crt \
--reloadcmd "systemctl reload nginx"
acme.sh installs a cron job under the installing user on first run. The --reloadcmd hook ensures your web server picks up the new certificate automatically after each renewal.
On SELinux-enabled RHEL systems (the default), ensure the certificate files are in a location with the correct context, or set it explicitly:
semanage fcontext -a -t cert_t "/etc/nginx/ssl(/.*)?"
restorecon -Rv /etc/nginx/ssl
Automating with DigiCert
DigiCert sits at the other end of the spectrum — paid certificates, organisation validation (OV) and extended validation (EV) options, and the kind of audit trail that regulated industries require. The fully automated path uses either DigiCert's ACME service or their REST API via CertCentral.
DigiCert ACME
DigiCert supports the ACME protocol for DV certificates through CertCentral. Once you've configured an ACME division in your CertCentral account and retrieved your ACME credentials, the client setup is almost identical to Let's Encrypt — just pointing at a different directory URL.
Using acme.sh with DigiCert's ACME endpoint:
acme.sh --register-account \
--server https://acme.digicert.com/v2/OV/directory \
-m admin@example.com
acme.sh --issue \
--server https://acme.digicert.com/v2/OV/directory \
--dns dns_aws \
-d example.com
For Certbot, use the --server flag to point at DigiCert's ACME directory:
certbot certonly \
--server https://acme.digicert.com/v2/OV/directory \
--dns-route53 \
-d example.com
DigiCert CertCentral API
For OV/EV certificates, or where you need programmatic control over the full issuance lifecycle, the CertCentral REST API gives you complete automation. Install the requests library via pip or your system package manager, then a typical renewal flow in Python:
dnf install -y python3-pip
pip3 install requests
import requests
from datetime import datetime, timedelta
DIGICERT_API_KEY = "your-api-key"
BASE_URL = "https://www.digicert.com/services/v2"
headers = {
"X-DC-DEVKEY": DIGICERT_API_KEY,
"Content-Type": "application/json",
}
def list_expiring_certificates(days_ahead=60):
"""Return certificates expiring within the next N days."""
response = requests.get(
f"{BASE_URL}/certificate",
headers=headers,
params={"filters[status]": "issued"}
)
response.raise_for_status()
expiry_threshold = datetime.utcnow() + timedelta(days=days_ahead)
expiring = []
for cert in response.json().get("certificates", []):
expiry = datetime.strptime(cert["valid_till"], "%Y-%m-%dT%H:%M:%S+00:00")
if expiry <= expiry_threshold:
expiring.append(cert)
return expiring
def renew_certificate(order_id):
"""Submit a renewal request for an existing order."""
response = requests.post(
f"{BASE_URL}/order/certificate/{order_id}/renew",
headers=headers,
json={}
)
response.raise_for_status()
return response.json()
if __name__ == "__main__":
expiring = list_expiring_certificates(days_ahead=60)
for cert in expiring:
print(f"Renewing: {cert['common_name']} (expires {cert['valid_till']})")
result = renew_certificate(cert["order_id"])
print(f" → New order ID: {result['id']}")
Deploy this as a systemd timer for reliable scheduling on RHEL:
# /etc/systemd/system/cert-renew.service
[Unit]
Description=DigiCert certificate renewal check
[Service]
Type=oneshot
ExecStart=/usr/bin/python3 /opt/cert-renew/renew.py
# /etc/systemd/system/cert-renew.timer
[Unit]
Description=Run DigiCert renewal check daily
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.target
systemctl enable --now cert-renew.timer
AWS Certificate Manager
ACM sits in its own category and it's worth treating separately, because the renewal story is very different depending on how you're using it.
Non-exportable certificates: nothing to do
If you're using ACM-provisioned public certificates with eligible AWS services — Application Load Balancers, CloudFront distributions, API Gateway, Elastic Beanstalk — ACM renews them automatically. There is no action required on your part. AWS handles validation renewal and certificate rotation without any downtime or intervention.
This is the best possible outcome and one of the strongest arguments for terminating TLS at the AWS layer rather than on your instances. The shortening validity timeline has zero operational impact if you're in this position.
The one caveat: if an ACM certificate isn't currently attached to an AWS resource, automatic renewal may require you to re-validate domain ownership. ACM will attempt DNS or email validation and will flag the certificate in the console if it can't complete renewal unattended. Keep DNS validation records in place — if you used Route 53 to validate, ACM can renew entirely automatically as long as the CNAME record exists.
Exportable certificates: automation required
Exportable ACM certificates — issued through ACM Private CA — behave differently. Because the private key leaves AWS, ACM cannot rotate them on your behalf. Renewal and redeployment are your responsibility.
The workflow is: request a renewed certificate from Private CA, export it, and redeploy it to wherever it's installed. The AWS CLI covers all of this.
Check expiry across your certificate inventory:
# List all issued certificates with expiry dates
aws acm list-certificates \
--certificate-statuses ISSUED \
--region eu-west-2 \
--query 'CertificateSummaryList[*].[CertificateArn,DomainName]' \
--output table
# Inspect a specific certificate
aws acm describe-certificate \
--certificate-arn arn:aws:acm:eu-west-2:123456789012:certificate/abc-123 \
--region eu-west-2 \
--query 'Certificate.{Domain:DomainName,Expiry:NotAfter,Status:Status}'
Request a renewal:
aws acm renew-certificate \
--certificate-arn arn:aws:acm:eu-west-2:123456789012:certificate/abc-123 \
--region eu-west-2
Export the renewed certificate (requires a passphrase to encrypt the private key):
aws acm export-certificate \
--certificate-arn arn:aws:acm:eu-west-2:123456789012:certificate/abc-123 \
--passphrase fileb://passphrase.txt \
--region eu-west-2 \
| jq -r '{
Certificate: .Certificate,
Chain: .CertificateChain,
Key: .PrivateKey
}'
In practice, you'll want to pipe the individual fields directly to files:
CERT_JSON=$(aws acm export-certificate \
--certificate-arn arn:aws:acm:eu-west-2:123456789012:certificate/abc-123 \
--passphrase fileb://passphrase.txt \
--region eu-west-2)
echo "$CERT_JSON" | jq -r '.Certificate' > /etc/nginx/ssl/cert.pem
echo "$CERT_JSON" | jq -r '.CertificateChain' > /etc/nginx/ssl/chain.pem
echo "$CERT_JSON" | jq -r '.PrivateKey' > /etc/nginx/ssl/key.pem
# Decrypt the private key using the passphrase
openssl rsa \
-in /etc/nginx/ssl/key.pem \
-out /etc/nginx/ssl/key-decrypted.pem \
-passin file:passphrase.txt
systemctl reload nginx
Automating exportable certificate renewal with EventBridge
Rather than polling on a schedule, you can trigger renewal automation reactively. ACM publishes an EventBridge event when a certificate enters the PENDING_AUTO_RENEWAL state — typically 60 days before expiry. A Lambda function subscribed to that event can handle the full renewal and redeployment cycle without any scheduled jobs.
The EventBridge rule pattern to match:
{
"source": ["aws.acm"],
"detail-type": ["ACM Certificate Approaching Expiration"],
"detail": {
"DaysToExpiry": [60, 45, 30, 15, 7, 3, 1]
}
}
For exportable certificates installed on EC2 instances, the Lambda handler can invoke SSM Run Command to pull the renewed certificate and reload the web server — keeping the entire operation within AWS without any inbound connectivity to your instances.
Centralised monitoring
Whichever CA you use, you should have independent monitoring that alerts on certificate expiry regardless of whether the automated renewal worked. Tools like Datadog, Uptime Robot, and AWS Certificate Manager all provide certificate expiry monitoring. A simple check with openssl works in any pipeline or cron job:
#!/bin/bash
# Alert if certificate expires within 30 days
DOMAIN="example.com"
EXPIRY=$(echo | openssl s_client -connect ${DOMAIN}:443 \
-servername ${DOMAIN} 2>/dev/null \
| openssl x509 -noout -enddate \
| cut -d= -f2)
EXPIRY_EPOCH=$(date -d "$EXPIRY" +%s)
NOW_EPOCH=$(date +%s)
DAYS_REMAINING=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))
if [ "$DAYS_REMAINING" -lt 30 ]; then
echo "WARNING: ${DOMAIN} certificate expires in ${DAYS_REMAINING} days" >&2
exit 1
fi
echo "OK: ${DOMAIN} certificate valid for ${DAYS_REMAINING} days"
Deploy as a systemd timer or cron job alongside your renewal automation — independent monitoring catches the case where the renewal automation itself fails silently.
The broader point
The industry is moving toward certificates that are effectively ephemeral. At 47 days, a certificate is closer in character to a session token than to a traditional identity document. That's a deliberate architectural direction — and it requires treating certificate management as an infrastructure concern, not an admin task.
If your certificate renewal process still involves a human opening a browser, the timeline above should be your prompt to change that. The tooling exists, it's mature, and — with Let's Encrypt — it's free. The question isn't whether to automate. It's how long you can afford to wait.
If you need help implementing automated certificate management as part of a broader infrastructure review, we're happy to talk.