先说说为什么要自己折腾SSL证书。免费的啊兄弟们!Let’s Encrypt和ZeroSSL都提供90天免费证书,关键是要自动化续期。别跟我说用付费证书,小项目一年几百上千块,还不如把这钱省下来买咖啡。
第一步:选择证书类型和申请方式
现在主流免费证书就两种:
- Let’s Encrypt:老牌,支持泛域名,推荐用acme.sh工具
- ZeroSSL:有管理后台,支持90天证书,可以用官网或acme.sh
我个人推荐Let’s Encrypt + acme.sh的组合。acme.sh这个工具写的真的良心,纯Shell脚本,安装简单,自动续期。
“bash
安装acme.sh
curl https://get.acme.sh | sh -s email=your@email.com
设置别名方便使用
alias acme.sh=~/.acme.sh/acme.sh
`
安装完成后,申请证书有几种验证方式。最推荐的是DNS API模式,适合泛域名。以阿里云为例:
`bash
先设置DNS API密钥
export Ali_Key="你的AccessKey"
export Ali_Secret="你的AccessKey Secret"
申请泛域名证书
acme.sh --issue --dns dns_ali -d example.com -d *.example.com
`
这个设计真的很反人类,但一旦配好了就一劳永逸。注意AccessKey权限不要给太大,只给DNS解析的权限就够了,安全第一。
开篇先亮出工具,这张图展示acme.sh的安装和证书申请全流程,从终端输入命令到成功拿到证书文件。
第二步:Nginx配置——最容易踩坑的地方
证书拿到手了,接下来就是配置Nginx。这里我踩过一个巨坑:配置完后浏览器一直报ERR_CERT_COMMON_NAME_INVALID。查了半天,原来是证书文件路径写错了,实际指向了一个旧证书。
正确的配置姿势是这样的:
`nginx
强制HTTPS重定向
server {
listen 80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
HTTPS服务
server {
listen 443 ssl http2;
server_name example.com www.example.com;
# 证书路径一定要用绝对路径,别用相对路径
ssl_certificate /root/.acme.sh/example.com_ecc/fullchain.cer;
ssl_certificate_key /root/.acme.s
h/example.com_ecc/example.com.key;
# 安全配置,这些参数我测试过,评级是A+
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;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# 这行很重要,开启HSTS
add_header Strict-Transport-Security "max-age=63072000" always;
location / {
root /var/www/html;
index index.html;
}
}
`
配置完后记得测试一下语法:
`bash
nginx -t
如果没问题就重载
systemctl reload nginx
`
这里展示部署后的SSL测试结果,来自SSL Labs的A+评级截图,以及浏览器地址栏的小锁标志。
第三步:自动化续期——90天证书的命脉
免费证书有效期只有90天,手动续期是不可能的。acme.sh默认会添加cron任务自动续期,但有个坑:续期后证书文件路径变了!
我刚开始用默认配置,续期后nginx指向的还是旧证书,导致服务中断。正确的做法是续期后执行reload命令:
`bash
设置续期后自动重启nginx
acme.sh --install-cert -d example.com \
--reloadcmd "systemctl reload nginx"
查看已添加的cron任务
crontab -l
`
验证自动续期是否正常:
`bash
强制测试续期
acme.sh --renew -d example.com --force
查看续期日志
tail -f ~/.acme.sh/acme.sh.log
`
还有个技巧:可以在续期前检查证书剩余天数,提前预警。写个简单的脚本:
`bash
#!/bin/bash
检查证书剩余天数
expire_date=$(openssl x509 -in /root/.acme.sh/example.com_ecc/fullchain.cer -noout -enddate | cut -d= -f2)
expire_seconds=$(date -d "$expire_date" +%s)
now_seconds=$(date +%s)
days_left=$(( ($expire_seconds - $now_seconds) / 86400 ))
if [ $days_left -lt 30 ]; then
echo "证书剩余 $days_left 天,即将过期"
# 可以发送通知
fi
`
总结前放一张自动化续期的流程图,展示从cron触发到续期、重载nginx的完整链路。
另一个坑:中间证书链
这个坑我印象特别深。配置完SSL后用curl -v https://example.com测试,发现证书链不完整。浏览器访问没问题,但某些老版本Android手机会报错。
解决方案是使用fullchain.cer而不是cert.cer,因为fullchain包含了中间证书。acme.sh默认生成的fullchain.cer就是完整链,所以用那个就行。
如果想验证证书链是否完整:
`bash“
openssl s_client -connect example.com:443 -showcerts
看输出里是否包含两个或更多证书,第一个是服务器证书,第二个是中间证书。
总结一下,你可以立刻用的三个点
最后说一句:别在证书上省钱,也别在配置上省心。免费工具用对了,比付费的还香。