目录

使用acme申请并自动更新SSL证书


安装acme.sh(非root用户下执行)

# 运行安装脚本
wget -O -  https://get.acme.sh | sh

# 让 acme.sh 命令生效
. .bashrc

# 开启 acme.sh 的自动升级
acme.sh --upgrade --auto-upgrade

证书申请-独立配置专属验证目录(非root用户下执行)

  • Nginx 独立配置专属验证目录(非root用户下执行)

先创建专属验证目录,与实际网站路径解耦;该目录用于acme.sh通用验证,无必须放置index.html;

后续所有网站均可共用这一个目录;

# 创建目录
mkdir -p ~/websites/acme_challenge

# 创建index.html网页
nano ~/websites/acme_challenge/index.html

# 保存完index.html后
chmod -R a+r ~/websites/acme_challenge
  • 简单网页 index.html

    <!DOCTYPE html>
    <html lang="zh">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>简单的网页</title>
    </head>
    <body>
        <h1>Hi!欢迎来到我的网页</h1>
        <p>这是一个非常简单的HTML网页。</p>
    </body>
    </html>
    

Nginx里配置80端口验证路径,sudo nano /etc/nginx/nginx.conf

  #
  # 统一处理所有常规网站的80端口
  #   - 浏览器访问指定长路径验证连通性
  # 	- acme.sh 证书申请/更新的验证
  #   - https 重定向
  #
  server {
    listen 80;
    server_name a.xxx.com
                b.xxx.com
                c.xxx.com;

    # 指定长路径,用于起初浏览器访问验证连通性
    # alias后的路径下放index.html文件
    location = /hello-world-test {
        alias /home/username/websites/acme_challenge/;
        try_files /index.html =404; # 必须是try_files,不是index, index会有重定向问题
    }

    # 所有域名的 acme 验证请求都会被拦截到这里, 与实际网站路径解耦
    location /.well-known/acme-challenge/ {
        root /home/username/websites/acme_challenge/; # 必须是root,不能是 alias
        try_files $uri =404;
    }

    # 所有其余常规 80 端口访问,一律强制重定向到 HTTPS
    location / {
        # 重定向http->https
        return 301 https://$host$request_uri;
    }
  }
  • 申请(非root用户下执行)

将证书申请下载下来(但下载的证书存放的目录不是最终我们想要的目录,需要后续安装);

acme.sh --set-default-ca --server letsencrypt

# -w 后的目录是网站文件所在目录
# 与nginx中配置的80端口location /.well-known/acme-challenge/下的alias路径一致
acme.sh --issue -d xxxx.com -w ~/websites/acme_challenge --keylength ec-256 --force

# 申请成功
[Tue Jun 16 08:15:43 AM UTC 2026] Your cert is in: /home/username/.acme.sh/xxxx.com_ecc/xxxx.com.cer
[Tue Jun 16 08:15:43 AM UTC 2026] Your cert key is in: /home/username/.acme.sh/xxxx.com_ecc/xxxx.com.key
[Tue Jun 16 08:15:43 AM UTC 2026] The intermediate CA cert is in: /home/username/.acme.sh/xxxx.com_ecc/ca.cer
[Tue Jun 16 08:15:43 AM UTC 2026] And the full-chain cert is in: /home/username/.acme.sh/xxxx.com_ecc/fullchain.cer
[Tue Jun 16 08:15:44 AM UTC 2026] ARI suggestedWindow: 2026-08-14T10:01:15Z to 2026-08-16T05:12:05Z
[Tue Jun 16 08:15:44 AM UTC 2026] Next renewal time picked from ARI window: 2026-08-16T01:06:59Z

证书安装(非root用户下执行)

将证书安装/拷贝到指定目录

  • 手动安装(不推荐,推荐后面的脚本方式安装):

    acme.sh --install-cert -d xxx.com --cert-file ~/certs/xxx.com/cert.pem --key-file ~/certs/xxx.com/key.pem --fullchain-file ~/certs/xxx.com/fullchain_cert.pem --ecc
    
    # 安装成功
    [Tue Feb 10 06:29:28 AM UTC 2026] Installing cert to: /home/username/certs/xxx.com/cert.pem
    [Tue Feb 10 06:29:28 AM UTC 2026] Installing key to: /home/username/certs/xxx.com/key.pem
    [Tue Feb 10 06:29:28 AM UTC 2026] Installing full chain to: /home/username/certs/xxx.com/fullchain_cert.pem
    
    # key.pem 文件默认对其他用户不可读,所以需要赋予其可读性权限
    chmod +r ~/certs/xxx.com/key.pem
    chmod +r ~/certs/xxx.com/ -R
    
  • 脚本方式安装:

先创建certs目录,使用自动更新脚本安装,方便后续crontab自动化

# 创建certs目录
mkdir -p ~/certs/xxx.com

# 自动更新脚本
nano ~/certs/xxx.com/cert-update.sh
chmod +x ~/certs/xxx.com/cert-update.sh

cert-update.sh:

#!/bin/bash

# ==================== 配置变量 ====================
# 你的域名
DOMAIN="xxx.com"

# 证书存放的根目录
CERT_DIR="/home/username/certs/xxx.com"

# ==================================================

# 安装证书
/home/username/.acme.sh/acme.sh --install-cert -d "$DOMAIN" \
    --cert-file "${CERT_DIR}/cert.pem" \
    --key-file "${CERT_DIR}/key.pem" \
    --fullchain-file "${CERT_DIR}/fullchain_cert.pem" \
    --ecc

echo "SSL Certificates Renewed"
echo | openssl s_client -connect "$DOMAIN":443 2>/dev/null | openssl x509 -noout -dates

