自从 Let's Encrypt
支持泛域名之后,为网站设置https就变得非常简单了。之前需要维护多个子域名的证书更新,操作起来也是很麻烦的。
因为最近我的 gogit.itfanr.cc
的https证书到期,所以就研究了一下泛域名的申请过程,想要将我所有 itfanr.cc
下的二级域名都设置成https的请求方式。
目前比较常用的为 Let's Encrypt
生成证书的工具比较多,比如 certbot
和 acme.sh
是我之前接触过的两款。这里我要使用 acme.sh
这个工具来安装 Let's Encrypt
证书。
acme.sh
acme.sh
是由国人利用 shell
脚本开发的,兼容各种 Linux
系统。仅仅依赖 curl
。 acme.sh
实现了 acme
协议, 可以从 letsencrypt
生成免费的证书。
acme.sh 支持 --webroot
, --standalone
, --apache
, --nginx
and --dns
5种证书申请模式。
安装
可以直接通过下面的脚本来安装 acme.sh
:
1 | curl https://get.acme.sh | sh |
安装过程不会污染已有的系统任何功能和文件,acme.sh
会被自动安装到 ~/.acme.sh/
中。
并且,还默认创建一个 bash
的 alias
, 方便你的使用: alias acme.sh=~/.acme.sh/acme.sh
。
此外,acme.sh
还自动创建了 cronjob
任务, 每天 0:00
点自动检测所有的证书, 如果快过期了, 需要更新, 则会自动更新证书.
单域名申请
当你只想要为一个域名设置 https
时,可以使用 --standalone
模式来申请。
比如我之前在为 gogit.itfanr.cc
设置时,我的网站程序是跑在Docker容器下的,外面用 Nginx
来做跳转。
首先,我需要先将占用 80
端口的 Nginx
服务停掉,然后再设置:
1 | $ sudo service nginx stop |
然后,生成https证书:
1 | $ acme.sh --issue -d gogit.itfanr.cc --standalone |
其中,gogit.itfanr.cc
请换成自己的站点域名。
Standalone 模式默认使用的是 80
端口,如果你的 80
端口无法使用的话,也可以指定相应的端口:
1 | $ acme.sh --issue -d gogit.itfanr.cc --standalone --httpport 88 |
获取AccessKeys
因为我要将 itfanr.cc
域名下所有的二级域名都设置成 https
,那么上面一个域名一个域名的设置方法就不行了。
泛域名就是类似于 *.example.com
这样的域名。
acme.sh
目前支持数十种域名解析商的API,可以自动添加 TXT
记录来验证。
这里我以阿里云DNS为例,其他支持的域名验证方式,可以查看这里了解 以及相应的设置方法
acme.sh
访问阿里云 DNS 是通过阿里云 DNS 公开的 API 以及用户的 AccessKeys
来进行交互的。
为了保证安全,阿里云 AccessKeys
是使用 阿里云子账户
来添加的。
登录 [阿里云管理控制台](https://home.console.aliyun.com/)
– 点击头像中的 accesskeys
– 选择 开始使用子用户AccessKeys
{或者直接点击该网址} – 设置 用户名
– 选择权限中输入“DNS”,选择 AliyunDNSFullAccess(管理员解析(DNS)的权限)
这项 – 之后子账户和AK都创建成功了。
AliyunDNSFullAccess
表示 “管理员解析(DNS)的权限”,既该账户就有了添加DNS记录和删除DNS记录的权限,但没有其他权限。
一定要在这一步记录下这个 AccessKey
信息,之后就无法看到了。
添加配置
在 bash
中执行如下命令,将参数添加到环境变量中:
1 | export Ali_Key="AccessKeyId" |
注意,这里的 Ali_Key
和 Ali_Secret
是和你所使用的域名提供商一一对应的。具体的可在这里查找:相应的设置方法
另外,这个临时环境变量只需配置这一次,当成功申请证书后,API信息会被自动保存在 ~/.acme.sh/account.conf
,下次你使用 acme.sh
的时候会被自动使用。
生成泛域名证书
接下来正式开始申请泛域名证书,将 example.com
换成你自己的域名:
1 | $ acme.sh --issue --dns dns_ali -d example.com -d '*.example.com' |
申请完成后可以在 ~/.acme.sh/example.com
下看到证书文件:
证书文件是 fullchain.cer
密钥文件是 example.com.key
证书续期
Let’s Encrypt 证书的有效期为三个月,acme.sh会每隔60天自动帮你续期。在以上命令执行后,会在 crontab
里添加计划,通过命令查看:
1 | $ crontab -l |
将证书配置到Nginx
放在 ~/.acme.sh/example.com
目录下的证书文件不能直接拿来使用,需要拷贝到一个自定义的目录下,再配置到Nginx中才能正常的使用。
Docker使用acme.sh
上面的方法安装起来虽说已经很简单了,但是对于像我这种但凡能用Docker来解决的问题绝对不用其他方式。
获取镜像
1 | $ docker pull neilpang/acme.sh |
创建acme.sh证书保存目录
1 | $ mkdir /etc/acme.sh |
运行 acme.sh 容器
这里依然需要从域名服务商处获得的ID和Secret:
1 | $ docker run --rm \ |
注意这里第一个域名为顶级域名,后面一个为泛域名。
这种方式将自动为你的域名添加一条 txt
解析,验证成功后,这条解析记录会被删除,所以对你来说是无感的,就是要等待 120
秒。
证书生成成功后,默认保存在 .acme.sh/example.com
中。
容器化自动续期
可以以后台进程的方式运行一个容器:
1 | $ docker run --name acme.sh \ |
这样,acme.sh
证书到60天就会自动更新。
注意事项
当我按照如上方法生成域名证书时,执行命令:
1 | $ docker run --rm \ |
发现会提示如下错误:
1 | ➜ acme.sh docker run --rm \ |
经查证,其中的泛域名 *.example.com
中由于带有 *
号,会报错。相应的解决方法是添加引号:-d '*.example.com'
我的操作记录
创建本地证书保存目录:
1 | $ mkdir /etc/acme.sh |
执行:
1 | ➜ acme.sh docker run --rm \ |
发现,当最后一行提示信息为 Sleep 120 seconds for the txt records to take effect
时,说明正在自动执行DNS绑定的操作。
当日志继续输出时,可以看到最后提示执行成功了 Cert success.
:
1 | [Tue Sep 18 15:11:32 UTC 2018] Sleep 120 seconds for the txt records to take effect |
查看 /etc/acme.sh
目录下:
1 | ➜ acme.sh ls |
其中, 证书文件是 fullchain.cer
,密钥文件是 itfanr.cc.key
。
配置Nginx
在域名的nginx配置文件中新增证书配置,例如我的 gogit.itfanr.cc
域名的配置文件 gogit.conf
如下:
1 | server { |
然后更新nginx,重新载入配置:
1 | $ sudo nginx -s reload |
在浏览器中访问域名,可以看到地址栏中的小绿锁已经出现了。