宝塔面板 acme 自动续签证书并全站启 HTTPS
前言
HTTPS 风靡全球,它不但可以提高 per 用户与网站连接的安全性,还代表了一种技术先进的象征,采用 HTTPS 连接的网站,更易被 Google 等搜索引擎收录。
现如今,SSL/TLS 证书也不再是大型企业、组织、机构的专利,它们多使用 EV 和 OV SSL 证书,安全性高,价格昂贵,始终令众多中小型企业网站、个人博客等站点的管理员望而却步,不过,随着 HTTPS 的成熟,DV SSL 证书的普及,也可以让他们享受 HTTPS 的安全与便捷。
Let’s Encrypt 的横空出世,彻底锤醒了靠售卖 SSL 证书坐收横财的 SSL 签发商的美梦,这个由 Google、CISCO、Mozilla、FaceBook、Akamai、Vultr、Github、DigitalOcean、EFF、OVH、MonGoDB、Version 等各国知名互联网/IDC/软件大厂共同支持的公益型数字证书认证机构,旨在推动消除复杂的数字证书申请流程和高额的部署成本,并使加密和安全在互联网中无处不在,主要为用户免费提供 SSL/TLS 证书。
无论是申请 Let’s Encrypt 证书,还是其他类型的证书,原理无非就是证书签发者需要验证当前管理员是否拥有该域名(域空间)的所有权,必须验证成功才能签发对应域名的证书。具体的验证手段有两种:
- A:让用户在绑定了该域名的域空间(VPS)下,放置一个带有校验码的文件,供外界访问。然后证书签发商去访问该用户的域上是否存放了这个文件(用户必须有权限才能放置,具有权限==具有管理权),验证通过后,即可给该域名颁发证书。
- B:让用户在域名解析商上,为当前域名 添加一条邮件 TXT 解析记录 ,并设置一段特殊的记录值,当解析生效后,如果解析类型和记录值符合证书签发商预先让用户设置的值,则会给该域名颁发证书。
以上两种原理的证书验证手段,既可以手动完成,也可以用脚本程序自动化完成。手动验证的流程暂且不表,各主流 Linux 面板、acme 等程序,均提供的一键签发 TLS 证书功能,以宝塔面板为例,虽然申请流程比较简单,部署起来也很方便,但因为面板程序的问题,也存在不少缺陷,比如:
1. 使用“文件验证”的方式,实际上面板说明里承诺3个月后的续签功能是不管用的,我有一个网站就遭遇过证书过期且没自动续签的窘迫——电脑端打开地址栏变红,手机端直接无法访问。
证书的有效期取决于签发商设置的时间,因为随着时间的流逝,每个管理员私钥丢失的概率会越来越大,当私钥丢失后,SSL/TLS 证书存在的意义也就没有了,所以自签发前,签发商必须规定一个有效期,以鼓励用户到期前重签证书,目前主流的证书签发有效期最长为39个月,最短为 Let’s Encrypt 这种3个月的(免费的总会有些不足和限制)。
这个“文件验证”就是上述提到的A原理,实际上宝塔面板这个功能有点坑,不但自动续签功能失效了,证书过期后苦逼地手动登陆面板后台,点击“申请”按钮,还有很大概率申请失败,按照报错去 debug,很大概率会无功而返。
2. 使用 DNS 验证的话,原理和上述B是一致的,如果用自动化流程来走,可以预先设置好你的域名解析商给你提供的 API 参数,然后程序会使用 API 自动在域名解析商处完成新建 TXT 解析记录并在证书颁发后自动删除的操作。
宝塔面板提供了“宝塔DNS云解析”、“DNSPod”、“阿里云DNS”、“手动解析”几个接口,其中“手动解析”是不支持自动续期的,内置的其他几个接口,如果你的域名本身就放在这些 DNS 商解析的,调用这些 DNS 商的 API 自然没问题。
但我的域名是放在 CloudFlare 上面解析的,如果要跨 DNS 商仅做一条 TXT 记录的解析,肯定会和原 DNS 解析商冲突,进而又会陷入“申请失败”→“重新申请”→“申请超限”→“一个月之内域名证书泡汤”的死循环,所以我最终弃用了这种方式,回到纯手动设置 acme 自动获取/续签证书的步骤。
忠告
如果自己的域名采用的不是“宝塔DNS云解析”、“DNSPod”、“阿里云DNS”这些解析商的任何一家,建站后首次采用宝塔面板“文件验证”的方式申请的 Let’s Encrypt 证书(首次采用 DNS 验证根本不可能签发证书成功),在3个月后采用“手动验证”或是“DNS验证”续签证书出现了错误。
或是即使规避了以上要点,首签或续签 Let’s Encrypt 证书立马出现了错误的网站管理员,请不要在查找错误上浪费时间,立马将你的网站打包备份到本地计算机,然后将整个域空间(VPS)重装系统,再重新安装宝塔面板,再勾选“编译安装 Nginx1.15”,且再也、永远不要在“站点”→“设置”→“SSL”里,利用宝塔面板的程序,做任何证书的自动签署的操作,否则你无法承担证书续签失败、证书过期、网站在一个月里无法采用新证书的后果的。
手动申请、自动续签、部署 Let’s encrypt TLS 证书
以 CloudFlare 为例,假设你的域名放在 CloudFlare 做解析,点击右上角账户头像,再点击“My Profile”:
翻到最底下,在“API Keys”里,找到 Global API Key 项,点击右边的“View”:
输入密码和图片验证码,就可以显示出 API Key:
此 API Key 具有被程序调用在该账户上进行操作的权限,一定不要轻易泄露给他人。
然后把你自己注册到 CloudFlare 的邮箱给记好,就可以进行下一步操作了。
前置组件安装
acme 需要用到 socat 这一前置组件,在安装 acme 前,请确认 socat 已安装。
Ubuntu/Debian:
apt-get install socat -y
CentOS/Redhat
yum install socat -y
安装 acme
curl https://get.acme.sh | sh
acme 本身不会在除自己文件夹以外的地方创建文件,或是向系统做任何全局设置,所有的设置、配置文件全部存放在它自己的文件夹里,这一点相当不错。安装好后,默认在 /root/.acme.sh 目录,然后进入这个目录:
cd /root/.acme.sh
在shell里直接执行下面两个命令,用于申请临时变量:
export CF_Key="你的 CloudFlare API Key"
export CF_Email=你的邮箱
第一行 CF_Key 对应的值,填写刚才在 CloudFlare Profile 里获取的 API Key;第二行 CF_Email 对应的值,填写自己当前使用的用于登陆 CloudFlare 的邮箱。
然后执行以下命令,为指定域名申请证书:
~/.acme.sh/acme.sh --issue --dns dns_cf -d 你的域名
如果要申请 ECC 证书,在命令行最后部分,添加“-k ec-256”参数即可:
~/.acme.sh/acme.sh --issue --dns dns_cf -d 你的域名 -k ec-256
证书:
/root/.acme.sh/你的域名/你的域名.cer
私钥:
/root/.acme.sh/你的域名/你的域名.key
ECC 证书:
/root/.acme.sh/你的域名_ecc/你的域名.cer
ECC 私钥:
/root/.acme.sh/你的域名_ecc/你的域名.key
私钥一定要私自妥善保管好,不要泄露给别人,否则使用该证书的网站的安全性将无从谈起。
由于 acme 和 Let’s encrypt 证书都在处于频繁的更新中,为 acme 设置为自动更新,显然更方便:
bash /root/.acme.sh/acme.sh --upgrade --auto-upgrade
短期内需多次重新部署 acme 用户的操作
如果你的 VPS 是测试环境,需在短期内多次重新部署运行环境,一定要妥善保管好 .acme.sh 文件夹里为当前绑定IP的域名部署的证书的文件,和 acme 程序本身的配置。
因为一方面,通过 acme 让 Let’s Encrypt 签发证书的频次有限制,每次重置过环境后某域名单小时、单月内均有次数限制,过于频繁地反复申请证书,签发机构有权利拒绝为该域名继续签发证书。
另一方面是已有的配置文件中,包含了之前我们预设的域名商API key等参数,和相应的下一次自动续签的计划任务参数,所以在重新部署同域名下的运行环境后,新安装 acme 主程序后,再直接把本地备份的 .acme.sh 文件夹给恢复过去,再使用命令更新 acme,既可以继续使用存放在acme文件夹中的证书,acme 的自动续签机制也没有发生变化,就不必再担心 Let’s Encrypt 证书三个月后一过期就没法自动续签的问题了。
如何备份” .acme.sh”文件至本地?
自行下载并安装 Xftp,输入 root 用户名和密码登陆,首次使用的时候,点击“工具”→“选项”,勾选“显示隐藏文件”→“确定”。
随后就能在 root 文件夹里,看到被隐藏的 .acme.sh 文件夹:
右击该文件夹,将其下载到默认文件夹并妥善备份即可。
假设之前已采取以上办法申请证书,且妥善备份了 .acme.sh 主文件夹和程序,但当我们在同域名同解析IP的机器里重新部署了环境,默认 acme 是未安装的状态,同样还是在 Xshell 里先安装:
curl https://get.acme.sh | sh
这个时候,千万别急着用上述办法直接新申请 acme 证书,否则过于频繁地向 let’s encrypt 申请证书,当前域名会被 let’s encrypt block 屏蔽从1小时到1个月不等的时间(具体以重新申请的频率和申请证书的数量为准)以至于无法再申请到证书!
我们的思路,就是把之前的备份直接恢复,由于在 .acme.sh/你的域名/你的域名.conf 文件里,专门记录了一条供定时任务决定是否继续重新申请证书的配置(主要记录的内容是你最近一次证书申请的时间,以安排2个月以后再次申请新证书)。
安装后,登陆 Xftp,在 /root/ 目录下会看到一个 .acme.sh 的文件,这个新安装的主程序当然没用,直接将其删除:
然后,把本地电脑上做好备份的 .acme.sh 文件上传到该目录:
然后切换回 terminal,输入:
crontab -l
如果出现了两条分别带有“certbot”和“acme”关键字的计划任务,则说明acme的计划任务处于正常状态,可在下一次可以重新证书的时候,重签let’s encrypt证书。
如果担心这个机制没有生效,可手动启动一次计划任务,观察acme程序返回的结果:
"/root/.acme.sh"/acme.sh --cron --home "/root/.acme.sh"
程序确实提示,证书续签程序会在60天后(本文章完成于2019/3/26)运行并生效:
最后,执行更新 .acme.sh 主程序命令并将其更新,并设置为自动更新其主程序:
bash /root/.acme.sh/acme.sh --upgrade --auto-upgrade
需要说明的是,你的证书公钥存储路径为:
/root/.acme.sh/你的域名/你的路径.cer
你的证书私钥的存储路径为:
/root/.acme.sh/你的域名/你的路径.key
如果是 ECC 证书,你的证书公钥存储路径为:
/root/.acme.sh/你的域名_ecc/你的路径.cer
如果是 ECC 证书,你的证书私钥的存储路径为:
/root/.acme.sh/你的域名_ecc/你的路径.key
私钥是极其重要且机密的信息 ,一旦泄露,后果将不堪设想,约等于即使你的网站套上了当前证书的 https,掌握该网站私钥证书的第三者,仍将可以完全监听任何访问者连接到该网站的流量,所以 千万不要将它透漏给任何人 ,也 不要 试图 将其存储在除你所信任的存储介质和你的 vps 之外的地方 ( 如百度网盘等 ),也 不要用任何聊天工具来传输你的私钥 !
使用证书并启用HTTPS
以宝塔面板5.9为例,我将向你演示如何使用 acme 为我们自动申请的 let’s encrypt 证书并为以 Nginx 为 Web 服务器的网站开启 HTTPS 的方法。
在步骤开始前,我已经默认你编译安装并启用了 Nginx,宝塔面板最新的 Nginx 1.15.8版本,修复了 1.15.6及以前版本存在的严重漏洞 。
添加网站,这个没啥好说的:
点击新建网站项目的右侧“操作”栏下的“设置”:
在第三行“listen 80;”下面,添加一条:
listen 443 ssl http2;
添加完成后是这个样子的:
在第9行, 注释“#error_page 404/404.html;”的下面 , 第12行,注释“#SSL-END”的上面 ,粘贴以下内容:
#HTTP_TO_HTTPS_START
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
#HTTP_TO_HTTPS_END
ssl_certificate /root/.acme.sh/你的域名/你的域名.cer;
ssl_certificate_key /root/.acme.sh/你的域名/你的域名.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497https://$host$request_uri;
如果是 ECC 证书:
#HTTP_TO_HTTPS_START
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
#HTTP_TO_HTTPS_END
ssl_certificate /root/.acme.sh/你的域名_ecc/你的域名.cer;
ssl_certificate_key /root/.acme.sh/你的域名_ecc/你的域名.key;