
👉体系化学习:运维工程师打怪升级进阶之路 4.0
— 特色专栏 —
大家好,我是民工哥!
一个脚本就把系统升级到 https 了,且永久免费!

这到底是怎么个事呢?
接下来慢慢看。
HTTPS 早已不再是大型网站的专利,个人站长、中小企业乃至开发者测试环境,都有足够理由将全站升级到加密传输。
然而长期以来,SSL/TLS 证书的高昂费用和繁琐申请流程让许多人望而却步。
2016年 Let's Encrypt 的横空出世,以及 自动化 证书管理协议(ACME)的普及,彻底改变了这一局面。
本文将用整整 2 万字的篇幅,手把手带你从零开始,仅使用一个开源脚本 acme.sh,一键将系统升级至 HTTPS,并且全程 永久免费。无论你是初次接触 SSL 的小白,还是寻求大规模部署方案的运维专家,都能从中获得完整、实用的指导。

在 HTTP 明文传输的世界里,任何中间节点(路由器、代理、ISP)都可以窃听、篡改传输内容。HTTPS通过SSL/TLS协议加密通信,提供三大保障:
如今,浏览器对HTTP站点标记“不安全”,搜索引擎降低HTTP站点的排名,甚至苹果强制要求App所有网络请求必须为HTTPS。升级HTTPS早已不是可选项,而是必选项。

