引言
在当今的互联网世界中,网站安全至关重要。使用 HTTPS 不仅可以保护用户的隐私和数据安全,还能提高网站的搜索引擎排名。ZeroSSL 提供了免费的 SSL/TLS 证书,而 acme.sh 则是一个强大的 ACME 客户端,可以自动化证书的申请和续期过程。本文将介绍如何使用 acme.sh 结合阿里云 DNS 来自动签发和续期 ZeroSSL 的免费数字证书。
ZeroSSL 和 acme.sh 简介
ZeroSSL 是一个相对较新的 SSL 证书提供商,为网站所有者提供免费和付费的 SSL/TLS 证书。它成立于 2019 年,旨在简化 SSL 证书的获取和管理过程,使网站加密变得更加容易。
acme.sh 是一个纯 Shell 脚本实现的 ACME 客户端,用于从 ZeroSSL (默认)申请和更新 SSL/TLS 证书。它支持两种验证方式,一种是通过HTTP服务器验证,另一种是通过DNS记录验证。今天我们要介绍的就是后者。它具有以下优势:
- 纯 Shell 脚本,无需安装依赖
- 支持多种 DNS 提供商的 API
- 自动化续期
- 支持多种服务器软件,Nginx、Apache 等
- 轻量级且高效
准备工作
在开始之前,我们需要准备以下内容:
- 一个运行 Linux 的服务器 (本教程以 Rocky Linux 8.10 版本为例)
- 域名及其 DNS 解析,由阿里云管理
- 阿里云账号及接口调用访问密钥 ( AccessKey ID 和 AccessKey Secret )
- 一个 Nginx 服务及网站配置,用于验证网站 SSL 证书是否生效
安装 acme.sh
首先,我们需要在服务器上安装acme.sh。普通用户和 root 用户都可以安装使用。我们这里使用 root 用户执行以下命令:
curl https://get.acme.sh | sh -s [email protected]
[root@kubecc acme]# curl https://get.acme.sh | sh -s [email protected]
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1032 0 1032 0 0 819 0 --:--:-- 0:00:01 --:--:-- 819
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 220k 100 220k 0 0 99k 0 0:00:02 0:00:02 --:--:-- 99k
[Tue Dec 31 14:50:56 CST 2024] Installing from online archive.
[Tue Dec 31 14:50:56 CST 2024] Downloading https://github.com/acmesh-official/acme.sh/archive/master.tar.gz
[Tue Dec 31 14:50:58 CST 2024] Extracting master.tar.gz
[Tue Dec 31 14:50:58 CST 2024] It is recommended to install socat first.
[Tue Dec 31 14:50:58 CST 2024] We use socat for the standalone server, which is used for standalone mode.
[Tue Dec 31 14:50:58 CST 2024] If you dont want to use standalone mode, you may ignore this warning.
[Tue Dec 31 14:50:58 CST 2024] Installing to /root/.acme.sh
[Tue Dec 31 14:50:58 CST 2024] Installed to /root/.acme.sh/acme.sh
[Tue Dec 31 14:50:58 CST 2024] Installing alias to '/root/.bashrc'
[Tue Dec 31 14:50:58 CST 2024] Close and reopen your terminal to start using acme.sh
[Tue Dec 31 14:50:58 CST 2024] Installing alias to '/root/.cshrc'
[Tue Dec 31 14:50:58 CST 2024] Installing alias to '/root/.tcshrc'
[Tue Dec 31 14:50:58 CST 2024] Installing cron job
[Tue Dec 31 14:50:58 CST 2024] bash has been found. Changing the shebang to use bash as preferred.
[Tue Dec 31 14:51:00 CST 2024] OK
[Tue Dec 31 14:51:00 CST 2024] Install success!
或者
wget -O - https://get.acme.sh | sh -s [email protected]
上诉命令会将 acme.sh 安装到你的 home 目录下的 .acme.sh 文件夹中,并创建 一个 shell 的 alias,例如 .bashrc
,为了方便后续使用你可以: alias acme.sh=~/.acme.sh/acme.sh
安装完成后,请确保重新加载 shell 配置:
source ~/.bashrc
配置阿里云 DNS API
为了让 acme.sh 能够自动添加 DNS 记录,我们需要配置阿里云的 API 密钥。首先登录到阿里云控制台,创建 AccessKey ID 和 AccessKey Secret。( 如何创建 AccessKey )
然后在服务器上设置环境变量:
export Ali_Key="your_access_key_id"
export Ali_Secret="your_access_key_secret"
为了使这些设置永久生效,你可以将它们添加到~/.bashrc
或~/.profile
文件中。
安装信息验证:
[root@kubecc ~]# acme.sh -v
https://github.com/acmesh-official/acme.sh
v3.1.0
[root@kubecc ~]# cat .acme.sh/account.conf
#LOG_FILE="/root/.acme.sh/acme.sh.log"
#LOG_LEVEL=1
#AUTO_UPGRADE="1"
#NO_TIMESTAMP=1
ACCOUNT_EMAIL='[email protected]'
UPGRADE_HASH='f981sadsadasdasdasdasdasdasdasd'
SAVED_Ali_Key='LTAI4sdansjdnasAdasndADNKCN'
SAVED_Ali_Secret='Uusadasdas80JNJKNJKNjnkjmnllk'
USER_PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin'
我们可以看到安装时设置的邮箱地址和阿里云的 API Key。
申请证书
现在我们可以使用 acme.sh 来申请证书了。假设你要为 www.kubecc.com 申请证书,运行以下命令:
acme.sh --issue --dns dns_ali -d www.kubecc.com
[root@kubecc .acme.sh]# acme.sh --issue --dns dns_ali -d www.kubecc.com
[Fri Jan 3 10:33:16 CST 2025] Using CA: https://acme.zerossl.com/v2/DV90
[Fri Jan 3 10:33:16 CST 2025] Creating domain key
[Fri Jan 3 10:33:16 CST 2025] The domain key is here: /root/.acme.sh/www.kubecc.com_ecc/www.kubecc.com.key
[Fri Jan 3 10:33:16 CST 2025] Single domain='www.kubecc.com'
[Fri Jan 3 10:33:25 CST 2025] Getting webroot for domain='www.kubecc.com'
[Fri Jan 3 10:33:25 CST 2025] Adding TXT value: sdasdasdasdaxxxxxxxxxxxxxxxxxx for domain: _acme-challenge.www.kubecc.com
[Fri Jan 3 10:33:26 CST 2025] The TXT record has been successfully added.
[Fri Jan 3 10:33:26 CST 2025] Lets check each DNS record now. Sleeping for 20 seconds first.
[Fri Jan 3 10:33:47 CST 2025] You can use '--dnssleep' to disable public dns checks.
[Fri Jan 3 10:33:47 CST 2025] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
[Fri Jan 3 10:33:47 CST 2025] Checking www.kubecc.com for _acme-challenge.www.kubecc.com
[Fri Jan 3 10:33:48 CST 2025] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 35
[Fri Jan 3 10:33:58 CST 2025] Please refer to https://curl.haxx.se/libcurl/c/libcurl-errors.html for error code: 28
[Fri Jan 3 10:33:58 CST 2025] Not valid yet, lets wait for 10 seconds then check the next one.
[Fri Jan 3 10:34:15 CST 2025] Lets wait for 10 seconds and check again.
[Fri Jan 3 10:34:26 CST 2025] You can use '--dnssleep' to disable public dns checks.
[Fri Jan 3 10:34:26 CST 2025] See: https://github.com/acmesh-official/acme.sh/wiki/dnscheck
[Fri Jan 3 10:34:26 CST 2025] Checking www.kubecc.com for _acme-challenge.www.kubecc.com
[Fri Jan 3 10:34:26 CST 2025] Success for domain www.kubecc.com '_acme-challenge.www.kubecc.com'.
[Fri Jan 3 10:34:26 CST 2025] All checks succeeded
[Fri Jan 3 10:34:26 CST 2025] Verifying: www.kubecc.com
[Fri Jan 3 10:34:28 CST 2025] Processing. The CA is processing your order, please wait. (1/30)
[Fri Jan 3 10:34:35 CST 2025] Success
[Fri Jan 3 10:34:35 CST 2025] Removing DNS records.
[Fri Jan 3 10:34:35 CST 2025] Removing txt: KCRFVDwS5exxxxxxxxxxxxxxxx for domain: _acme-challenge.www.kubecc.com
[Fri Jan 3 10:34:37 CST 2025] Successfully removed
[Fri Jan 3 10:34:37 CST 2025] Verification finished, beginning signing.
[Fri Jan 3 10:34:37 CST 2025] Lets finalize the order.
[Fri Jan 3 10:34:37 CST 2025] Le_OrderFinalize='https://acme.zerossl.com/v2/DV90/order/xxxxxxx/finalize'
[Fri Jan 3 10:34:42 CST 2025] Order status is 'processing', lets sleep and retry.
[Fri Jan 3 10:34:42 CST 2025] Sleeping for 15 seconds then retrying
[Fri Jan 3 10:34:58 CST 2025] Polling order status: https://acme.zerossl.com/v2/DV90/order/xxxxxxxxxxxxxxkpg
[Fri Jan 3 10:35:01 CST 2025] Downloading cert.
[Fri Jan 3 10:35:01 CST 2025] Le_LinkCert='https://acme.zerossl.com/v2/DV90/cert/xxxxxxxxxxxxxxxx'
[Fri Jan 3 10:35:04 CST 2025] Cert success.
-----BEGIN CERTIFICATE-----
MIID/xxxxxxxxxxxxxxxxxxxxxx/Eq3IkNj+gMlTDlAwCgYIKoZIzj0EAwMwSzEL
MAkGA1UEBhMCQVQxEDAOBgNVBAoTB1plcm9TU0wxKjAoBgNVBAMTIVplcm9TU0wg
RUNDIERvbWFpbiBTZWN1cmUgU2l0ZSBDQTAeFw0yNTAxMDMwMDAwMDBaFw0yNTA0
MDMyMzU5NTlaMBkxFzAVBgNVBAMTDnd3dy5rdWJlY2MuY29tMFkwEwYHKoZIzj0C
AQYIKoZIzj0DAQcDQgAEFyfPwtHh48X9mbgabswxzbEGhBWcLNoVWj8VCIRLni0f
+FTDuyvNl4D9pznBmpX5aYLUKkeU3J+w39b/tmvWeqOCAnowggJ2MB8GA1UdIwQY
MBaAFA9r5kvOOUeu9xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxOlPTT69Xp4i
few0zXUTYTAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADAdBgNVHSUEFjAU
BggrBgEFBQcDAQYIKwYBBQUHAwIwSQYDVR0gBEIwQDA0BgsrBgEEAbIxAQICTjAl
MCMGCCsGAQUFBwIBFhdodHRwczovL3NlY3RpZ28uY29tL0NQUzAIBgZngQwBAgEw
gYgGCCsGAQUFBwEBBHwwejBLBggrBgEFBQcwAoY/aHR0cDovL3plcm9zc2wuY3J0
LnNlY3RpZ28uY29tLxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxMCsG
CCsGAQUFBzABhh9odHRwOi8vemVyb3NzbC5vY3NwLnNlY3RpZ28uY29tMIIBBAYK
KwYBBAHWeQIEAgSB9QSB8gDwAHYAzxFW7tUufK/zh1vZaS6b6RpxZ0qwF+ysAdJb
d87MOwgAAAGUKgPhDQAABAMARzBFAiEAr8tpj5dw570imSrK7F+/2DG8WL8s+wdc
Yeumc9bDLNMCIGTCvkKHcJdHNFbOkI8idW/Y7zRC+6e5PR7CAcL0WP8VAHYAzPsP
aoVxCWX+lZtTzumyfCLphVwNl422qX5UwP5MDbAAAAGUKgPgzQAABAMARzBFAiAg
S5OsQE+NT07CfCFW1hygWn8JROy2a0jgxv4J0EUDVwIhALs8ZCuE/mjJdvLM2+AN
XCnD84ovDFn8KDfGtXnAWGALMBkGA1UdEQQSMBCCDnd3dy5rdWJlY2MuY29tMAoG
CCqGSM49BAMDA2gAMGUCMQCneaUeF8sFqazFs40/3Psald6j6B9AwE35SRBIIAP+
DO759Keek0t6DjoSAYIN+dUCMEFPG9eqglqkajjHHqW1U1kBFtlsvYjGZLPEjKJR
CTaP2LQ1X6sUmH0JOmTPeftawA==
-----END CERTIFICATE-----
[Fri Jan 3 10:35:04 CST 2025] Your cert is in: /root/.acme.sh/www.kubecc.com_ecc/www.kubecc.com.cer
[Fri Jan 3 10:35:04 CST 2025] Your cert key is in: /root/.acme.sh/www.kubecc.com_ecc/www.kubecc.com.key
[Fri Jan 3 10:35:04 CST 2025] The intermediate CA cert is in: /root/.acme.sh/www.kubecc.com_ecc/ca.cer
[Fri Jan 3 10:35:04 CST 2025] And the full-chain cert is in: /root/.acme.sh/www.kubecc.com_ecc/fullchain.cer
这个命令会执行以下步骤:
- 生成证书请求
- 通过阿里云 API 添加必要的 DNS TXT 记录
- 等待 ZeroSSL 验证 DNS 记录,验证通过后会将 DNS 中用于验证域名所有权的 TXT 解析记录删除
- 获取证书
如果一切顺利,你将看到成功信息,证书文件会被保存在 ~/.acme.sh/www.kubecc.com/
目录下。
安装证书至 Nginx
获取证书后,我们需要将其安装到 Web 服务器中。以 Nginx 为例:
[root@kubecc .acme.sh]# acme.sh --install-cert -d www.kubecc.com \
> --key-file /etc/nginx/sslkey/kubecc.com/www.kubecc.com.key \
> --fullchain-file /etc/nginx/sslkey/kubecc.com/www.kubecc.cer \
> --reloadcmd "sudo service nginx force-reload"
[Fri Jan 3 10:35:39 CST 2025] The domain 'www.kubecc.com' seems to already have an ECC cert, lets use it.
[Fri Jan 3 10:35:39 CST 2025] Installing key to: /etc/nginx/sslkey/kubecc.com/www.kubecc.com.key
[Fri Jan 3 10:35:39 CST 2025] Installing full chain to: /etc/nginx/sslkey/kubecc.com/www.kubecc.cer
[Fri Jan 3 10:35:39 CST 2025] Running reload cmd: sudo service nginx force-reload
Redirecting to /bin/systemctl force-reload nginx.service
[Fri Jan 3 10:35:39 CST 2025] Reload successful
这个命令会将证书文件复制到指定位置,并在证书更新时重新加载 Nginx,记得提前修改 Nginx 配置文件以使用新的证书:
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /path/to/fullchain/nginx/cert.pem;
ssl_certificate_key /path/to/keyfile/in/nginx/cert.key;
# ........
}
验证证书信息:
[root@kubecc ~]# acme.sh --info -d www.kubecc.com
[Fri Jan 3 18:25:16 CST 2025] The domain 'www.kubecc.com' seems to already have an ECC cert, lets use it.
DOMAIN_CONF=/root/.acme.sh/www.kubecc.com_ecc/www.kubecc.com.conf
Le_Domain=www.kubecc.com
Le_Alt=no
Le_Webroot=dns_ali
Le_PreHook=
Le_PostHook=
Le_RenewHook=
Le_API=https://acme.zerossl.com/v2/DV90
Le_Keylength=ec-256
Le_OrderFinalize=https://acme.zerossl.com/v2/DV90/order/kra3C-DVCNbHmoM0lsO11g/finalize
Le_LinkOrder=https://acme.zerossl.com/v2/DV90/order/kra3C-DVCNbHmoM0lsO11g
Le_LinkCert=https://acme.zerossl.com/v2/DV90/cert/AulqYPZhPp70qPYeA1etLg
Le_CertCreateTime=1735893871
Le_CertCreateTimeStr=2025-01-03T08:44:31Z
Le_NextRenewTimeStr=2025-03-03T08:44:31Z
Le_NextRenewTime=1740991471
Le_RealCertPath=
Le_RealCACertPath=
Le_RealKeyPath=/etc/nginx/sslkey/kubecc.com/www.kubecc.com.key
Le_ReloadCmd=sudo service nginx force-reload
Le_RealFullChainPath=/etc/nginx/sslkey/kubecc.com/www.kubecc.com.cer
自动续期
acme.sh 会自动创建一个 cron 作业,每天检查证书是否需要续期。默认情况下,您不需要手动更新证书,所有证书将每 60 天自动更新一次。
你可以通过以下命令查看cron作业:
crontab -l
如果你想手动强制续期,可以运行:
acme.sh --renew -d example.com --force
常见问题及解决方案
-
DNS 验证失败
- 检查阿里云API密钥是否正确
- 确保域名在阿里云 DNS 管理下
- 检查是否有其他 DNS 记录冲突
-
证书安装失败
- 确保指定的路径存在且有写入权限
- 检查 Web 服务器配置是否正确
-
自动续期不工作
- 检查 cron 作业是否正确设置
- 确保 acme.sh 有足够的权限执行更新
-
如何升级 acme.sh
# 您可以将 acme.sh 更新到最新代码 acme.sh --upgrade # 您还可以启用自动升级 acme.sh --upgrade --auto-upgrade # 禁用自动升级 acme.sh --upgrade --auto-upgrade 0
-
API 调用次数限制
- 阿里云可能会限制 API 调用次数,避免频繁操作
-
证书吊销
如果需要吊销证书:
acme.sh --remove -d example.com [--ecc] # 证书/密钥文件不会从磁盘中删除,您可以手动删除
最佳实践
- 定期备份
定期备份~/.acme.sh目录,以防意外情况发生。 - 监控证书状态
设置监控系统,及时发现证书问题。 - 使用强密码学套件
在 Web 服务器配置中使用强密码学套件,提高安全性。 - 启用 HSTS
考虑启用 HTTP 严格传输安全 (HSTS) ,进一步增强安全性。 - 保护私钥
确保证书私钥的安全,限制访问权限。 - 测试续期过程
定期测试证书续期过程,确保自动化流程正常工作。
总结
通过使用 acme.sh 和阿里云 DNS,我们可以轻松实现免费数字证书的自动签发和续期。这不仅节省了大量时间和精力,还确保了网站始终受到 SSL/TLS 的保护。
参考文献
[1] acmesh-official