脚本解决雷池 WAF 的域名证书自动续签

2010 字约 7 分钟...

在没有自动化执行之前,我都是用的 utool 中的域名插件,手动生成泛域名证书,然后拷贝到 WAF 中的。

脚本解决雷池WAF的域名证书自动续签

最近想要把这件事自动化一下。

折腾第一次~

看到了一个 github 帖子【推荐】纯脚本解决雷池 WAF 自动续签问题 #987 ↗

该帖子发布较早,现在已经无法正确执行。

docker run --rm  -it -v "/data/acme":/acme.sh neilpang/acme.sh  --issue --dns dns_tencent -d *.987654321.xyz -d 987654321.xyz --yes-I-know-dns-manual-mode-enough-go-ahead-please

会报错:

[Tue Aug 25 07:35:45 UTC 2026] Using CA: https://acme.zerossl.com/v2/DV90
[Tue Aug 25 07:35:45 UTC 2026] No EAB credentials found for ZeroSSL, let's obtain them
[Tue Aug 25 07:35:45 UTC 2026] acme.sh is using ZeroSSL as default CA now.
[Tue Aug 25 07:35:45 UTC 2026] Please update your account with an email address first.
[Tue Aug 25 07:35:45 UTC 2026] acme.sh --register-account -m my@example.com
[Tue Aug 25 07:35:45 UTC 2026] See: https://github.com/acmesh-official/acme.sh/wiki/ZeroSSL.com-CA
[Tue Aug 25 07:35:45 UTC 2026] Please add '--debug' or '--log' to see more information.
[Tue Aug 25 07:35:45 UTC 2026] See: https://github.com/acmesh-official/acme.sh/wiki/How-to-debug-acme.sh

所以脚本需要添加:--register-account -m my@example.com 增加这个以后会自动拿着这个邮箱注册。

我也用的是腾讯云的域名管理,然后按照要求把SAVED_Tencent_SecretId 和 SAVED_Tencent_SecretKey 写入到 account.conf 文件。

如果使用了--issue --dns dns_tencent DNS 验证的话,那么就不需要--yes-I-know-dns-manual-mode-enough-go-ahead-please手动验证的参数了。

再次执行修改后的脚本:

docker run --rm  -it -v /opt/myapp/acme:/acme.sh neilpang/acme.sh --register-account -m aaa@qq.com --server zerossl  --issue --dns dns_tencent -d *.lichenghao.cn

执行结果,大概如下所示:

Using CA: https://acme.zerossl.com/v2/DV90
Single domain='*.lichenghao.cn'
Getting webroot for domain='*.lichenghao.cn'
Adding TXT value: Dx-5nGnsfULyqNR6K6tqniMbI for domain: _acme-challenge.lichenghao.cn
The TXT record has been successfully added.
Let's check each DNS record now. Sleeping for 20 seconds first.
You can use '--dnssleep' to disable public dns checks.
See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
Checking lichenghao.cn for _acme-challenge.lichenghao.cn
Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35
Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 28
Not valid yet, let's wait for 10 seconds then check the next one.
Let's wait for 10 seconds and check again.
You can use '--dnssleep' to disable public dns checks.
See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
Checking lichenghao.cn for _acme-challenge.lichenghao.cn
Success for domain lichenghao.cn '_acme-challenge.lichenghao.cn'.
All checks succeeded
Verifying: *.lichenghao.cn
Processing. The CA is processing your order, please wait. (1/30)
Pending. The CA is processing your order, please wait. (2/30)
Success
Removing DNS records.
Removing txt: Dx-5nGnsfU5DVC6LyqNJ_lZZIgShP11eR6K6tqniMbI for domain: _acme-challenge.lichenghao.cn
Successfully removed
Verification finished, beginning signing.
Let's finalize the order.
Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/suec4vMZuHaDZKQ/finalize'
Order status is 'processing', let's sleep and retry.
Sleeping for 15 seconds then retrying
Polling order status: https://acme.zerossl.com/v2/DV90/order/suec4vMDaDZKQ
Downloading cert.
Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/LB9E122S4t-g'
Cert success.
-----BEGIN CERTIFICATE-----
MIIDfzCCAyagAwIBAgIRAKWk8AY1fNKWe64zQciAJtcwCgYIKoZIzj0EAwIwRjEL
......
hkjOPQMBBwNCAASmRtrrDZ7ByjaHX11+D76N1I85BsupVmGGOSi+ActjyK7ziO32
......
UAIgdEzu7GvLOBTavFZKZXsshpPb9eMTp3vRMYQDOM+czsc=
-----END CERTIFICATE-----
Your cert is in: /acme.sh/*.lichenghao.cn_ecc/*.lichenghao.cn.cer
Your cert key is in: /acme.sh/*.lichenghao.cn_ecc/*.lichenghao.cn.key
The intermediate CA cert is in: /acme.sh/*.lichenghao.cn_ecc/ca.cer
And the full-chain cert is in: /acme.sh/*.lichenghao.cn_ecc/fullchain.cer
ARI suggestedWindow: 2026-11-10T23:59:59Z to 2026-11-12T23:59:59Z
Next renewal time picked from ARI window: 2026-11-11T01:11:45Z

中间有两个错误码,别担心,不影响最终证书的生成~ 最终会生成 *.lichenghao.cn.cer 和 *.lichenghao.cn.key 这俩是我们最终要用的。

可以先把他俩手动复制到雷池的证书管理中,验证一下是否可用,出现如下就是没问题了哦~

脚本解决雷池WAF的域名证书自动续签

没有问题以后,接下来修改renew.sh。

考虑修改:

  1. 建立脚本目录, 所有脚本以及生成的文件存放目录,我修改为: /opt/myapp/acme;
  2. 建立证书归档目录, 我修改为: /opt/myapp/acme/archived/;
  3. WAF 证书 ID, 雷池 WAF 域名证书的 ID;
  4. DOMAIN, 需要生成证书的域名,我的域名 lichenghao.cn;
  5. newfile 和 oldfile 的路径;

修改后的脚本:

#!/bin/bash
#auto renew ssl for safeline waf
#by dominicx

#cert id in safeline for this ssl
CERTID=1
DOMAIN="lichenghao.cn"
ARCHIVEDDIR="/opt/myapp/acme/archived/"

#step 1 renew ssl cert
docker run --rm  -it -v "/opt/acme":/acme.sh neilpang/acme.sh --issue --dns dns_tencent -d "*.$DOMAIN" -d "$DOMAIN"

newfile="/opt/myapp/acme/*.$DOMAIN\_ecc/*.$DOMAIN.cer"
oldfile="/data/safeline/resources/nginx/certs/cert_$CERTID.crt"

newkey="/opt/myapp/acme/*.$DOMAIN\_ecc/*.$DOMAIN.key"
oldkey="/data/safeline/resources/nginx/certs/cert_$CERTID.key"

if [ ! -e $newfile ] || [ ! -e $newkey ] ; then
    echo "至少有一个文件不存在,请检查文件路径。"
    echo $newfile
    echo $newkey
    exit 1
fi

newfile_ts=$(stat -c %Y $newfile)
oldfile_ts=$(stat -c %Y $oldfile)

if [ $[$newfile_ts - $oldfile_ts] -ge 300 ]; then   #5 minutes
    echo "Move old SSL cert files to $ARCHIVEDDIR ."
    mv $oldfile $ARCHIVEDDIR
    mv $oldkey $ARCHIVEDDIR
    echo "Copy new SSL cert files."
    cp $newfile $oldfile
    cp $newkey $oldkey

    keystr="$(<$newkey)"
    certstr="$(<$newfile)"

    sql="update mgt_ssl_cert set updated_at=to_timestamp($newfile_ts),valid_before=CAST(concat(to_timestamp($newfile_ts+90*24*3600)::date+1,' 07:59:59+08') AS TIMESTAMPTZ ),cert_content='$certstr',key_content='$keystr' where id=$CERTID;"

    #update safeline pg
    docker exec -it safeline-pg psql -U safeline-ce safeline-ce  -c "$sql"
    #nginx reload ssl cert
    docker exec -it safeline-tengine nginx -s reload

    echo "updating site $CERTID SSL cert file Done."

fi

最后增加个系统定时任务,每个月的 1 号和 15 号 凌晨 1:15 执行一次。

15 1 1,15 * * /opt/acme/scripts/renew.sh > /opt/acme/logs/update.log 2>&1 &

🎉🎉🎉

折腾第二次~

上面操作有个错误,应该把泛域名证书的 fullchain 证书复制到文件 cert_1.crt。

但是总感觉这个脚本太复杂了呢,然后就有搜索了下文档,直到雷池社区版自动 SSL ↗ , 就是以后还是要第一时间找官网的文档。

官方文档给了两个方式,我选择了第二种。

  • freessl 配置域名,省事方案
  • dns api 方案,适用于域名多,或者不信任 ✅

安装 acme 脚本

curl https://get.acme.sh | sh -s email=my@example.com

或者

wget -O -  https://get.acme.sh | sh -s email=my@example.com

验证

acme.sh -h

整理安装脚本

在参考雷池的官网文档:雷池 WAF 帮助文档 - 雷池社区版自动 SSL ↗ 和 acme 的文档后,我选择使用 DNS api 验证域名所有权;

github.com/acmesh-official/acme.sh/wiki/dnsapi ↗

使用 Use TencentCloud (DNSPod) API 生成证书;得到最终的命令脚本,安装并重启 nginx。

acme.sh --install-cert --issue --dns dns_tencent -d *.lichenghao.cn \
--key-file       /data/safeline/resources/nginx/certs/cert_1.key  \
--fullchain-file /data/safeline/resources/nginx/certs/cert_1.crt \
--reloadcmd     "docker exec safeline-tengine nginx -s reload"

设置 encent_SecretId 和 Tencent_SecretKey

在执行命令之前,需要把腾讯云的 Tencent_SecretId 和 Tencent_SecretKey 加入环境变量。

Please visit https://console.cloud.tencent.com/cam/capi ↗ to obtain the API key.

export Tencent_SecretId="<Your SecretId>"
export Tencent_SecretKey="<Your SecretKey>"

有很多方案,无论使用那种方法,acme.sh 会自动把腾讯云的密钥保存到它的账户配置中,下次自动续期时无需再次 export。

✅ 方案一:写入 acme.sh 的专用配置文件(最安全、最省事)

  acme.sh 会自动把腾讯云的密钥保存到它的账户配置中,下次自动续期时无需再次 export。
执行一次签发后(确保这次能成功),acme.sh 会自动将其存入 ~/.acme.sh/account.conf。你也可以手动写入:

echo "Tencent_SecretId='你的SecretId'" >> ~/.acme.sh/account.conf
echo "Tencent_SecretKey='你的SecretKey'" >> ~/.acme.sh/account.conf

✅ 方案二:写入 Shell 的启动文件(永久有效)

  如果你想在任意新终端直接使用,把 export 命令写入你的 Shell 配置文件:

# 如果你是 bash
echo "export Tencent_SecretId='你的SecretId'" >> ~/.bashrc
echo "export Tencent_SecretKey='你的SecretKey'" >> ~/.bashrc
source ~/.bashrc

# 如果你是 zsh
echo "export Tencent_SecretId='你的SecretId'" >> ~/.zshrc
echo "export Tencent_SecretKey='你的SecretKey'" >> ~/.zshrc
source ~/.zshrc

✅ 方案三:直接写在脚本 first2.sh 的最前面(测试方便)

  把你的 export​ 命令直接写在 first2.sh 脚本的顶部(放在 acme.sh 命令之前)。这样只要执行脚本,变量就会被自动设置(仅对脚本内的命令生效)。

#!/bin/bash
export Tencent_SecretId="你的SecretId"
export Tencent_SecretKey="你的SecretKey"
# 下面接着你的 acme.sh 命令...

执行脚本证书更新

执行完毕后,查询下证书的更新时间即可。

报错处理

执行脚本报错:acme.sh: command not found

./scripts/first2.sh: line 6: acme.sh: command not found

编辑你的 shell 配置文件(~/.bashrc​ 或 ~/.zshrc),加入:

export PATH="$HOME/.acme.sh:$PATH"

然后执行:

source ~/.bashrc   # 或 source ~/.zshrc

此后任何终端都能直接使用 acme.sh。

🎉🎉🎉

📍 文章地点 — 中关村南大街

💬 评论区