阿里云域名 + Nginx + acme.sh 自动申请通配符 HTTPS 证书教程

阿里云域名 + Nginx + acme.sh 自动申请通配符 HTTPS 证书教程(脱敏版)

本文使用通用示例,不包含真实域名、邮箱、IP、AccessKey 或服务器标识。

请按实际情况替换:

  • example.com
  • your-email@example.com
  • YOUR_ACCESS_KEY_ID
  • YOUR_ACCESS_KEY_SECRET
  • YOUR_SERVER_PUBLIC_IP

1. 适用场景

  • 服务器运行在阿里云
  • 域名 DNS 由阿里云云解析管理
  • 服务器已经安装 Nginx
  • 需要申请根域名和一级通配符证书
  • 需要证书自动续期
  • 续期后自动重新加载 Nginx

申请目标:

text 复制代码
example.com
*.example.com

可覆盖:

text 复制代码
example.com
www.example.com
admin.example.com
api.example.com

不能覆盖:

text 复制代码
test.api.example.com

2. 配置域名解析

进入阿里云控制台:

text 复制代码
云解析 DNS → 权威解析

如果所有一级子域名都指向同一台服务器,可以配置:

记录类型 主机记录 记录值
A @ YOUR_SERVER_PUBLIC_IP
A * YOUR_SERVER_PUBLIC_IP

说明:

text 复制代码
@  表示根域名 example.com
*  表示所有一级子域名

也可以逐个添加:

text 复制代码
www    A    YOUR_SERVER_PUBLIC_IP
admin  A    YOUR_SERVER_PUBLIC_IP
api    A    YOUR_SERVER_PUBLIC_IP

3. 放行端口

阿里云安全组建议放行:

text 复制代码
TCP 80
TCP 443

本教程使用 DNS-01 验证,申请证书本身不依赖 80 端口,但网站访问仍需要开放 80 和 443。


4. 创建阿里云 RAM 用户

不建议在服务器中使用阿里云主账号 AccessKey。

进入:

text 复制代码
阿里云控制台 → RAM 访问控制 → 用户

创建一个证书申请专用 RAM 用户,例如:

text 复制代码
acme-dns

创建 AccessKey,并妥善保存:

text 复制代码
AccessKey ID
AccessKey Secret

可以先授予:

text 复制代码
AliyunDNSFullAccess

生产环境建议进一步收敛为只允许查询、添加和删除 DNS 解析记录的自定义最小权限。

不要把 AccessKey 写入 Git 仓库、聊天记录、截图或公开日志。


5. 安装 acme.sh

建议使用 root 用户执行:

bash 复制代码
sudo -i

安装:

bash 复制代码
curl https://get.acme.sh | sh -s email=your-email@example.com

加载环境变量:

bash 复制代码
source ~/.bashrc

检查版本:

bash 复制代码
~/.acme.sh/acme.sh --version

设置默认 CA 为 Let's Encrypt:

bash 复制代码
~/.acme.sh/acme.sh --set-default-ca --server letsencrypt

6. 配置阿里云 DNS API

在当前终端执行:

bash 复制代码
export Ali_Key="YOUR_ACCESS_KEY_ID"
export Ali_Secret="YOUR_ACCESS_KEY_SECRET"

变量名必须保持:

text 复制代码
Ali_Key
Ali_Secret

首次成功调用后,acme.sh 会保存相关配置,后续自动续期通常不需要再次手工导出。


7. 申请根域名和通配符证书

执行:

bash 复制代码
~/.acme.sh/acme.sh --issue \
  --server letsencrypt \
  --dns dns_ali \
  -d example.com \
  -d '*.example.com' \
  --keylength ec-256

参数说明:

text 复制代码
--dns dns_ali        使用阿里云 DNS API
-d example.com       申请根域名
-d '*.example.com'   申请一级通配符域名
--keylength ec-256   使用 ECC P-256 私钥

通配符参数建议使用单引号:

bash 复制代码
-d '*.example.com'

8. 将证书安装到 Nginx 目录

创建目录:

bash 复制代码
mkdir -p /etc/nginx/ssl/example.com

安装证书:

bash 复制代码
~/.acme.sh/acme.sh --install-cert -d example.com \
  --ecc \
  --key-file /etc/nginx/ssl/example.com/private.key \
  --fullchain-file /etc/nginx/ssl/example.com/fullchain.pem \
  --reloadcmd "nginx -t && nginx -s reload"

因为申请时使用了:

bash 复制代码
--keylength ec-256

所以安装和续期时必须带:

bash 复制代码
--ecc

设置权限:

bash 复制代码
chmod 600 /etc/nginx/ssl/example.com/private.key
chmod 644 /etc/nginx/ssl/example.com/fullchain.pem

9. 配置 Nginx HTTPS

9.1 WebSocket 公共配置

创建:

bash 复制代码
vi /etc/nginx/conf.d/00-websocket-map.conf

内容:

nginx 复制代码
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