# 修改权限
chmod +r "${CERT_DIR}/key.pem"
chmod +r "${CERT_DIR}/" -R
echo "Read Permission Granted for Private Key"

# 重载 Nginx
sudo systemctl reload nginx
echo "Nginx Reloaded"

然后该用户下直接执行./cert-update.sh

./certs/xxx.com/cert-update.sh
[Tue Jun 16 08:27:13 AM UTC 2026] Installing cert to: /home/username/certs/xxx.com/cert.pem
[Tue Jun 16 08:27:13 AM UTC 2026] Installing key to: /home/username/certs/xxx.com/key.pem
[Tue Jun 16 08:27:13 AM UTC 2026] Installing full chain to: /home/username/certs/xxx.com/fullchain_cert.pem
SSL Certificates Renewed
notBefore=Jun 11 10:27:51 2026 GMT
notAfter=Sep  9 10:27:50 2026 GMT
Read Permission Granted for Private Key
Nginx Reloaded

证书自动更新(非root用户下执行)

目前证书有效期时90天; acme.sh 通过在安装时自动添加定时任务(Cron Job),通常每天检查一次证书有效期。若证书临近过期(默认剩余少于30天),它会自动通过 DNS 或 HTTP 验证申请新证书并执行重载命令更新服务器,实现无需人工干预的自动续期。 

但它并无法自动安装新证书,所以我们需要新增一个系统的自动周期任务来完成安装这一步。

!!!要编辑username用户下的,而非root用户下的!!!

# 要编辑username用户下的,而非root用户下的
crontab -e

crontab:

51 23 * * * "/home/username/.acme.sh"/acme.sh --cron --home "/home/username/.acme.sh" > /dev/null

# 1:00am, 1st day each month, run "cert-update.sh`
0 1 1 * *   bash /home/username/certs/xxx.com/cert-update.sh
0 1 1 * *   bash /home/username/certs/xxx.com/cert-update.sh

其他acme使用指南

Webroot 模式下路径变更

acme.sh初次申请证书是-w(Webroot 模式)传入的路径,如果路径后续不存在/变动,会影响后续证书的自动更新;

acme.sh 的 Webroot 模式工作原理如下:

  1. 申请/续期时,Let’s Encrypt 服务器会要求验证你对域名的所有权。
  2. acme.sh 会在你指定的本地文件夹(Webroot)下创建 .well-known/acme-challenge/ 目录并写入一个随机验证文件。
  3. Let’s Encrypt 会通过互联网访问 http://yourdomain.com/.well-known/acme-challenge/xxx
  4. 问题所在:续期时是无人值守的自动化脚本在跑。如果路径 A 变成了 Bacme.sh 依然把文件写到 A(或者因为找不到 A 直接报错),而你的 Nginx/Web 服务器指向的是 B,Let’s Encrypt 访问时就会返回 404 导致续期失败。

若路径变更,有两种方式修复:

  • 方法一:直接修改 acme.sh 的配置文件(推荐,最快)

    acme.sh 为每个域名都维护了一个配置文件。

    1. 找到该域名的配置目录(默认在 ~/.acme.sh/你的域名/

    2. 打开 你的域名.conf 文件

    3. 找到 Le_Webroot 这一行

      # 它看起来像这样:
      Le_Webroot='/old/path/to/folder'
      
      # 将其修改为新的绝对路径:
      Le_Webroot='/new/path/to/folder'
      
    4. 修改后验证:

      acme.sh --renew -d yourdomain.com --force
      
  • 方法二:使用 --renew 命令带上新路径强行刷新

    acme.sh 带着新路径手动续期一次,它会自动覆盖旧的配置记录:

    acme.sh --renew -d yourdomain.com -w /new/path/to/folder --force
    

查看及管理历史域名

# 查看当前 acme.sh 还在维护的证书列表
acme.sh --list

# 从自动续期列表中移除
# --remove 命令后,acme.sh 只是把它从续期任务中剔除了,
# 但之前申请下来的证书文件、私钥以及域名的配置文件夹依然保存在服务器上(通常在 ~/.acme.sh/ 目录下)。
#为了彻底释放空间和保持清爽,可以手动把它的整套配置删掉:
acme.sh --remove -d olddomain.com
rm -rf ~/.acme.sh/olddomain.com/

-w路径错误导致失败的报错

Certbot ‘invalid response from well-known acme challenge’Certbot“来自知名 acme 质询的无效响应”

acme.sh --issue -d xxx.com -w /home/username/certs/xxx.com --keylength ec-256 --force
[Tue Jan 14 12:34:38 UTC 2025] Using CA: https://acme-v02.api.letsencrypt.org/directory
[Tue Jan 14 12:34:38 UTC 2025] Single domain='xxx.com'
[Tue Jan 14 12:34:40 UTC 2025] Getting webroot for domain='xxx.com'
[Tue Jan 14 12:34:40 UTC 2025] Verifying: xxx.com
[Tue Jan 14 12:34:41 UTC 2025] Pending. The CA is processing your order, please wait. (1/30)
[Tue Jan 14 12:34:45 UTC 2025] xxx.com: Invalid status. Verification error details: 47.79.32.103: Invalid response from http://xxx.com/.well-known/acme-challenge/hVhFFpEfCo4FYDW_tB567OoxeUKpfzfD3EAc8yOyoqg: 404
[Tue Jan 14 12:34:45 UTC 2025] Please add '--debug' or '--log' to see more information.
[Tue Jan 14 12:34:45 UTC 2025] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh

相关链接

https://github.com/acmesh-official/acme.sh

使用 ACME.SH 申请并安装 LET’S ENCRYPT SSL证书 - 易科博客