部署环境:Ubuntu 24.04
1. 前置准备
确保你的域名已正确解析到服务器公网 IP,并且 Nginx 已安装且配置了基本的 HTTP (80端口) 服务或指向了正确的网站根目录(Webroot)。
2. 签发证书 (Webroot 模式)
推荐使用 webroot 模式配合 Let’s Encrypt 官方源,该模式无需停止 Nginx,验证最稳定。
|
|
注:看到 Verify success 和 Cert success 即表示签发成功。
3. 安装证书并配置自动重载
不要直接使用 ~/.acme.sh/ 目录下的文件,应使用 --install-cert 将证书复制到 Nginx 的专属目录,并绑定 Nginx 的重载命令,以实现未来续期时的全自动化。
|
|
4. 配置 Nginx 启用 HTTPS
在 Nginx 配置文件中指定证书路径,并开启 HTTP/2 和现代 TLS 协议。
|
|
5. 验证与续期测试
测试 Nginx 配置语法,并强制触发一次续期,验证全链路是否畅通。
|
|
6.补充测试命令
|
|
7. 示例nginx配置
server {
# 仅监听 443 端口,开启 HTTP/2
listen 443 ssl http2;
server_name yourdomain.com;
# 1. 证书路径
ssl_certificate /etc/nginx/ssl/yourdomain.com.pem;
ssl_certificate_key /etc/nginx/ssl/yourdomain.com.key;
# 2. 现代 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 on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 3. 隐藏版本号 & 禁止目录浏览
server_tokens off;
autoindex off;
# 4. 安全响应头
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
# 5. 网站根目录
root /var/www/myblog/public;
index index.html;
# 6. 静态资源缓存 & Gzip
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 7d;
add_header Cache-Control "public, no-transform";
access_log off;
}
# 7. 核心路由
location / {
try_files $uri $uri/ =404;
}
# 自定义 404
error_page 404 /404.html;
}
# 可选:如果你希望有人输入 http://yourdomain.com 时直接断开连接(极简且安全)
# server {
# listen 80;
# server_name yourdomain.com;
# return 444; # Nginx 特有状态码,直接关闭连接,不返回任何 HTTP 响应
# }
踩坑记录
💣 坑1:acme.sh 缓存残留导致找不到证书文件
- 报错现象:
The domain seems to already have an ECC cert...随后提示cat: .../fullchain.cer: No such file or directory或Cannot find config file。 - 原因分析:之前中断的签发或错误的清理导致
acme.sh内部记录与实际文件系统脱节。 - 解决方案:彻底清理残留并强制重新签发。
1 2 3acme.sh --remove -d yourdomain.com --ecc rm -rf ~/.acme.sh/yourdomain.com* # 重新签发时务必加上 --force
💣 坑2:SSL 证书加载失败 (PEM 格式错误 / 权限拒绝)
- 报错现象:
nginx -t提示PEM_read_bio_X509_AUX() failed ... Expecting: TRUSTED CERTIFICATE或Permission denied。 - 原因分析:
--key-file(私钥) 和--fullchain-file(证书链) 的路径填反了。- Nginx 运行用户(如
www-data)对证书目录没有读取权限。
- 解决方案:确保路径对应正确,并修复目录权限(目录
755,pem644,key600)。
💣 坑3:80 端口被 Nginx 占用导致 Standalone 模式失败
- 报错现象:无法使用
--standalone,尝试使用--nginx模式时报Cannot find config file。 - 原因分析:
standalone需要独占 80 端口;而acme.sh的--nginx模式对非标准的 Nginx 配置文件结构解析能力较弱,容易“眼瞎”。 - 解决方案:改用
--webroot模式,直接指定 Nginx 的静态文件根目录进行验证,绕开 Nginx 进程本身的干扰。
💣 坑4:ZeroSSL 默认 CA 导致验证无限超时
- 报错现象:日志显示
Pending...多次后,提示The retryafter=86400 value is too large... will not retry anymore。 - 原因分析:
acme.sh默认切换到了 ZeroSSL CA,其验证机制在某些网络环境下会返回长达 24 小时的重试等待,导致脚本主动放弃。 - 解决方案:在签发命令中显式指定使用 Let’s Encrypt:
--server letsencrypt。
💣 坑5:Nginx 安全规则误杀 ACME 验证路径 (403 Forbidden)
- 报错现象:验证时提示
Invalid response from ... /.well-known/acme-challenge/...: 403。 - 原因分析:为了安全,Nginx 配置了
location ~ /\.来拦截所有以.开头的隐藏文件(如.git)。这不幸误杀了以.well-known开头的 ACME 验证路径。 - 解决方案:利用 Nginx 的
^~前缀匹配优先级,在拦截规则上方添加“绿色通道”:1 2 3 4 5 6 7# 优先级更高,放行验证请求 location ^~ /.well-known/acme-challenge/ { default_type "text/plain"; root /your/webroot; } # 原有的隐藏文件拦截规则 location ~ /\. { deny all; }