Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Lets Encrypt

FSecurity

Expert agent for Let's Encrypt free TLS certificates via ACME. Covers certbot, acme.sh, HTTP-01/DNS-01/TLS-ALPN-01 challenges, 90-day and 6-day certificate lifetimes, wildcard certificates, rate limits, staging environment, and automation best practices. WHEN: \"Let's Encrypt\", \"certbot\", \"acme.sh\", \"ACME\", \"free TLS\", \"LEGO\", \"Certify The Web\", \"short-lived certificate\", \"6-day certificate\", \"ACME challenge\", \"DNS-01 challenge\".

4 stars
0 votes
0 copies
0 views
Added 9/24/2026
devopspythonrustgobashdockerawsazuretestinggitapi

Works with

cliapi

Security Analysis

F32/100
criticalPipes output to a shell interpreter
mediumUses curl or wget to download content
highCreates or modifies cron jobs for persistent execution
highCreates or modifies cron jobs for persistent execution
criticalModifies startup scripts or system services for persistence
criticalDownloads and executes remote scripts — classic supply chain attack
mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned 9/24/2026

$npx -y skills add chrishuffman5/domain-expert --skill lets-encrypt --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Lets Encrypt?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Lets Encrypt
[![Security: F — Skills Directory](https://www.skillsdirectory.com/api/skills/chrishuffman5-lets-encrypt/badge)](https://www.skillsdirectory.com/skills/chrishuffman5-lets-encrypt)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: lets-encrypt
description: "Expert agent for Let's Encrypt free TLS certificates via ACME. Covers certbot, acme.sh, HTTP-01/DNS-01/TLS-ALPN-01 challenges, 90-day and 6-day certificate lifetimes, wildcard certificates, rate limits, staging environment, and automation best practices. WHEN: \"Let's Encrypt\", \"certbot\", \"acme.sh\", \"ACME\", \"free TLS\", \"LEGO\", \"Certify The Web\", \"short-lived certificate\", \"6-day certificate\", \"ACME challenge\", \"DNS-01 challenge\"."
license: MIT
---

# Let's Encrypt

This skill covers Let's Encrypt and the ACME protocol ecosystem. It has deep knowledge of certificate issuance, renewal automation, challenge types, rate limits, and integration patterns.

## How to Approach Tasks

1. **Identify the deployment context**: web server (nginx/Apache/Caddy), container (K8s), serverless, load balancer, or custom application.
2. **Determine challenge type needed**: HTTP-01 (single servers with port 80), DNS-01 (wildcard, no port 80 access), TLS-ALPN-01 (only port 443).
3. **Identify ACME client**: certbot (most common), acme.sh (scriptable), LEGO (Go), step CLI, or built-in (Caddy, Traefik).
4. **Consider lifetime**: 90-day (current default), 6-day (available, requires renewal every ~4 days), 45-day opt-in (May 2026).

## Certificate Lifetimes

| Profile | Lifetime | Renewal Frequency | Launched |
|---|---|---|---|
| Default (90-day) | 90 days | Every ~60 days (at 2/3) | Always |
| Short-lived (6-day) | 6 days | Every ~4 days | March 2025 |
| 45-day opt-in | 45 days | Every ~30 days | May 2026 |

**6-day certificates**: Require fully automated renewal. No OCSP needed (cert expires before compromise can be acted upon). Ideal for fully automated infrastructure.

**Recommendation**: Use 90-day unless you have full automation and want to eliminate revocation dependency.

## certbot

### Installation

```bash
# Ubuntu/Debian
sudo apt install certbot python3-certbot-nginx  # or python3-certbot-apache

# macOS
brew install certbot

# pip (any platform)
pip install certbot certbot-nginx certbot-apache

# snap (recommended for Ubuntu)
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
```

### Obtaining Certificates

```bash
# Nginx — automatically edits nginx config
sudo certbot --nginx -d example.com -d www.example.com

# Apache — automatically edits Apache config
sudo certbot --apache -d example.com -d www.example.com

# Standalone (temporary HTTP server on port 80)
# Use when nginx/Apache is not running
sudo certbot certonly --standalone -d example.com

# Webroot (place challenge files in existing webroot)
sudo certbot certonly --webroot -w /var/www/html -d example.com -d www.example.com

# DNS-01 (for wildcard, requires DNS plugin)
sudo certbot certonly --dns-cloudflare \
    --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
    -d example.com -d "*.example.com"
```

### DNS-01 Plugins

certbot has plugins for major DNS providers:
- `certbot-dns-cloudflare` — Cloudflare
- `certbot-dns-route53` — AWS Route 53
- `certbot-dns-google` — Google Cloud DNS
- `certbot-dns-azure` — Azure DNS
- `certbot-dns-digitalocean` — DigitalOcean
- `certbot-dns-ovh` — OVH

```bash
# Install Cloudflare plugin
pip install certbot-dns-cloudflare

# Cloudflare credentials file
cat > ~/.secrets/certbot/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
chmod 600 ~/.secrets/certbot/cloudflare.ini

# Issue wildcard cert
certbot certonly \
    --dns-cloudflare \
    --dns-cloudflare-credentials ~/.secrets/certbot/cloudflare.ini \
    --dns-cloudflare-propagation-seconds 30 \
    -d example.com \
    -d "*.example.com"
```

### Certificate Files

Certbot stores certificates in `/etc/letsencrypt/live/<domain>/`:

```
/etc/letsencrypt/live/example.com/
  cert.pem         → Certificate only (not for nginx/Apache — use fullchain)
  chain.pem        → Intermediate certificate(s) only
  fullchain.pem    → cert.pem + chain.pem (use this for most servers)
  privkey.pem      → Private key (readable only by root)
```

nginx config:
```nginx
ssl_certificate     /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
```

### Renewal

```bash
# Test renewal (dry run, no actual cert change)
sudo certbot renew --dry-run

# Force renewal (even if not yet due)
sudo certbot renew --force-renewal

# Renew specific certificate
sudo certbot renew --cert-name example.com

# Check renewal timer (systemd)
sudo systemctl status snap.certbot.renew.timer
# Or cron:
0 0,12 * * * root certbot renew --quiet
```

### Renewal Hooks

```bash
# Deploy hook — runs after successful renewal
# /etc/letsencrypt/renewal-hooks/deploy/reload-nginx.sh
#!/bin/bash
systemctl reload nginx

# Pre-hook — runs before renewal attempt
# /etc/letsencrypt/renewal-hooks/pre/stop-haproxy.sh
#!/bin/bash
systemctl stop haproxy

# Post-hook — runs after renewal attempt (success or failure)
# /etc/letsencrypt/renewal-hooks/post/start-haproxy.sh
#!/bin/bash
systemctl start haproxy
```

Or configure in `/etc/letsencrypt/renewal/example.com.conf`:
```ini
[renewalparams]
deploy_hook = systemctl reload nginx
```

## acme.sh

A pure Bash ACME client with broad DNS provider support (150+ providers).

```bash
# Install
curl https://get.acme.sh | sh -s email=admin@example.com

# Issue certificate (HTTP-01, webroot mode)
acme.sh --issue -d example.com -w /var/www/html

# Issue certificate (standalone)
acme.sh --issue -d example.com --standalone

# Issue wildcard (DNS-01, Cloudflare example)
export CF_Token="your-cloudflare-api-token"
export CF_Account_ID="your-account-id"
acme.sh --issue -d example.com -d "*.example.com" --dns dns_cf

# Install certificate to nginx
acme.sh --install-cert -d example.com \
    --cert-file /etc/nginx/ssl/cert.pem \
    --key-file /etc/nginx/ssl/privkey.pem \
    --fullchain-file /etc/nginx/ssl/fullchain.pem \
    --reloadcmd "systemctl reload nginx"

# List all certificates
acme.sh --list

# Force renew
acme.sh --renew -d example.com --force

# Auto-renewal is handled by cron (installed automatically)
# Check with: crontab -l | grep acme
```

### acme.sh with Let's Encrypt Staging

```bash
# Use staging to test without hitting rate limits
acme.sh --issue -d example.com --standalone --staging

# Switch from staging to production
acme.sh --issue -d example.com --standalone --server letsencrypt
```

## Built-in ACME Servers

### Caddy

Caddy automatically obtains and renews Let's Encrypt certificates:

```caddyfile
# Caddyfile
example.com {
    root * /var/www/html
    file_server
    # TLS is automatic — Caddy handles ACME
}

# With custom email
{
    email admin@example.com
}
```

For internal CAs:
```caddyfile
example.com {
    tls {
        ca https://step-ca.internal/acme/acme/directory
    }
}
```

### Traefik

```yaml
# traefik.yml
certificatesResolvers:
  letsencrypt:
    acme:
      email: admin@example.com
      storage: /letsencrypt/acme.json
      httpChallenge:
        entryPoint: web      # use HTTP-01 challenge
      # OR:
      dnsChallenge:
        provider: cloudflare  # use DNS-01 challenge
        delayBeforeCheck: 30

---
# Docker label on service
labels:
  - "traefik.http.routers.myapp.tls.certresolver=letsencrypt"
  - "traefik.http.routers.myapp.rule=Host(`example.com`)"
```

## Rate Limit Management

### Avoiding Limits

1. **Use staging for testing**: `--staging` flag; staging uses separate rate limit pool
2. **Reuse certificates**: Don't re-issue when cert is still valid; use `--force-renewal` sparingly
3. **Batch issuance**: Include all SANs in one certificate rather than separate certificates per domain
4. **Monitor usage**: `https://crt.sh/?q=example.com` shows issued certificates

### When You Hit Rate Limits

Let's Encrypt returns a `429 Too Many Requests` or specific error message indicating which limit was hit:
- "too many certificates already issued for exact set of domains" — Duplicate limit (5/week)
- "too many certificates already issued for this domain" — Domain limit (50/week)

**Only solution**: Wait until the sliding window resets (7 days from oldest cert in that group).

### Rate Limit Exceptions

Apply for rate limit increases: `https://issuance-limit-requests.letsencrypt.org` for legitimate high-volume needs. Alternatives:
- ZeroSSL (same ACME protocol, separate rate limits)
- Google Trust Services (separate rate limits, requires Google Cloud project)
- AWS Certificate Manager (ACM) for AWS-hosted workloads (no rate limits, free in ACM)

## Common Issues and Fixes

### "Connection refused" on HTTP-01 challenge

1. Check port 80 is open in firewall/security group
2. Check web server is listening on port 80
3. Check no redirect loop before challenge token is served: challenge path must serve token on HTTP (not redirect to HTTPS)
4. If behind load balancer: LB must forward `.well-known/acme-challenge/` to the server running certbot

```nginx
# Ensure challenge path is served before HTTPS redirect
server {
    listen 80;
    server_name example.com;
    
    location /.well-known/acme-challenge/ {
        root /var/www/certbot;
        # Served BEFORE redirect
    }
    
    location / {
        return 301 https://$host$request_uri;
    }
}
```

### "DNS problem" on DNS-01 challenge

1. Check DNS propagation: `dig TXT _acme-challenge.example.com @8.8.8.8`
2. Increase `--dns-cloudflare-propagation-seconds` (or equivalent) to 60-120s
3. Verify API token has DNS:Edit permission for the zone
4. Check TTL on TXT record (short TTL helps during validation)

### Certificate Not Renewed After Expiry

1. Check certbot timer: `systemctl status snap.certbot.renew.timer`
2. Check cron: `crontab -l | grep certbot` or `/etc/cron.d/certbot`
3. Check logs: `/var/log/letsencrypt/letsencrypt.log`
4. Verify certificate location: `certbot certificates`
5. Check if server is reloaded after renewal (missing deploy hook)

### CAA Record Blocking Issuance

If you have CAA records that don't include `letsencrypt.org`:
```
# DNS: Allow Let's Encrypt
example.com. CAA 0 issue "letsencrypt.org"
example.com. CAA 0 issuewild "letsencrypt.org"  # for wildcard
```

## Production Checklist

- [ ] Test in staging environment first
- [ ] Configure automatic renewal (cron or systemd timer)
- [ ] Set up reload hook (nginx/Apache reload after renewal)
- [ ] Monitor certificate expiry independently (external monitoring, not just certbot)
- [ ] Set up CAA DNS records
- [ ] Configure OCSP stapling in web server
- [ ] Test HTTPS with `https://www.ssllabs.com/ssltest/`
- [ ] Set up alerts for renewal failures (email or monitoring integration)

Attribution

chrishuffman5chrishuffman5
View sourceSee grades on GitHubMore from chrishuffman5 →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Terraform Module Library

Build reusable Terraform modules for AWS, Azure, and GCP infrastructure following infrastructure-as-code best practices. Use when creating infrastructure modules, standardizing cloud provisioning, or implementing reusable IaC components.

401991 votes

sematext-otel

Wire a service's OpenTelemetry output to Sematext Cloud. Walks through region, App-type, instrumentation flow (managed OTLP endpoint vs Sematext Agent), and signal selection (traces/metrics/logs), then produces the exact env-var block and points at a runnable reference example in this repo. Invoke when instrumenting a new app for Sematext.

01 votes

Deployment Patterns

Deployment workflows, CI/CD pipeline patterns, Docker containerization, health checks, rollback strategies, and production readiness checklists for web applications. Use when setting up deployment infrastructure or planning releases.

2699140 votes

Babysit

Watch a pull request or review cycle until it is ready to merge. Use when asked to babysit, monitor, or keep checking PR comments, reviews, and CI until all actionable issues are resolved.

971540 votes

V7 Roster

Interact with the Paperclip control plane API for task coordination and governance. Use when checking assignments, updating issue status, posting comments, delegating work, managing routines, or calling Paperclip API endpoints.

953190 votes
View all in devops →