给一个静态站点配上 HTTPS,本质上就三步:签发证书、配置 Nginx、设置自动续期。 这篇是我反复用过几次后整理的最小流程备忘。
1. 先用 HTTP 起站,留好验证路径
证书签发(HTTP-01 验证)需要让签发机构能通过 http://你的域名/.well-known/ acme-challenge/ 访问到一个临时文件。所以 Nginx 里要先保证 80 端口可达,并把
这个路径指向 webroot:
server {
listen 80;
server_name example.com www.example.com;
location ^~ /.well-known/acme-challenge/ {
root /var/www/example;
}
location / {
return 301 https://$host$request_uri;
}
}
注意:80 → 443 的跳转要把验证路径排除在外,否则签发时会被 301 带走导致验证 失败。
2. 用 acme.sh 签发证书
我用的是 acme.sh,纯脚本、不依赖 root 守护进程:
# 签发(ECC 证书,webroot 方式)
acme.sh --issue -d example.com -w /var/www/example \
--keylength ec-256 --server zerossl
# 安装到固定路径,并配置签发后自动 reload
acme.sh --install-cert -d example.com --ecc \
--key-file /etc/nginx/ssl/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com.crt \
--reloadcmd "systemctl reload nginx"
--install-cert 这一步很关键:它会把证书复制到稳定路径,并记住 reload 命令,
之后续期时会自动执行。
3. 配置 443
server {
listen 443 ssl http2;
server_name example.com www.example.com;
ssl_certificate /etc/nginx/ssl/example.com.crt;
ssl_certificate_key /etc/nginx/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
root /var/www/example;
index index.html;
location / { try_files $uri $uri/ =404; }
}
改完 nginx -t 检查语法,再 systemctl reload nginx。
4. 自动续期
acme.sh 安装时会自动加一条 cron(或 systemd timer),每天检查一次,证书到期前 30 天左右自动续期并执行上面配置的 reload 命令。一般不用手动管,只要确认定时任 务在跑:
crontab -l | grep acme
踩过的坑:DNSSEC 导致 Let’s Encrypt 签发失败
这是最花时间的一个坑。我有个域名挂在开启了 DNSSEC 的后缀下,但子域没有配置对应
的 DNSKEY/DS 记录。结果 Let’s Encrypt 在做 DNS 校验时会因为 DNSSEC 链不完整
而查询超时(报错类似 DNSKEY Missing)。
解决办法是换用不强制做该校验的签发机构,比如 ZeroSSL:上面命令里的
--server zerossl 就是为此。同一套 acme.sh 流程,换个 CA 立刻就签出来了。
小结:遇到莫名其妙的签发超时,除了看 80 端口和防火墙,也记得排查一下域名的 DNSSEC 配置。