- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. TLS/SSL Certificate Fundamentals
- 2. What Is Let's Encrypt
- 3. ACME Protocol Mechanics
- 4. Certbot Installation
- 5. Certificate Issuance Methods
- 6. Issued File Structure
- 7. Automatic Renewal Setup
- 8. Rate Limits
- 9. Alternative Tools
- 10. Troubleshooting
- 11. Security Best Practices
- 12. Conclusion
1. TLS/SSL Certificate Fundamentals
1.1 Why TLS Certificates Are Needed
TLS (Transport Layer Security) certificates provide three core security elements for web communication.
- Encryption: Encrypts data between client and server to prevent eavesdropping
- Authentication: Proves the server is the real owner of the domain
- Integrity: Guarantees data was not tampered with during transmission
1.2 Certificate Chain Structure
┌───────────────────────┐
│ Root CA Certificate │ <- Trust anchor embedded in browsers/OS
│ (Self-Signed) │
└───────────┬───────────┘
│ Signs
┌───────────▼───────────┐
│ Intermediate CA Cert │ <- Intermediate CA certificate
│ (Signed by Root CA) │
└───────────┬───────────┘
│ Signs
┌───────────▼───────────┐
│ Server Certificate │ <- Domain certificate (Leaf)
│ (Signed by Inter. CA) │
└───────────────────────┘
1.3 Public/Private Key Pairs
- Private Key: Held only by the server, must never be leaked
- CSR (Certificate Signing Request): Public key + domain info, submitted to CA
- Certificate: CA-signed public key + domain info
2. What Is Let's Encrypt
2.1 Overview
Let's Encrypt is a free, automated, open Certificate Authority (CA) operated by ISRG (Internet Security Research Group).
Key features:
- Free: Issues Domain Validation (DV) certificates at no cost
- Automated: Fully automates certificate issuance/renewal via ACME protocol
- Open: Uses open-source protocols and tools
- Validity: 90 days (short cycle enhances security)
- Trusted: Trusted by all major browsers and operating systems
2.2 Certificate Type Comparison
| Type | Validation Level | Issuance Time | Cost | Let's Encrypt |
|---|---|---|---|---|
| DV (Domain Validation) | Domain ownership | Minutes | Free to low | Supported |
| OV (Organization Validation) | Organization | Days | Paid | Not supported |
| EV (Extended Validation) | Extended | Weeks | Expensive | Not supported |
3. ACME Protocol Mechanics
ACME (Automatic Certificate Management Environment) is a protocol that automates certificate issuance.
3.1 Overall Flow
┌────────┐ ┌──────────────┐
│ Certbot│ │ Let's Encrypt│
│(Client)│ │ (CA/ACME) │
└───┬────┘ └──────┬───────┘
│ 1. Account Registration │
│──────────────────────────────────────>│
│ 2. Account Created │
│<──────────────────────────────────────│
│ │
│ 3. Order (domain list) │
│──────────────────────────────────────>│
│ 4. Authorizations + Challenges │
│<──────────────────────────────────────│
│ │
│ 5. Respond to Challenge │
│ (HTTP-01 / DNS-01 / TLS-ALPN-01) │
│──────────────────────────────────────>│
│ │
│ 6. Challenge Validated │
│<──────────────────────────────────────│
│ │
│ 7. Finalize (send CSR) │
│──────────────────────────────────────>│
│ 8. Certificate issued │
│<──────────────────────────────────────│
3.2 HTTP-01 Challenge
The most common challenge type. Validates that a specific file is accessible over port 80.
Let's Encrypt -> http://yourdomain.com/.well-known/acme-challenge/TOKEN_VALUE
Process:
1. Certbot places a token file on the web server
2. Let's Encrypt accesses the file via HTTP
3. If content matches expected value, domain ownership is confirmed
Advantages:
- Simplest and most common
- No additional DNS configuration needed
- Easy to set up on most web servers
Limitations:
- Port 80 must be externally accessible
- Cannot issue wildcard certificates
- Configuration can be complex behind load balancers
3.3 DNS-01 Challenge
Proves domain ownership by creating a DNS TXT record. Required for wildcard certificates.
Let's Encrypt -> DNS lookup: _acme-challenge.yourdomain.com TXT
Process:
1. Certbot calculates a token
2. Set the token value in _acme-challenge.yourdomain.com TXT record
3. Let's Encrypt queries DNS to verify the value
4. If it matches, domain ownership is confirmed
Advantages:
- Can issue wildcard certificates
- Works without a web server
- Port 80 does not need to be open
- One certificate can be used across multiple servers
Limitations:
- DNS Provider API needed (for automation)
- Possible DNS propagation delay
- Manual setup can be tedious
3.4 TLS-ALPN-01 Challenge
Validates through the ALPN (Application-Layer Protocol Negotiation) extension during TLS connection on port 443.
3.5 Challenge Comparison
| Feature | HTTP-01 | DNS-01 | TLS-ALPN-01 |
|---|---|---|---|
| Port | 80 | None (DNS) | 443 |
| Wildcard | No | Yes | No |
| Web Server Required | Yes | No | Yes |
| Automation Difficulty | Low | Medium (DNS API needed) | High |
| DNS Setup Required | No | Yes | No |
| Primary Use | General web servers | Wildcards, internal servers | Special environments |
4. Certbot Installation
4.1 Ubuntu / Debian
# Install via snap (recommended)
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
4.2 CentOS / RHEL / Rocky Linux
sudo dnf install epel-release
sudo dnf install certbot
sudo dnf install python3-certbot-nginx
4.3 macOS
brew install certbot
4.4 Docker
docker run -it --rm \
-v /etc/letsencrypt:/etc/letsencrypt \
-v /var/lib/letsencrypt:/var/lib/letsencrypt \
certbot/certbot certonly --help
5. Certificate Issuance Methods
5.1 Standalone Mode
Certbot runs its own web server to handle the HTTP-01 challenge. The existing web server must be stopped.
sudo systemctl stop nginx
sudo certbot certonly --standalone \
-d example.com \
-d www.example.com \
--agree-tos \
--email admin@example.com \
--non-interactive
sudo systemctl start nginx
5.2 Webroot Mode
Issues certificates without stopping the existing web server. The web server must serve a specific directory.
Nginx configuration:
server {
listen 80;
server_name example.com www.example.com;
location /.well-known/acme-challenge/ {
root /var/www/certbot;
}
location / {
return 301 https://$host$request_uri;
}
}
sudo mkdir -p /var/www/certbot
sudo certbot certonly --webroot \
-w /var/www/certbot \
-d example.com \
-d www.example.com \
--agree-tos \
--email admin@example.com
5.3 Nginx Plugin
Certbot automatically modifies the Nginx configuration.
sudo certbot --nginx \
-d example.com \
-d www.example.com \
--agree-tos \
--email admin@example.com
5.4 DNS Plugin (Wildcard Certificates)
Wildcard certificates require the DNS-01 challenge.
Cloudflare DNS Plugin:
sudo snap install certbot-dns-cloudflare
cat > /etc/letsencrypt/cloudflare.ini << 'CFEOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
CFEOF
sudo chmod 600 /etc/letsencrypt/cloudflare.ini
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini \
-d "example.com" \
-d "*.example.com" \
--agree-tos \
--email admin@example.com
AWS Route 53 DNS Plugin:
sudo snap install certbot-dns-route53
sudo certbot certonly \
--dns-route53 \
-d "example.com" \
-d "*.example.com" \
--agree-tos \
--email admin@example.com
6. Issued File Structure
/etc/letsencrypt/live/example.com/
cert.pem # Server certificate only
chain.pem # Intermediate CA certificate chain
fullchain.pem # cert.pem + chain.pem (used by servers)
privkey.pem # Private key
| File | Contents | Usage |
|---|---|---|
| cert.pem | Server certificate | Standalone use (rarely used) |
| chain.pem | Intermediate CA cert | For OCSP Stapling |
| fullchain.pem | Server cert + Intermediate CA | Nginx ssl_certificate |
| privkey.pem | Private key | Nginx ssl_certificate_key |
Apply to Nginx:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
}
7. Automatic Renewal Setup
7.1 Renewal Test
sudo certbot renew --dry-run
7.2 systemd Timer (Recommended)
# /etc/systemd/system/certbot-renew.timer
[Unit]
Description=Certbot renewal timer
[Timer]
OnCalendar=*-*-* 00,12:00:00
RandomizedDelaySec=3600
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/certbot-renew.service
[Unit]
Description=Certbot renewal service
[Service]
Type=oneshot
ExecStart=/usr/bin/certbot renew --quiet --deploy-hook "systemctl reload nginx"
sudo systemctl daemon-reload
sudo systemctl enable --now certbot-renew.timer
7.3 Crontab
# crontab -e
0 2,14 * * * certbot renew --quiet --deploy-hook "systemctl reload nginx"
7.4 Renewal Hooks
# Deploy hook (runs only when renewal succeeds)
sudo mkdir -p /etc/letsencrypt/renewal-hooks/deploy
cat > /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh << 'HOOKEOF'
#!/bin/bash
systemctl reload nginx
echo "Certificate renewed and nginx reloaded at $(date)" >> /var/log/certbot-deploy.log
HOOKEOF
chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
8. Rate Limits
Let's Encrypt applies the following rate limits to prevent abuse.
| Limit | Value | Description |
|---|---|---|
| Certificates per Registered Domain | 50/week | 50 per domain per week |
| Duplicate Certificate | 5/week | 5 for identical domain sets |
| Failed Validations | 5/hour/account/hostname | Validation failure limit |
| New Orders | 300/3 hours | New order limit |
| Accounts per IP | 10/3 hours | Account creation per IP |
Use the Staging Environment:
# Use staging server for testing (much more lenient rate limits)
sudo certbot certonly --standalone \
--staging \
-d example.com \
--agree-tos \
--email admin@example.com
9. Alternative Tools
9.1 acme.sh
A pure shell script ACME client.
curl https://get.acme.sh | sh
acme.sh --issue -d example.com -w /var/www/html
# Wildcard with DNS API
acme.sh --issue \
-d example.com \
-d "*.example.com" \
--dns dns_cf \
--dnssleep 120
# Install to Nginx
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.fullchain.pem \
--reloadcmd "systemctl reload nginx"
9.2 Caddy (Automatic HTTPS)
Caddy handles HTTPS automatically within the web server itself.
# Caddyfile
example.com {
root * /var/www/html
file_server
}
# This alone auto-issues and renews Let's Encrypt certificates!
9.3 cert-manager (Kubernetes)
Automatically manages certificates in Kubernetes environments.
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@example.com
privateKeySecretRef:
name: letsencrypt-prod-key
solvers:
- http01:
ingress:
class: nginx
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- app.example.com
secretName: app-tls-secret
rules:
- host: app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: app-certificate
namespace: default
spec:
secretName: app-tls-secret
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- app.example.com
- api.example.com
renewBefore: 720h # Renew 30 days before expiry
10. Troubleshooting
10.1 Common Errors and Solutions
Challenge failure:
# Verify HTTP-01 challenge file access
curl -v http://yourdomain.com/.well-known/acme-challenge/test
# Check firewall (port 80)
sudo ufw status
sudo iptables -L -n | grep 80
# Check DNS
dig +short yourdomain.com
Certificate renewal failure:
sudo certbot certificates
sudo certbot renew --dry-run -v
sudo cat /var/log/letsencrypt/letsencrypt.log
Certificate info check:
# View certificate contents
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -text -noout
# Check expiration date
openssl x509 -in /etc/letsencrypt/live/example.com/cert.pem -enddate -noout
# Check remote server certificate
openssl s_client -connect example.com:443 -servername example.com < /dev/null 2>/dev/null | \
openssl x509 -text -noout
11. Security Best Practices
- Protect private keys: Set privkey.pem permissions to 600, readable only by root
- Monitor automatic renewal: Set up alerts for renewal failures (email, Slack, etc.)
- Staging first: Always test new configurations in the staging environment
- Apply HSTS: Configure HSTS headers after certificate issuance
- Certificate Transparency monitoring: Monitor domain certificate issuance at crt.sh
- Backup: Regularly back up the /etc/letsencrypt directory
12. Conclusion
Let's Encrypt and Certbot have become the standard for free TLS certificates. Key takeaways:
- HTTP-01 challenge is simplest, but wildcards require DNS-01
- Certbot Webroot or Nginx plugin is most practical
- Automatic renewal via systemd timer or crontab
- cert-manager is the standard in Kubernetes environments
- Understand rate limits and use staging server for testing
- After certificate issuance, always optimize Nginx TLS security settings