Let's Encrypt 免费 SSL 证书配置完全指南 - HTTPS 应用实战
Let's Encrypt Free SSL Certificate Complete Setup Guide
引言:HTTPS 已不再是可选项,而是必需品
在 2026 年的今天,HTTPS 已成为网站的必备要素。Google Chrome、Firefox、Safari 等所有主流浏览器都会在 HTTP 网站上显示"不安全"警告,Google 也会为 HTTPS 网站提供搜索排名加分。此外,HTTP/2、HTTP/3、Service Worker 等最新 Web 技术仅在 HTTPS 环境下才能运行。
过去申请一份 SSL 证书每年要花费数十万韩元,但自从 Let's Encrypt 出现后,情况彻底改变了。成立于 2015 年的 Let's Encrypt 是一家非营利证书颁发机构(CA),让任何人都可以完全免费申请到 SSL 证书。截至 2026 年,它已成为全球使用最广泛的免费 SSL 证书,每天签发数百万份证书。
本指南将涵盖使用 Let's Encrypt 将 HTTPS 应用于实际服务的全部流程。从 Certbot 安装到 Nginx/Apache 应用、通配符证书、自动续期,以及常见问题与解决方法,全部详细讲解,助你在实际工作中立即上手。
1. Let's Encrypt 与 SSL 证书基础
1.1 Let's Encrypt 的特点
- 完全免费:申请、续期、重新签发全部免费
- 自动化:通过 ACME 协议可实现签发/续期自动化
- 有效期 90 天:比商业证书(1~2 年)短,但可通过自动续期解决
- 仅支持域名验证(DV):不支持组织验证(OV)和扩展验证(EV)
- 支持通配符:可以签发
*.example.com形式的证书 - 所有主流浏览器均信任:Chrome、Firefox、Safari、Edge 均自动信任
1.2 理解验证方式
Let's Encrypt 通过验证域名所有权的质询(Challenge)机制来签发证书:
| 质询类型 | 验证方式 | 用途 |
|---|---|---|
| HTTP-01 | 在 Web 服务器特定路径放置文件进行验证 | 最常见,单域名 |
| DNS-01 | 通过 DNS TXT 记录验证 | 通配符证书必需,可自动化 |
| TLS-ALPN-01 | 在 TLS 握手期间验证 | 特殊环境(如 80 端口被封) |
• 单域名(example.com、www.example.com):HTTP-01(最简单)
• 通配符(*.example.com):必须使用 DNS-01
• 内网服务器、80 端口被封:使用 DNS-01
1.3 申请前的准备事项
- 域名所有权:需要拥有可实际管理的域名
- DNS 配置:域名需正确解析到服务器 IP
- 开放 80/443 端口:HTTP-01 方式要求 80 端口可从外部访问
- root 权限:用于证书安装和 Web 服务器配置修改
2. 安装 Certbot
Certbot 是由 EFF(电子前沿基金会)开发的 Let's Encrypt 官方客户端,可自动化完成证书的申请与管理。
2.1 Ubuntu/Debian 安装
# snap 方式(官方推荐)
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
# 或 apt 方式(简便)
sudo apt update
sudo apt install certbot -y
sudo apt install python3-certbot-nginx -y # Nginx 插件
sudo apt install python3-certbot-apache -y # Apache 插件(如需要)
# 查看版本
certbot --version
2.2 RHEL/Rocky Linux/CentOS 安装
# 启用 EPEL 仓库(RHEL/CentOS 7)
sudo yum install epel-release -y
sudo yum install certbot python3-certbot-nginx -y
# RHEL 9 / Rocky Linux 9
sudo dnf install epel-release -y
sudo dnf install certbot python3-certbot-nginx -y
# snap 方式(所有版本通用)
sudo dnf install snapd -y
sudo systemctl enable --now snapd.socket
sudo ln -s /var/lib/snapd/snap /snap
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
3. 在 Nginx 上应用 SSL 证书
3.1 自动配置(最简单的方法)
使用 Certbot 的 Nginx 插件,可以一次性完成证书签发和 Nginx 配置修改:
# 前提条件:Nginx 中需已存在该域名对应的 server 块
# 例如:server_name example.com www.example.com;
# 签发证书并自动配置 Nginx
sudo certbot --nginx -d example.com -d www.example.com
# 运行时将询问以下信息:
# 1. 输入邮箱地址(用于接收过期提醒)
# 2. 同意使用条款(Y)
# 3. 是否接收 EFF 通讯(可选 N)
# 4. HTTP → HTTPS 重定向配置(建议选 2)
成功时将输出类似下面的信息:
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/example.com/privkey.pem
This certificate expires on 2026-07-05.
Deploying certificate
Successfully deployed certificate for example.com
Successfully deployed certificate for www.example.com
Your existing server block has been modified to redirect HTTP traffic to HTTPS.
3.2 手动配置(仅签发证书)
如果想自己编写 Nginx 配置,可以只签发证书而手动编写配置:
# webroot 方式(Nginx 运行中)
sudo certbot certonly --webroot -w /var/www/example.com/html \
-d example.com -d www.example.com
# standalone 方式(临时停止 Nginx 后签发)
sudo systemctl stop nginx
sudo certbot certonly --standalone -d example.com -d www.example.com
sudo systemctl start nginx
# 手动 Nginx 配置示例
# /etc/nginx/conf.d/example.com.conf
# HTTP → HTTPS 重定向
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
# HTTPS 主配置
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# Let's Encrypt 证书路径
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL 最佳配置
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 8.8.8.8 8.8.4.4 valid=300s;
# HSTS(强制 HTTPS)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
root /var/www/example.com/html;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
# 验证配置并应用
sudo nginx -t
sudo systemctl reload nginx
4. 在 Apache 上应用 SSL 证书
4.1 自动配置
# 启用 Apache SSL 模块(Ubuntu/Debian)
sudo a2enmod ssl
sudo a2enmod headers
sudo systemctl reload apache2
# 使用 Certbot Apache 插件自动配置
sudo certbot --apache -d example.com -d www.example.com
4.2 手动 Apache 配置
# /etc/apache2/sites-available/example.com-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
DocumentRoot /var/www/example.com/html
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# SSL 协议(TLS 1.2 及以上)
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
SSLHonorCipherOrder off
SSLSessionTickets off
# OCSP Stapling
SSLUseStapling on
SSLStaplingCache "shmcb:logs/ssl_stapling(32768)"
# HSTS
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
ErrorLog ${APACHE_LOG_DIR}/example.com-ssl-error.log
CustomLog ${APACHE_LOG_DIR}/example.com-ssl-access.log combined
</VirtualHost>
</IfModule>
# HTTP → HTTPS 重定向
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
Redirect permanent / https://example.com/
</VirtualHost>
# 启用站点
sudo a2ensite example.com-ssl.conf
# 验证配置并应用
sudo apachectl configtest
sudo systemctl reload apache2
5. 签发通配符证书(DNS-01)
通配符证书(*.example.com)只需一张证书即可覆盖所有子域名(app.example.com、api.example.com 等),非常方便。但它只支持 DNS-01 质询。
5.1 手动 DNS-01 签发
# 手动 DNS 质询
sudo certbot certonly --manual --preferred-challenges=dns \
-d example.com -d "*.example.com"
# Certbot 会输出类似下面的信息:
# Please deploy a DNS TXT record under the name:
# _acme-challenge.example.com
# with the following value:
# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# 将上述 TXT 记录手动添加到 DNS 管理面板
# 添加后确认 DNS 传播情况(按 Enter 前)
dig -t txt _acme-challenge.example.com
# 确认 DNS 已传播后按 Enter 进行验证
dig 命令确认传播完成后再按 Enter。过早按 Enter 会导致验证失败。
5.2 DNS API 自动化(Cloudflare 示例)
如果你使用 Cloudflare、Route53、Google Cloud DNS 等,可通过 API 实现自动化:
# 安装 Cloudflare 插件
sudo snap install certbot-dns-cloudflare
# 或
sudo apt install python3-certbot-dns-cloudflare -y
# 保存 Cloudflare API Token (/root/.secrets/cloudflare.ini)
sudo mkdir -p /root/.secrets
sudo cat > /root/.secrets/cloudflare.ini << 'EOF'
dns_cloudflare_api_token = YOUR_CLOUDFLARE_API_TOKEN
EOF
sudo chmod 600 /root/.secrets/cloudflare.ini
# 自动签发通配符证书
sudo certbot certonly \
--dns-cloudflare \
--dns-cloudflare-credentials /root/.secrets/cloudflare.ini \
-d example.com -d "*.example.com"
# Route53 插件 (AWS)
sudo snap install certbot-dns-route53
sudo certbot certonly \
--dns-route53 \
-d example.com -d "*.example.com"
# (IAM 凭证需配置在环境变量或 ~/.aws/credentials 中)
6. 证书自动续期
Let's Encrypt 证书每 90 天需要续期一次。Certbot 默认支持自动续期。
6.1 检查自动续期
# 自动续期测试(不实际续期,仅模拟)
sudo certbot renew --dry-run
# 强制续期(即使距到期还有 30 天以上)
sudo certbot renew --force-renewal
# 仅续期指定域名
sudo certbot renew --cert-name example.com
# 自动续期定时器状态 (systemd)
sudo systemctl status certbot.timer
# cron 方式(snap 版本自动配置)
systemctl list-timers | grep certbot
6.2 自动续期机制
Certbot 在安装时会配置自动续期机制:
- systemd timer:
/etc/systemd/system/certbot.timer(snap/最新安装) - cron:
/etc/cron.d/certbot(apt 安装) - 运行周期:每天 2 次(每 12 小时)
- 续期条件:仅在到期 30 天以内的证书才会实际续期
# 手动注册 cron(如需要)
sudo crontab -e
# 每天凌晨 3 点检查自动续期
0 3 * * * /usr/bin/certbot renew --quiet --post-hook "systemctl reload nginx"
# 续期后执行指定命令 (hook)
sudo certbot renew --post-hook "systemctl reload nginx"
sudo certbot renew --deploy-hook "systemctl reload nginx"
6.3 配置续期失败通知
# 修改通知邮箱
sudo certbot update_account --email new@example.com
# 续期失败时执行脚本
# /etc/letsencrypt/renewal-hooks/deploy/notify.sh
#!/bin/bash
echo "Certificate renewed: $RENEWED_DOMAINS" | mail -s "SSL Renewal" admin@example.com
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/notify.sh
7. 证书管理命令
7.1 常用 Certbot 命令
# 查看已签发证书列表
sudo certbot certificates
# 删除指定证书
sudo certbot delete --cert-name example.com
# 重新签发证书(添加其他域名)
sudo certbot certonly --expand -d example.com -d www.example.com -d blog.example.com
# 使用 ECDSA 密钥(比 RSA 更快、更小)
sudo certbot certonly --nginx --key-type ecdsa --elliptic-curve secp384r1 \
-d example.com -d www.example.com
# 使用指定邮箱注册
sudo certbot register --email admin@example.com --agree-tos
# 查看证书详细信息
openssl x509 -in /etc/letsencrypt/live/example.com/fullchain.pem -text -noout
# 查看到期日
echo | openssl s_client -connect example.com:443 2>/dev/null | \
openssl x509 -noout -dates
7.2 证书文件结构
| 文件名 | 说明 |
|---|---|
cert.pem |
仅服务器证书(单独) |
chain.pem |
中间 CA 证书链 |
fullchain.pem |
服务器证书 + 中间链(用于 Nginx/Apache) |
privkey.pem |
私钥(绝对不能泄露!) |
privkey.pem 绝对不要上传到 Git 仓库、共享文件夹或外部服务。一旦泄露,必须立即重新签发证书并吊销(revoke)原有证书。
8. HTTPS 配置验证与优化
8.1 在线 SSL 检测工具
- SSL Labs (Qualys):https://www.ssllabs.com/ssltest/ - 最权威的 SSL 检测工具。目标是 A+ 等级。
- Mozilla Observatory:https://observatory.mozilla.org/ - 综合安全评分
- testssl.sh:可在本地运行的 CLI 工具
- SSL Configuration Generator:https://ssl-config.mozilla.org/ - 自动生成最佳配置
# 使用 testssl.sh 本地检测
git clone https://github.com/drwetter/testssl.sh.git
cd testssl.sh
./testssl.sh https://example.com
# 查看证书链
curl -vI https://example.com 2>&1 | grep -i "SSL\|certificate"
# 查看协议/加密套件
nmap --script ssl-enum-ciphers -p 443 example.com
8.2 争取 A+ 等级的额外配置
# 生成 Strong DH Parameters(比较耗时)
sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
# 在 Nginx 配置中添加
ssl_dhparam /etc/nginx/dhparam.pem;
# 安全响应头(SSL Labs A+ 要求)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options DENY always;
add_header X-Content-Type-Options nosniff always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline';" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
8.3 HSTS Preload 注册
注册到 HSTS preload 后,即使用户首次访问你的网站,浏览器也会强制使用 HTTPS 连接:
# 注册条件(需全部满足)
1. 拥有有效证书
2. HTTP → HTTPS 重定向
3. 所有子域名均提供 HTTPS
4. HSTS 响应头中 max-age=63072000(2 年)以上
5. HSTS 响应头中包含 includeSubDomains
6. HSTS 响应头中包含 preload
# 注册网址:https://hstspreload.org/
9. 常见问题与解决方法
9.1 "Connection refused" 错误
Problem: Failed authorization procedure.
example.com (http-01): urn:ietf:params:acme:error:connection :: The server could not connect to the client to verify the domain :: Fetching http://example.com/.well-known/acme-challenge/xxx: Connection refused
原因:80 端口从外部无法访问
解决:
- 在防火墙中允许 80 端口:
sudo ufw allow 80/tcp - 在云平台安全组中放行 HTTP
- 确认域名解析到正确的 IP:
dig example.com
9.2 Rate Limit 超限
Problem: too many certificates already issued for exact set of domains
原因:达到 Let's Encrypt 的签发限制
Let's Encrypt 的主要 Rate Limit:
- 相同域名集合每周 5 次重复签发限制
- 同一注册域名每周 50 份证书
- 失败的验证尝试每小时 5 次
解决:
- 测试环境使用
--staging选项(无限制) - 等待一段时间后重试(通常 1 周)
- 添加域名以改变域名集合
# 在 staging 环境中测试
sudo certbot --nginx --staging -d example.com
# staging 证书在实际浏览器中不会被信任
# 配置完成后正式签发:
sudo certbot --nginx --force-renewal -d example.com
9.3 DNS 验证失败
Problem: DNS problem: NXDOMAIN looking up TXT for _acme-challenge.example.com
原因:DNS TXT 记录尚未传播
解决:
# 检查 TXT 记录
dig -t txt _acme-challenge.example.com
# 通过 Google DNS 查询
dig -t txt _acme-challenge.example.com @8.8.8.8
# 通过 Cloudflare DNS 查询
dig -t txt _acme-challenge.example.com @1.1.1.1
# 全部返回相同值则表示传播完成
9.4 混合内容(Mixed Content)警告
在 HTTPS 页面中加载 HTTP 资源(图片、脚本等)时,浏览器会发出警告。
解决:
- 将 HTML 中的
http://改为//(协议相对)或https:// - 通过 CSP 响应头自动升级:
upgrade-insecure-requests
# 在 Nginx 中自动升级
add_header Content-Security-Policy "upgrade-insecure-requests" always;
9.5 证书续期失败
# 查看续期日志
sudo journalctl -u certbot.timer
sudo cat /var/log/letsencrypt/letsencrypt.log
# 常见原因
# 1. Web 服务器配置错误 → nginx -t / apachectl configtest
# 2. 防火墙拦截 → ufw status / firewall-cmd --list-all
# 3. 磁盘已满 → df -h
# 4. DNS 变更 → dig example.com
# 手动强制续期
sudo certbot renew --force-renewal --cert-name example.com
10. 实战运维检查清单
10.1 证书签发后的确认事项
- ✅ 浏览器访问确认:
https://example.com是否无警告打开 - ✅ 锁形图标确认:地址栏是否显示绿色锁形图标
- ✅ HTTP 重定向确认:
http://example.com是否自动跳转到 HTTPS - ✅ SSL Labs 等级确认:至少 A 等级,争取 A+
- ✅ 自动续期测试:
certbot renew --dry-run是否成功 - ✅ 证书到期监控:设置到期前 30 天提醒
- ✅ 备份:定期备份
/etc/letsencrypt/目录
10.2 证书监控脚本
#!/bin/bash
# /usr/local/bin/check_ssl_expiry.sh - 证书到期监控
DOMAINS=("example.com" "api.example.com" "blog.example.com")
WARNING_DAYS=30
ALERT_EMAIL="admin@example.com"
for domain in "${DOMAINS[@]}"; do
expiry_date=$(echo | openssl s_client -servername "$domain" \
-connect "$domain:443" 2>/dev/null | \
openssl x509 -noout -enddate | cut -d= -f2)
expiry_epoch=$(date -d "$expiry_date" +%s)
now_epoch=$(date +%s)
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
echo "$domain: $days_left days remaining"
if [ $days_left -lt $WARNING_DAYS ]; then
echo "WARNING: $domain expires in $days_left days!" | \
mail -s "SSL Expiry Alert: $domain" "$ALERT_EMAIL"
fi
done
# 授予执行权限并注册 cron
sudo chmod +x /usr/local/bin/check_ssl_expiry.sh
# 每天上午 9 点执行
sudo crontab -e
# 0 9 * * * /usr/local/bin/check_ssl_expiry.sh
结论:用 Let's Encrypt 为所有网站启用 HTTPS
Let's Encrypt 不只是一个免费 SSL 证书的概念,更是一次将整个 Web 安全水平提升到新高度的创新。过去因成本问题而放弃 HTTPS 的众多网站,如今都已全部以安全的 HTTPS 对外提供服务,这对用户和服务提供者来说都是双赢的改变。
本指南涉及的核心要点总结如下:
- 用 Certbot 实现自动化 - 手动签发和续期容易出错。请务必启用 Certbot 的自动续期。
- 通配符使用 DNS-01 - 如果运营多个子域名,通配符证书要方便得多。
- 一定要配置监控 - 即使设置了自动续期也可能失败,到期监控是必不可少的。
- 以 SSL Labs A+ 等级为目标 - 不只是简单启用 HTTPS,还要同时应用优化的 SSL 配置。
- HSTS 要谨慎启用 - 一旦启用就难以撤回,请在所有配置都完美时再启用。
- 严格保护私钥 -
privkey.pem绝对不能泄露到外部。
使用 Let's Encrypt 和 Certbot,几分钟内即可构建生产级 HTTPS。请将本指南中的示例按实际环境加以调整,打造安全的 Web 服务。