SSL/TLS证书是由受信任的证书颁发机构(CA)签发的电子文件,包含网站的公钥、组织信息、颁发者、有效期等。浏览器内置了CA根证书列表,当服务器出示证书时,浏览器可验证签名链,确保证书合法且未被篡改。
证书的核心生命周期分为:生成私钥 → 生成证书签名请求(CSR)→ CA验证域名所有权 → 签发证书 → 部署 → 续期。
在Let's Encrypt诞生之前,购买一张受信任的SSL证书每年需数百甚至数千元,而且申请流程通常需要人工审核邮件或电话,周期长达数天。对于个人开发者或中小企业,这是不小的负担。
Let's Encrypt成立于2016年,由Mozilla、思科、Google等机构赞助,旨在为全球网站提供免费、自动化的SSL证书。其核心技术是ACME(自动证书管理环境)协议,客户端通过该 协议 与CA服务器交互,自动完成域名验证、证书申请、下载与续期。
ACME协议彻底解放了运维人员,将证书有效期缩短为90天,但通过自动化脚本实现无感续期,反而比传统一年期证书更安全(密钥轮换更频繁)。
很多人会疑惑:“免费证书真的能永久免费吗?”答案是:是的,而且有成熟、可持续的商业模式支持。
因此,“永久免费”不是营销口号,而是由开放生态和技术进步共同支撑的现实。
acme.sh 是一个纯Shell脚本编写的ACME客户端,无需任何依赖(仅需Unix-like系统下的curl和openssl),可运行在Linux、macOS、Windows(WSL/Cygwin)上。作者是Neil Pang,项目托管于GitHub,是目前全球最受欢迎的ACME客户端之一。
客户端 | 语言 | 特性优势 | 不足 |
|---|---|---|---|
acme.sh | Shell | 极轻量,零依赖,DNS API最全,安装即续期 | 仅限类Unix |
Certbot | Python | 官方客户端,模块化,社区庞大 | 依赖复杂,重 |
Lego | Go | 单二进制,跨平台 | 功能相对精简 |
Win-ACME | C#/.NET | Windows原生 | 仅Windows |
acme.sh最大的优势是对DNS服务商的API支持极其丰富(超过100家),可以一键完成泛域名证书申请与自动续期。
操作系统:建议CentOS 7+、Ubuntu 16+、Debian 8+、macOS。
工具:curl、openssl、crontab。
域名:需要有一个已经解析到当前服务器的域名。
防火墙:若使用HTTP验证,需开放80端口;若使用DNS验证,无端口要求。
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仓库到~/.acme.sh/。.acme.sh目录,并设置环境变量。~/.bashrc中添加别名acme.sh。执行上述命令后,终端输出大致如下:
Installing to /home/ubuntu/.acme.sh
Installed to /home/ubuntu/.acme.sh/acme.sh
Installing alias to '/home/ubuntu/.bashrc'
OK, Close and reopen your terminal to start using acme.sh, or just run 'source ~/.bashrc'
Installing cron job
no crontab for ubuntu
no crontab for ubuntu
Cron job installed. Good!
source ~/.bashrc 或重新登录后即可直接使用acme.sh命令。
升级acme.sh自身:
acme.sh --upgrade
自动升级(推荐):
acme.sh --upgrade --auto-upgrade
卸载acme.sh:
acme.sh --uninstall
rm -rf ~/.acme.sh
acme.sh 1.0以后默认CA为ZeroSSL(也完全免费),但我们可以手动切换回Let's Encrypt,或使用其他CA:
acme.sh --set-default-ca --server letsencrypt
目前支持的CA:
不同CA证书有效期不同:Let's Encrypt/ZeroSSL 90天,Buypass 180天,Google 90天。
首次签发证书时,acme.sh会自动与CA注册账户。也可提前注册:
acme.sh --register-account -m my@example.com --server letsencrypt
账户私钥保存在~/.acme.sh/ca/letsencrypt/account.key。
假设我们有一个域名example.com,且已经解析到服务器IP,HTTP服务运行于80端口(用于验证)。执行:
acme.sh --issue -d example.com -w /var/www/html
-w指定网站根目录,acme.sh会将验证文件写入该目录下的.well-known/acme-challenge/,Let's Encrypt会通过HTTP访问该文件来验证域名所有权。
成功后,证书和私钥会保存在~/.acme.sh/example.com/目录下。
将多个域名放在同一张证书中:
acme.sh --issue -d example.com -d www.example.com -d blog.example.com -w /var/www/html
只要第一个域名是主域名,证书的Subject Alternative Name将包含所有列出的域名。
泛域名证书(如*.example.com)可以保护所有二级子域名。必须使用DNS-01验证,因为HTTP验证无法对泛域名生效(验证域名本身不存在)。
acme.sh --issue --dns dns_cf -d example.com -d '\*.example.com'
这里的dns_cf是Cloudflare的DNS API标识,我们将在第6章详细讲解。
默认签发RSA 2048位证书。若需ECC证书(更高效),添加--keylength参数:
acme.sh --issue -d example.com -w /var/www/html --keylength ec-256
也可同时申请RSA+ECC双证书:
acme.sh --issue -d example.com -w /var/www/html --keylength ec-256
acme.sh --issue -d example.com -w /var/www/html --keylength 2048
证书分别保存在example.com_ecc和example.com目录。
申请成功后,~/.acme.sh/example.com/目录下包含:
example.com.key:私钥example.com.cer:证书fullchain.cer:证书链(含中间证书)ca.cer:仅CA证书注意:永远不要手动拷贝这些文件用于部署!应使用acme.sh --install-cert命令安装证书,该命令会将证书复制到目标位置并执行重载脚本(见第7章)。
原理:CA服务器访问http://<域名>/.well-known/acme-challenge/<token>,验证指定文件内容。
优点:无需DNS操作,即时生效。
缺点:需要80端口可访问;无法签发泛域名;无法用于仅限内网的服务器。
acme.sh命令:
acme.sh --issue -d example.com -w /var/www/html
原理:在域名的_acme-challenge.<域名>下添加TXT记录,CA通过查询DNS验证所有权。
优点:可签发泛域名;无需开放HTTP端口;适合非Web服务。
缺点:需DNS服务商支持API自动化,否则手动添加记录较繁琐。
acme.sh支持通过API自动添加/删除TXT记录(需配置凭据)。如Cloudflare:
export CF_Token="你的API Token"
export CF_Account_ID="你的账户ID"
acme.sh --issue --dns dns_cf -d example.com -d '\*.example.com'
与HTTP-01类似,但acme.sh不写入文件,而是要求用户提前自行放置验证文件。适合无法执行命令写入的环境。通过--webroot参数指定根目录即可。
原理:acme.sh自身启动一个临时Web服务器(监听80或443端口)来响应验证请求。无需已有Web服务器。
用法:
acme.sh --issue -d example.com --standalone
需确保80端口未被占用。若仅443端口可用,可用--httpport 443。
TLS-ALPN-01:基于TLS扩展,需443端口支持ALPN协议(Nginx等支持)。
阿里云DNS、DNSPod等数十种DNS API均被acme.sh原生支持。
DNS-01验证自动化是acme.sh的核心优势。我们以最常用的Cloudflare和 阿里云 为例讲解。
acme.sh通过--dns指定提供商标识,目前支持超过100家,包括:
dns_cf)dns_ali)dns_dp)dns_huaweicloud)dns_aws)dns_gd)dns_namecheap)完整列表:acme.sh dnsapi目录(https://github.com/acmesh-official/acme.sh/tree/master/dnsapi "acme.sh dnsapi目录")
步骤1:在Cloudflare获取API Token (推荐)或Global API Key。
步骤2:设置环境变量。
export CF_Token="your_api_token"
export CF_Account_ID="your_account_id"
步骤3:执行签发。
acme.sh --issue --dns dns_cf -d example.com -d '\*.example.com'
acme.sh会自动创建_acme-challenge.example.com TXT记录,验证后自动删除。
步骤4:持久化凭据。可将export语句写入~/.bashrc,或使用acme.sh的--set-dns命令保存(1.5+版本):
acme.sh --set-dns dns_cf --dnssleep 30
阿里云用户需在控制台获取AccessKey ID和Secret(建议使用子账号,仅授权DNS管理)。
export Ali_Key="your_ak_id"
export Ali_Secret="your_ak_secret"
acme.sh --issue --dns dns_ali -d example.com -d '\*.example.com'
注意:阿里云API修改解析记录后,生效时间一般为1-10分钟,acme.sh默认等待120秒,可通过--dnssleep调整。
配置方式均类似:设置特定环境变量,然后--dns指定标识。详见acme.sh Wiki。
永远不要将API密钥明文写在脚本中!
acme.sh将凭据保存在~/.acme.sh/account.conf,此文件权限默认600,相对安全。也可通过密码管理器注入环境变量。
申请到的证书只有被Web服务器加载并对外提供HTTPS服务,才算真正“升级系统”。
假设Nginx配置文件路径为/etc/nginx/nginx.conf,证书计划放在/etc/nginx/ssl/example.com/。
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com/fullchain.cer \
--reloadcmd "systemctl force-reload nginx"
————————————————
版权声明:本文为CSDN博主「油墨香^_^」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_41581588/article/details/157993141
说明:
--key-file 私钥目标路径--fullchain-file 证书链完整路径(证书+中间证书)--reloadcmd 安装或续期后执行的命令,通常用于重载Web服务器Nginx配置示例:
nginx
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/example.com/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/example.com/example.com.key;
# ... 其他配置
}
类似地,指定--key-file、--fullchain-file及--reloadcmd。
acme.sh --install-cert -d example.com \
--key-file /etc/ssl/private/example.com.key \
--fullchain-file /etc/ssl/certs/example.com.crt \
--reloadcmd "systemctl force-reload apache2"
Apache配置:
apache
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/example.com.crt
SSLCertificateKeyFile /etc/ssl/private/example.com.key
</VirtualHost>
acme.sh不直接支持每种服务器的配置格式,但我们可以导出证书再手动转换。
Tomcat需要PKCS12或JKS格式:
acme.sh --install-cert -d example.com \
--cert-file /tmp/example.com.pem \
--key-file /tmp/example.com.key \
--fullchain-file /tmp/example.com.chain.pem
然后使用openssl转换:
openssl pkcs12 -export -in /tmp/example.com.pem -inkey /tmp/example.com.key \
-out /tmp/example.com.p12 -name tomcat -CAfile /tmp/example.com.chain.pem -caname root
之后导入Java密钥库。
IIS需要PFX格式,类似方法转换。
若有多台服务器需要同一张证书,可通过scp或rsync将证书文件分发,并在远程执行重载命令。acme.sh内置了--deploy钩子,支持sftp、scp、ssh等,也可自定义脚本。
确保--reloadcmd正确执行。acme.sh会捕获命令的退出码,失败时会提示。常见重载命令:
Nginx: nginx -s reload 或 systemctl reload nginx
Apache: apachectl -k graceful 或 systemctl reload apache2
仅验证配置:nginx -t 后再重载。
Let's Encrypt证书有效期90天,acme.sh会在证书剩余不足30天时自动续期。续期过程完全复用首次申请的参数(域名、验证方式、密钥长度等),无需重新指定。
安装acme.sh时自动添加cron任务:
0 0 * * * "/home/ubuntu/.acme.sh"/acme.sh --cron --home "/home/ubuntu/.acme.sh" > /dev/null
每天零点执行--cron,检查所有已签发证书,自动续期并执行部署命令。
立即执行续期:
acme.sh --cron
强制续期(即使未到期):
acme.sh --renew -d example.com --force
--renew仅续期指定域名,--cron处理所有。若修改了证书参数(如增加域名、更换CA),需先更新域名信息再强制续期。
acme.sh --list
显示所有已签发证书的主域名、签发CA、到期时间等。
仅仅配置好证书还不足够,我们需要确保所有流量默认走HTTPS,同时避免混合内容。
以Nginx为例,新建HTTPS server块,并复制原有location配置。
将所有HTTP请求永久重定向到HTTPS:
nginx
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$host$request_uri;
}
注意:若已经配置HSTS,且includeSubDomains开启,浏览器会强制HTTPS,无需HTTP跳转。但首次启用时仍需保留跳转。
HTTPS页面加载HTTP资源(图片、CSS、JS)时,浏览器会阻止或标记不安全。通过Content Security Policy或直接修改资源链接解决。
# 简单粗暴:全站替换http://为https://
sed -i 's|http://|https://|g' /var/www/html/\*.html
更稳妥的方法是升级CMS插件,或使用相对协议//example.com/xxx.js。
使用浏览器访问https://example.com/ 查看小锁标志。
使用SSL Labs测试获取详细评分。
使用curl -I https://example.com验证重定向链。
Nginx配置示例:
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384';
ssl_prefer_server_ciphers off;
HTTP Strict Transport Security 告诉浏览器:未来指定时间内,此域名强制使用HTTPS,禁止任何HTTP连接。
Nginx添加响应头:
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
max-age:秒,建议至少31536000(一年)。includeSubDomains:可选,影响所有子域。preload:申请加入浏览器预加载列表,无法轻易撤销。启用HSTS前,请确保HTTPS永久可用!
OCSP Stapling可提升TLS握手性能,由服务器主动缓存OCSP响应并发送给客户端。
Nginx配置:
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/nginx/ssl/example.com/chain.cer;
resolver 8.8.8.8 8.8.4.4 valid=300s;
resolver_timeout 5s;
现代CA必须将证书签发记录提交到公开日志,浏览器也要求提供SCT(签名证书时间戳)。Let's Encrypt证书已自动包含,通常无需额外配置。若需自签名嵌入,可使用acme.sh的--embedded-scts(实验性)。
~/.acme.sh/目录,包含所有证书、私钥及配置文件。虽然acme.sh自动续期,但仍有极少数情况会失败(如DNS API过期、服务器宕机)。建议部署外部监控,例如:
acme.sh在续期成功后会执行--reloadcmd,你可以将通知命令加入其中:
--reloadcmd "systemctl reload nginx && curl -fsS -m 10 --retry 3 -o /dev/null https://hchk.io/your-uuid"
acme.sh本身不支持内置邮件通知,但我们可以自定义脚本:
邮件通知示例(需安装mail命令):
--reloadcmd "systemctl reload nginx && echo '证书已续期' | mail -s 'SSL Renewal Success' admin@example.com"
钉钉机器人:
--reloadcmd "systemctl reload nginx && curl 'https://oapi.dingtalk.com/robot/send?access_token=xxx' -H 'Content-Type: application/json' -d '{\"msgtype\":\"text\",\"text\":{\"content\":\"SSL证书续期成功\"}}'"
推荐使用 testssl.sh定期扫描,检查SSL配置漏洞,并可将报告发送到日志系统。
单张证书部署在多台服务器上,可以使用以下策略:
acme.sh --deploy -d example.com --deploy-hook ssh \
--deploy-ssh-user root \
--deploy-ssh-server 192.168.1.10 \
--deploy-cert /etc/nginx/ssl/example.com/fullchain.cer \
--deploy-key /etc/nginx/ssl/example.com/example.com.key \
--deploy-reloadcmd "systemctl reload nginx"
对于几十个域名,可编写循环脚本批量签发。对于成百上千个域名,建议搭建ACME自动化平台,如Step CA + acme.sh,实现私有CA与公网CA结合。
acme.sh支持多种部署钩子(deploy hook),详见Wiki(https://github.com/acmesh-official/acme.sh/wiki/deployhooks "Wiki")。
将acme.sh安装和证书申请写成Ansible playbook,实现基础设施即代码。示例任务:
- name:Installacme.sh
shell:curlhttps://get.acme.sh|sh-semail={{acme_email}}
args:
creates:/root/.acme.sh/acme.sh
-name:Issuecertificate
shell:/root/.acme.sh/acme.sh--issue--dnsdns_ali-d{{domain}}-d'*.{{ domain }}'
environment:
Ali_Key:"{{ aliyun_ak }}"
Ali_Secret:"{{ aliyun_sk }}"
when:ssl_certisnotexists
HTTP-01:手动访问http://example.com/.well-known/acme-challenge/xxx,确认返回正确token。
DNS-01:使用dig _acme-challenge.example.com txt查看记录是否已生效。增加--dnssleep 300以等待更长时间。
crontab -lacme.sh --cron --debug查看详细日志。acme.sh --remove -d example.com移除。acme.sh默认日志输出到终端,可通过--debug参数输出更详细信息。持久化日志:
acme.sh --cron --debug >> /var/log/acme.sh.log 2>&1
example.com(托管在阿里云)curl https://get.acme.sh | sh -s email=admin@example.com
source ~/.bashrc
acme.sh --set-default-ca --server letsencrypt
使用阿里云DNS API:
export Ali_Key="LTAI5t...xxxx"
export Ali_Secret="LTAI5t...xxxx"
acme.sh --issue --dns dns_ali -d example.com -d '*.example.com'
等待约2分钟,看到Cert success.即成功。
创建目录/etc/nginx/ssl/example.com/,安装证书:
acme.sh --install-cert -d example.com \
--key-file /etc/nginx/ssl/example.com/example.com.key \
--fullchain-file /etc/nginx/ssl/example.com/fullchain.cer \
--reloadcmd "systemctl reload nginx"
编辑Nginx配置文件,添加443监听,复制原有根目录配置。然后重载Nginx。
acme.sh的cron已存在,无需额外设置。测试续期:
acme.sh --renew -d example.com --force
https://example.com,显示安全锁。Let's Encrypt由Linux基金会托管,2021年时年度预算约360万美元,主要来自Google、Mozilla、Facebook、Cisco、AWS等企业赞助以及个人捐赠。其成本包括工程师薪酬、服务器、带宽等。证书签发完全免费,将来也会坚持免费。
acme.sh项目作者Neil Pang为独立开发者,通过GitHub Sponsors、PayPal捐赠等方式获得支持。项目遵循GPLv3协议,任何人可以免费使用、修改,甚至商用。因此acme.sh本身也是永久免费的。
来源:https://youmoxiang.blog.csdn.net/arti cle/details/157993141