开启网站HTTPS

芸殇
2024-03-14 / 0 评论 / 0 阅读 / 正在检测是否收录...

使用 acme.sh 为 Nginx 申请、部署 HTTPS 证书并自动续期

本文使用虚构示例介绍宝塔与 Nginx 的 HTTPS 申请部署流程。example.com、203.0.113.10 和 DNS 地址均为文档占位符,使用时须替换为自己的配置。

一、示例环境与路径

项目示例值
域名blog.example.com
服务器 IP203.0.113.10
ACME 客户端/opt/acme/acme.sh
HTTP 验证目录/www/acme
HTTPS 网站配置/www/server/panel/vhost/nginx/blog.example.com.conf
HTTP 验证配置/www/server/panel/vhost/nginx/blog-acme-http.conf
部署证书目录/www/server/panel/vhost/cert/blog.example.com
自动续期任务/etc/cron.d/acme-renew
自动续期日志/var/log/acme-renew.log

所有配置路径均为示例,应按自己的服务器调整。

以下命令在服务器上以 root 执行。证书私钥、ACME 账户密钥不要放入博客或公开仓库。

二、先确认域名解析

在域名解析控制台添加或修改:

记录类型:A
主机记录:blog
记录值:203.0.113.10

仅在解析列表里添加记录还不够:域名注册商配置的 DNS 服务器必须与解析服务商分配的地址一致。DNS 地址应使用服务商实际分配的值,以下仅为占位符:

ns1.dns-provider.example
ns2.dns-provider.example

如果控制台提示“未接入使用云解析 DNS,当前配置的解析记录不会生效”,应到域名注册管理中的 DNS 修改页面更改 DNS 服务器,而不是在解析列表中新增 NS 记录代替。其他域名应使用其控制台实际分配的地址。

检查解析与网络:

getent hosts blog.example.com
curl -I --max-time 10 http://blog.example.com/

阿里云安全组和服务器防火墙需要允许 TCP 80、443。HTTP-01 验证需要公网访问 80 端口;不要直接关闭防火墙。

三、安装 acme.sh(已有安装可跳过)

从官方项目下载脚本:

mkdir -p /opt/acme-bootstrap
cd /opt/acme-bootstrap
curl -fL --connect-timeout 10 --max-time 60 \
  https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh \
  -o acme.sh

确认下载成功并查看脚本后,从脚本所在目录执行安装:

cd /opt/acme-bootstrap
sh acme.sh --install --home /opt/acme --nocron
sh /opt/acme/acme.sh --home /opt/acme --version

本教程使用独立 cron 任务,因此安装时指定 --nocron,避免重复配置。后续命令始终显式传入 --home /opt/acme。

如果服务器无法连接 GitHub,可在自己的电脑从同一官方地址下载,再通过 scp 上传。不要因为网络失败改用来历不明的脚本,也不要关闭 TLS 校验。

官方项目与完整说明:https://github.com/acmesh-official/acme.sh

四、配置 HTTP 验证路径

已有配置时,续期不要重复创建同名 server。新部署时,先备份现有 Nginx 配置,确保这个域名在 80 端口只有一个匹配的虚拟主机。

创建验证目录:

mkdir -p /www/acme/.well-known/acme-challenge

当前 blog-acme-http.conf 的内容为:

server {
    listen 80;
    listen [::]:80;
    server_name blog.example.com;

    location ^~ /.well-known/acme-challenge/ {
        root /www/acme;
        default_type text/plain;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

HTTPS 网站原配置中保留 443 监听,并移除该域名重复的 80 监听。验证路径直接返回文件,其余 HTTP 请求跳转 HTTPS。不要在上述 HTTP server 中加入会对所有请求执行的 HTTPS 重写,否则验证文件也可能被重定向。

检查并重载配置:

/www/server/nginx/sbin/nginx -t && \
  /www/server/nginx/sbin/nginx -s reload

测试验证路径:

printf 'acme-ready\n' > /www/acme/.well-known/acme-challenge/probe
curl --max-time 10 http://blog.example.com/.well-known/acme-challenge/probe

应该直接输出 acme-ready,而不是 404、登录页或跳转页面。最好同时从另一台电脑测试公网访问。

五、申请 Let's Encrypt 证书

申请前阅读签发机构条款;提交注册申请可能涉及接受其服务协议。为自己的域名申请,不要使用他人域名。

sh /opt/acme/acme.sh --home /opt/acme \
  --issue --server letsencrypt \
  -d blog.example.com \
  -w /www/acme \
  --keylength ec-256

成功后会显示 Cert success。ECC 证书及密钥保存在:

/opt/acme/blog.example.com_ecc/

该目录由 acme.sh 管理。部署时使用 --install-cert 复制证书到 Nginx 的固定路径,不要把 Nginx 直接指向 ACME 内部工作文件。

六、部署证书并重载 Nginx

修改前先备份现有证书及 Nginx 配置。备份应保存在仅 root 可访问的目录,且不要覆盖唯一一份旧备份。

CERT_DIR=/www/server/panel/vhost/cert/blog.example.com
BACKUP_DIR=/var/backups/https-$(date +%Y%m%d-%H%M%S)
mkdir -m 700 "$BACKUP_DIR"
cp -a "$CERT_DIR" "$BACKUP_DIR/"
cp -a /www/server/panel/vhost/nginx/blog.example.com.conf "$BACKUP_DIR/"

安装证书,并让 acme.sh 记住续期后的部署路径和重载命令:

sh /opt/acme/acme.sh --home /opt/acme \
  --install-cert --ecc -d blog.example.com \
  --key-file /www/server/panel/vhost/cert/blog.example.com/privkey.pem \
  --fullchain-file /www/server/panel/vhost/cert/blog.example.com/fullchain.pem \
  --reloadcmd '/www/server/nginx/sbin/nginx -t && /www/server/nginx/sbin/nginx -s reload'

chmod 600 /www/server/panel/vhost/cert/blog.example.com/privkey.pem

HTTPS server 中的证书配置应对应:

ssl_certificate /www/server/panel/vhost/cert/blog.example.com/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/blog.example.com/privkey.pem;

fullchain.pem 包含站点证书及中间证书链。单独复制站点证书可能造成部分客户端无法建立信任链。

七、验证部署结果

查看文件中的证书信息:

openssl x509 \
  -in /www/server/panel/vhost/cert/blog.example.com/fullchain.pem \
  -noout -dates -issuer -ext subjectAltName

验证公网 HTTPS:

curl -I --max-time 15 https://blog.example.com/

正常应返回 HTTP 200 或预期的业务跳转,且不能出现证书验证错误。这里不要加 -k,否则会跳过证书校验。

若 DNS 缓存尚未一致,可直接验证新服务器,但仍使用域名进行证书校验:

curl --resolve blog.example.com:443:203.0.113.10 \
  -I https://blog.example.com/

浏览器应通过域名访问。证书只覆盖 blog.example.com,不覆盖服务器 IP,也不自动覆盖 www.example.com。

八、配置自动续期

示例任务文件为 /etc/cron.d/acme-renew,内容为:

17 3 * * * root /bin/sh /opt/acme/acme.sh --cron --home /opt/acme >> /var/log/acme-renew.log 2>&1

这表示每天按服务器本地时间 03:17 检查是否需要续期,并非每天都重新签发。acme.sh 根据证书状态和 CA 信息决定续期时间;成功后会使用已保存的路径部署,并重载 Nginx。

检查任务和服务:

cat /etc/cron.d/acme-renew
systemctl is-active crond
sh /opt/acme/acme.sh --cron --home /opt/acme
tail -n 50 /var/log/acme-renew.log

显示 Skipping 并给出下次续期时间通常是正常现象,表示现在还不需要续期。若任务尚未运行,日志文件可能还不存在。

需要提前续期时先用普通命令:

sh /opt/acme/acme.sh --home /opt/acme \
  --renew --ecc -d blog.example.com

只有确认需要立即重签时才添加 --force。不要反复强制申请,以免触发签发限制。

九、常见问题

DNS 查询失败或验证一直 Pending

检查注册商 DNS 服务器、A 记录、是否有错误 AAAA 记录、80 端口、安全组和验证文件路径。不同递归 DNS 的缓存更新时间可能不同。不要看到某一台机器能解析,就认定所有验证节点都已更新。

证书已经更新,但浏览器仍显示“不安全”

先确认浏览器访问的是 https://blog.example.com/,再查看它实际收到的证书域名和有效期。用新无痕窗口复测;如仍异常,检查开发者工具 Security、Console、Network 中的证书或混合内容错误。不要简单假定所有异常都是缓存,也不要通过跳过安全警告作为长期解决方法。

文件中的证书是新的,但网站仍提供旧证书

检查 Nginx 实际使用的虚拟主机和证书路径,执行 nginx -t 后再重载。如果有 CDN 或负载均衡,还要检查入口节点的证书。

acme.sh 安装报 cannot stat 'acme.sh'

从下载脚本所在目录执行安装。示例:

cd /opt/acme-bootstrap
sh acme.sh --install --home /opt/acme --nocron

续期失败

先查看 /var/log/acme-renew.log,确认域名仍指向这台服务器、HTTP 验证目录仍可访问、cron 正常、续期后的 reload 命令仍有效。修改宝塔网站配置后,也要检查验证路径有没有被删除或覆盖。

0

评论 (0)

取消