map 只配置一次,不要在多个站点文件中重复定义。

9.2 前端站点示例

nginx 复制代码
server {
    listen 80;
    server_name www.example.com;

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

server {
    listen 443 ssl http2;
    server_name www.example.com;

    ssl_certificate     /etc/nginx/ssl/example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com/private.key;

    ssl_protocols TLSv1.2 TLSv1.3;

    root /path/to/web;
    index index.html;

    location / {
        try_files $uri $uri.html $uri/ /index.html;
    }

    location ~ ^/(api|v1)(/|$) {
        proxy_pass http://127.0.0.1:3000;

        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

9.3 管理端示例

nginx 复制代码
server {
    listen 80;
    server_name admin.example.com;

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

server {
    listen 443 ssl http2;
    server_name admin.example.com;

    ssl_certificate     /etc/nginx/ssl/example.com/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com/private.key;

    ssl_protocols TLSv1.2 TLSv1.3;

    location / {
        proxy_pass http://127.0.0.1:3000;

        proxy_http_version 1.1;

        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;

        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;

        proxy_read_timeout 300s;
        proxy_send_timeout 300s;
    }
}

检查并重新加载:

bash 复制代码
nginx -t && systemctl reload nginx

10. 查看自动续期任务

acme.sh 安装后通常会自动创建 crontab:

bash 复制代码
crontab -l

示例:

cron 复制代码
17 0 * * * "/root/.acme.sh/acme.sh" --cron --home "/root/.acme.sh" > /dev/null

含义:

text 复制代码
每天检查一次证书是否需要续期

并不是每天都重新签发。


11. 建议启用续期日志

编辑:

bash 复制代码
crontab -e

将任务改成:

cron 复制代码
17 0 * * * "/root/.acme.sh/acme.sh" --cron --home "/root/.acme.sh" >> /var/log/acme-renew.log 2>&1

查看日志:

bash 复制代码
tail -n 100 /var/log/acme-renew.log

实时查看:

bash 复制代码
tail -f /var/log/acme-renew.log

12. 验证证书

查看 acme.sh 证书列表:

bash 复制代码
~/.acme.sh/acme.sh --list

查看本地证书:

bash 复制代码
openssl x509 \
  -in /etc/nginx/ssl/example.com/fullchain.pem \
  -noout \
  -subject \
  -issuer \
  -dates \
  -ext subjectAltName

检查线上证书:

bash 复制代码
openssl s_client \
  -connect www.example.com:443 \
  -servername www.example.com \
  </dev/null 2>/dev/null |
openssl x509 \
  -noout \
  -subject \
  -issuer \
  -dates \
  -ext subjectAltName

13. 测试自动续期

测试 cron 检查流程:

bash 复制代码
/root/.acme.sh/acme.sh --cron --home /root/.acme.sh

强制测试一次续期:

bash 复制代码
~/.acme.sh/acme.sh --renew \
  -d example.com \
  --ecc \
  --force

成功后应看到类似:

text 复制代码
Cert success.
Installing key to: /etc/nginx/ssl/example.com/private.key
Installing full chain to: /etc/nginx/ssl/example.com/fullchain.pem
Running reload cmd: nginx -t && nginx -s reload
Reload successful

--force 仅用于首次验证,不要频繁执行。


14. 常见问题

Nginx 报 unknown directive "http2"

旧版本 Nginx 不支持:

nginx 复制代码
http2 on;

改为:

nginx 复制代码
listen 443 ssl http2;

如果仍不支持,先使用:

nginx 复制代码
listen 443 ssl;

检查模块:

bash 复制代码
nginx -V 2>&1 | grep http_v2_module

页面返回 502

502 Bad Gateway 通常不是证书问题,而是 Nginx 无法连接后端。

检查 Docker 端口:

bash 复制代码
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"

如果容器映射为:

text 复制代码
0.0.0.0:3000->3000/tcp

Nginx 应配置:

nginx 复制代码
proxy_pass http://127.0.0.1:3000;

测试:

bash 复制代码
curl -v http://127.0.0.1:3000/

查看错误日志:

bash 复制代码
tail -n 100 /var/log/nginx/error.log

路径写错

不要保留教程中的示例路径:

text 复制代码
/etc/nginx/ssl/example.com/

应替换成自己的真实域名目录。

通配符证书不能覆盖根域名

单独申请:

text 复制代码
*.example.com

不能覆盖:

text 复制代码
example.com

因此必须同时申请:

bash 复制代码
-d example.com
-d '*.example.com'

15. 流程总结

text 复制代码
创建阿里云 RAM 用户
        ↓
获取专用 AccessKey
        ↓
安装 acme.sh
        ↓
配置 Ali_Key 和 Ali_Secret
        ↓
使用 dns_ali 申请根域名和通配符证书
        ↓
安装证书到 Nginx 正式目录
        ↓
Nginx 配置 HTTPS
        ↓
acme.sh 每天自动检查续期
        ↓
续期成功后自动检查并重新加载 Nginx