Introduction to Let's Encrypt
Let's Encrypt is a free, automated, and open certificate authority (CA) that provides domain-validated (DV) SSL/TLS certificates. Backed by the Internet Security Research Group (ISRG), its mission is to make encrypted connections ubiquitous across the web by removing cost, complexity, and manual intervention from the certificate lifecycle. Instead of relying on traditional paid certificates that must be renewed manually every one or two years, Let's Encrypt issues short-lived certificates (90 days) and fully automates issuance and renewal via the ACME (Automated Certificate Management Environment) protocol.
The service is trusted by all major browsers and operating systems, meaning certificates issued by Let's Encrypt are recognized as valid without any additional configuration on the client side. Since its launch, it has become the default choice for developers, small businesses, and large-scale deployments alike, securing hundreds of millions of domains worldwide.
Why Let's Encrypt Matters
🚀 Deploy your AI agent in 10 minutes
Managed Hermes hosting. Zero DevOps. 100M tokens/mo included.
Try it free →Before Let's Encrypt, HTTPS adoption was hindered by cost and operational overhead. Manual certificate renewal led to expired certificates, broken websites, and security lapses. Let's Encrypt addresses these issues directly:
- Zero cost: Eliminates the financial barrier, making HTTPS accessible to hobby projects, non-profits, and enterprise alike.
- Automation: The ACME protocol allows client software like Certbot to automatically request, validate, install, and renew certificates with minimal human intervention.
- Short validity period: 90-day certificates reduce the impact of key compromise and encourage automation, as manual renewal is impractical.
- Transparency: All issued certificates are publicly logged via Certificate Transparency logs, allowing domain owners and researchers to monitor for misissuance.
- Improved security ecosystem: By making HTTPS the default, it helps protect user privacy and data integrity across the entire web.
For a developer, using Let's Encrypt means you can deploy production-grade TLS on any server in minutes, integrate it into CI/CD pipelines, and never worry about expiration again if renewal automation is properly configured.
How Let's Encrypt Works
Let's Encrypt uses the ACME protocol (RFC 8555) to handle certificate requests and domain validation. A client (such as Certbot, acme.sh, lego, or a custom implementation) communicates with Let's Encrypt servers to prove ownership of a domain name. The process typically follows these steps:
- The client generates a key pair and a certificate signing request (CSR) for the domains to be secured.
- The client submits the CSR to Let's Encrypt and requests a challenge type for domain validation.
- Let's Encrypt issues a challenge (e.g., HTTP-01, DNS-01) that the client must complete to prove control over the domain.
- The client completes the challenge and notifies the CA.
- Upon successful validation, Let's Encrypt issues the certificate, which the client downloads and installs.
- The client typically saves the certificate and private key, configures the web server, and sets up automated renewal.
Validation Methods
There are several challenge types, each suited to different environments:
- HTTP-01: The client places a specific token at a known URL (
/.well-known/acme-challenge/<token>) on the domain's web server. Let's Encrypt fetches that token over HTTP (or HTTPS if already available) to verify control. This is the most common method and works well for publicly accessible web servers. - DNS-01: The client creates a TXT record at a specified subdomain (
_acme-challenge.yourdomain.example) containing a token. Let's Encrypt queries DNS for the record. This method can secure domains even when no web server is running, works for wildcard certificates, and is ideal for load balancers, CDNs, or internal services. - TLS-ALPN-01: Rarely used directly by end-users; designed for reverse proxies and TLS-terminating servers where HTTP access is not possible. The client serves a special self-signed certificate during a TLS handshake on port 443 to prove control.
Choosing the right challenge depends on your infrastructure. HTTP-01 is simplest for typical web servers; DNS-01 is required for wildcard certificates and for setups where the server isn't publicly reachable on port 80.
Setting Up Let's Encrypt
The most widely used ACME client is Certbot, maintained by the Electronic Frontier Foundation (EFF). It integrates directly with many web servers (Apache, Nginx) to handle both challenge completion and configuration. You can also use other clients like acme.sh, lego, or dehydrated for more customized scenarios. Below, we focus on Certbot, but the core concepts apply to all ACME clients.
Installing Certbot
The recommended installation method varies by OS and web server. On modern distributions, using the snap package ensures you always get the latest version with automatic updates. For older systems, native packages or pip may be used.
Example: Installing Certbot via snap on Ubuntu 20.04+:
# Install snapd if not already installed
sudo apt update
sudo apt install snapd
# Install the core snap, then Certbot
sudo snap install core
sudo snap install --classic certbot
# Link the certbot command to the snap binary
sudo ln -s /snap/bin/certbot /usr/bin/certbot
For Debian-based systems with the Certbot package in the repository:
sudo apt update
sudo apt install certbot python3-certbot-nginx python3-certbot-apache
Replace python3-certbot-nginx or python3-certbot-apache with the appropriate plugin for your web server.
Obtaining a Certificate (HTTP-01 Challenge)
If you are running a web server that Certbot supports, you can obtain and install a certificate in one command. The server must already be serving the domain on port 80 (HTTP) and have the necessary server block or virtual host configured.
Nginx
sudo certbot --nginx -d example.com -d www.example.com
Certbot will scan the Nginx configuration, find the relevant server blocks, perform the HTTP-01 challenge automatically, and modify the configuration to enable HTTPS by adding SSL directives and redirecting HTTP to HTTPS. You’ll be prompted for an email address for renewal notifications and to agree to the terms of service.
Apache
sudo certbot --apache -d example.com -d www.example.com
Similarly, Certbot modifies Apache virtual hosts, enabling the SSL module and rewriting configurations to use the new certificate.
Manual / Standalone Mode (No Running Server)
If you don't have a web server running or prefer not to let Certbot modify configurations, you can use the certonly subcommand with the standalone plugin. This spins up a temporary web server on port 80 to complete the challenge.
sudo certbot certonly --standalone -d example.com
After issuance, the certificate and key are stored in /etc/letsencrypt/live/example.com/ (by default). You must then manually configure your web server to use them.
Obtaining a Certificate with DNS-01 Challenge
DNS validation is essential for wildcard certificates and for domains where HTTP access is blocked or impractical. You need to automate DNS record creation via a plugin or perform manual steps.
Using DNS Plugin (Cloudflare Example)
Certbot supports many DNS providers through plugins. For Cloudflare, install the plugin and provide API credentials:
# Install the Cloudflare DNS plugin (snap)
sudo snap install certbot-dns-cloudflare
# Create a file containing Cloudflare API token
# e.g., /home/user/.secrets/cloudflare.ini
# dns_cloudflare_api_token = "your-token"
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /home/user/.secrets/cloudflare.ini \
-d example.com \
-d *.example.com
This automatically creates and removes the required TXT record, then issues the certificate. Wildcard certificates cover any subdomain at the same level (e.g., *.example.com).
Manual DNS Challenge
If no plugin exists for your DNS provider, use the manual mode:
sudo certbot certonly --manual --preferred-challenges dns -d example.com
Certbot will output a specific TXT record and wait for you to create it. After DNS propagation (you can verify with dig or nslookup), press Enter to continue. This method is not automatable for renewal, so use it only for initial testing or if you plan to script the renewal with a custom hook.
Certificate File Locations and Renewal Basics
All certificates, keys, and related files are stored in the /etc/letsencrypt directory structure (default for Certbot on Linux):
/etc/letsencrypt/live/<domain>/– symbolic links to the latest certificate and key files. Use these paths in your server config.fullchain.pem– the certificate plus the intermediate CA certificate, ready for use by most servers.privkey.pem– the private key. Keep this secure.cert.pem– server certificate only.chain.pem– intermediate certificate.
Certbot sets up a systemd timer (or cron job) that runs twice daily and renews certificates that expire in less than 30 days. You can test renewal manually:
sudo certbot renew --dry-run
This simulates the renewal process without actually issuing new certificates. Always test after configuration changes.
Configuration and Integration
Configuring Web Servers to Use the Certificate
When Certbot does not modify server configurations automatically (e.g., certonly or manual mode), you must update your server's SSL settings yourself. Here are examples for common servers.
Nginx
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# Strong TLS configuration (recommended)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...';
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
root /var/www/html;
# ... other directives
}
# HTTP redirect to HTTPS
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
Apache
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# Strong TLS settings
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:...
DocumentRoot /var/www/html
# ...
</VirtualHost>
# Redirect HTTP to HTTPS
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
Automated Renewal with Hooks
Certbot allows you to define pre- and post-hooks that run before and after renewal. This is crucial for servers that need to reload configurations or for DNS plugins that require cleanup. Hooks can be specified in /etc/letsencrypt/renewal/example.com.conf or globally.
Example: Reload Nginx after successful renewal:
# In the renewal configuration file:
renew_hook = systemctl reload nginx
Or pass as command-line option during initial run:
sudo certbot --nginx -d example.com --post-hook "systemctl reload nginx"
If you use DNS plugins, the plugin itself handles cleanup; no extra hooks are typically needed. For custom scripts, ensure the hook exits with zero status and does not block indefinitely.
Renewal for Non-Web Servers (Mail, FTP, etc.)
Certificates can secure non-HTTP services. After obtaining a certificate (using standalone or DNS challenge), simply point the service's configuration to fullchain.pem and privkey.pem. Then ensure renewal includes a post-hook that restarts or reloads the service. For example, with Postfix or Dovecot, the hook could run systemctl restart postfix dovecot.
Multi-Domain and Wildcard Certificates
You can include up to 100 domains per certificate (subject to rate limits). Use the -d flag for each domain. Wildcard domains require DNS-01 validation:
sudo certbot certonly --dns-cloudflare --dns-cloudflare-credentials ~/cloudflare.ini \
-d example.com -d *.example.com -d example.net
This creates a single certificate covering all listed domains. Renewal works automatically as long as the DNS plugin credentials remain valid.
Best Practices
1. Automate Renewal and Monitor It
Never rely on manual certificate renewal. Certbot’s timer is robust, but you must ensure the timer is active and that renewal succeeds without errors. Monitor expiration using external services (e.g., Uptime Robot, Nagios, or custom scripts) that query the certificate’s notAfter date or attempt TLS connections.
Verify the renewal timer:
sudo systemctl status certbot.timer # systemd
# or
sudo crontab -l | grep certbot # cron
Set up email alerts for renewal failures by configuring Certbot’s --email flag or using post-hook scripts that send notifications.
2. Protect Private Keys
Private keys in /etc/letsencrypt/live/ should be readable only by root and the services that need them. Use strict file permissions (e.g., 640) and never expose them via public web directories. For extra security, consider using hardware security modules (HSMs) or separate key management, but for most deployments, standard OS file permissions suffice.
# Ensure the directory is secure
sudo chmod 0750 /etc/letsencrypt/live
sudo chmod 0750 /etc/letsencrypt/archive
3. Use the Right Validation Method for Your Environment
Choose HTTP-01 for standard, internet-facing web servers with a running HTTP stack. Use DNS-01 when you need wildcard certificates, when port 80 is blocked by a firewall, or when you’re securing internal services that do not have public HTTP endpoints. Avoid manual DNS mode for production because it cannot be automated for renewal. Prefer DNS plugins tied to your DNS provider’s API.
4. Keep Client Software Updated
ACME clients evolve rapidly to support new features, fix security bugs, and adapt to CA changes. If using Certbot via snap, updates happen automatically. With pip or package managers, schedule regular updates (e.g., monthly) and watch for deprecation notices from Let's Encrypt (e.g., algorithm changes, new chain requirements).
5. Handle Rate Limits Gracefully
Let's Encrypt imposes rate limits to protect infrastructure. The main limits are:
- 50 certificates per registered domain per week (this includes subdomains).
- 5 failures per account per hour for a specific challenge type.
- Duplicate certificate limit: 5 identical certificates per week.
During development, use the staging environment (--test-cert or the ACME staging URL) to avoid hitting limits. Staging certificates are not trusted by browsers but mimic the real CA behavior exactly.
# Test with staging
sudo certbot --dry-run --test-cert --nginx -d example.com
When rolling out a large number of domains, stagger issuance over multiple weeks or use multiple accounts (with careful planning) to stay within limits.
6. Always Use the Fullchain File
Most modern servers (Nginx, Apache, HAProxy) require the full chain – the server certificate concatenated with the intermediate CA certificate. Point to fullchain.pem rather than cert.pem alone, otherwise some clients (especially mobile browsers) may not trust the connection. The fullchain.pem file is updated on renewal, so using symlinks ensures your server always picks up the latest version.
7. Configure Strong TLS Settings
Obtaining a certificate is only half the story. Ensure your server’s TLS configuration follows modern security standards. Recommended base settings:
- Enable TLS 1.2 and TLS 1.3 only.
- Use secure cipher suites preferring ECDHE key exchange and AEAD algorithms.
- Set
ssl_prefer_server_ciphers on(Nginx) orSSLHonorCipherOrder on(Apache). - Enable HSTS (HTTP Strict Transport Security) with a max-age of at least six months, ideally after verifying no mixed-content issues.
- Use OCSP stapling to improve TLS handshake performance and privacy.
Example Nginx OCSP stapling and HSTS:
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/example.com/chain.pem;
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
8. Plan for Disaster Recovery
Since Let's Encrypt certificates are short-lived, losing access to the private key or the ACME account can be problematic. Back up the following securely:
/etc/letsencrypt/accounts/(account keys and registration data)./etc/letsencrypt/renewal/(renewal configurations).- Your DNS API credentials if using DNS plugins.
If a server is lost, you can re-register with the same ACME account (using the account key backup) and re-issue certificates immediately without rate limit concerns. Without the account key, you can create a new account, but you may encounter the duplicate certificate limit temporarily.
9. Avoid Hardcoding Certificate Paths in Containerized Environments
In Docker or Kubernetes, certificates are often short-lived and generated at runtime. Instead of using Certbot inside a container that persists certificates on a volume, consider using an ACME-aware ingress controller (like cert-manager for Kubernetes) that handles issuance and renewal dynamically. If you must use Certbot in a container, use a shared volume or a sidecar pattern, and ensure renewal hooks reload the web server inside the container.
10. Contribute and Stay Informed
Let's Encrypt is community-driven. Subscribe to their blog and community forum to stay updated on upcoming changes (e.g., new chain requirements, algorithm deprecation). Report issues, share feedback, and if possible, donate or contribute code to help keep the ecosystem healthy.
Conclusion
Let's Encrypt has transformed the landscape of web security by making TLS certificates free and effortless. For developers, it removes a major friction point, enabling secure deployments from day one. The key to success lies in understanding the validation mechanisms, choosing the right client for your stack, and meticulously setting up automated renewal with proper monitoring. By following the practices outlined here—securing keys, using fullchain files, testing in staging, and keeping software current—you can ensure that your services remain trusted and resilient. Embrace the automation, and let Let's Encrypt handle the certificate lifecycle while you focus on building great applications.