0%

HTTPS泛域名证书申请之一-申请流程

自从 Let's Encrypt 支持泛域名之后,为网站设置https就变得非常简单了。之前需要维护多个子域名的证书更新,操作起来也是很麻烦的。

因为最近我的 gogit.itfanr.cc 的https证书到期,所以就研究了一下泛域名的申请过程,想要将我所有 itfanr.cc 下的二级域名都设置成https的请求方式。

目前比较常用的为 Let's Encrypt 生成证书的工具比较多,比如 certbotacme.sh 是我之前接触过的两款。这里我要使用 acme.sh 这个工具来安装 Let's Encrypt 证书。

acme.sh

acme.sh 是由国人利用 shell 脚本开发的,兼容各种 Linux 系统。仅仅依赖 curlacme.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/ 中。

并且,还默认创建一个 bashalias, 方便你的使用: 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
2
export Ali_Key="AccessKeyId"
export Ali_Secret="AccessKeySecret"

注意,这里的 Ali_KeyAli_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
2
3
4
5
$ docker run --rm \
-v /etc/acme.sh:/acme.sh \
-e Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" \
-e Ali_Secret="jlsdflanljkljlfdsaklkjflsa" \
neilpang/acme.sh --issue --dns dns_ali -d example.com -d '*.example.com'

注意这里第一个域名为顶级域名,后面一个为泛域名。

这种方式将自动为你的域名添加一条 txt 解析,验证成功后,这条解析记录会被删除,所以对你来说是无感的,就是要等待 120 秒。

证书生成成功后,默认保存在 .acme.sh/example.com 中。

容器化自动续期

可以以后台进程的方式运行一个容器:

1
2
3
4
$ docker run --name acme.sh \
-d --restart unless-stopped \
-v /etc/acme.sh:/acme.sh \
neilpang/acme.sh daemon

这样,acme.sh 证书到60天就会自动更新。


注意事项

当我按照如上方法生成域名证书时,执行命令:

1
2
3
4
5
$ docker run --rm \
-v /etc/acme.sh:/acme.sh \
-e Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" \
-e Ali_Secret="jlsdflanljkljlfdsaklkjflsa" \
neilpang/acme.sh --issue --dns dns_ali -d itfanr.cc -d *.itfanr.cc

发现会提示如下错误:

1
2
3
4
5
6
7
➜  acme.sh docker run --rm \
-v /etc/acme.sh:/acme.sh \
-e Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" \
-e Ali_Secret="jlsdflanljkljlfdsaklkjflsa" \
neilpang/acme.sh --issue --dns dns_ali -d itfanr.cc -d *.itfanr.cc
zsh: no matches found: *.itfanr.cc
➜ acme.sh

经查证,其中的泛域名 *.example.com 中由于带有 * 号,会报错。相应的解决方法是添加引号:-d '*.example.com'


我的操作记录

创建本地证书保存目录:

1
$ mkdir /etc/acme.sh

执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
➜  acme.sh docker run --rm \
-v /etc/acme.sh:/acme.sh \
-e Ali_Key="sdfsdfsdfljlbjkljlkjsdfoiwje" \
-e Ali_Secret="jlsdflanljkljlfdsaklkjflsa" \
neilpang/acme.sh --issue --dns dns_ali -d itfanr.cc -d '*.itfanr.cc'
[Tue Sep 18 15:11:27 UTC 2018] Registering account
[Tue Sep 18 15:11:28 UTC 2018] Registered
[Tue Sep 18 15:11:28 UTC 2018] ACCOUNT_THUMBPRINT='AR2Gc73349sl32z_kw-kY9nP7qqesQqFlK8'
[Tue Sep 18 15:11:28 UTC 2018] Creating domain key
[Tue Sep 18 15:11:29 UTC 2018] The domain key is here: /acme.sh/itfanr.cc/itfanr.cc.key
[Tue Sep 18 15:11:29 UTC 2018] Multi domain='DNS:itfanr.cc,DNS:*.itfanr.cc'
[Tue Sep 18 15:11:29 UTC 2018] Getting domain auth token for each domain
[Tue Sep 18 15:11:30 UTC 2018] Getting webroot for domain='itfanr.cc'
[Tue Sep 18 15:11:30 UTC 2018] Getting webroot for domain='*.itfanr.cc'
[Tue Sep 18 15:11:30 UTC 2018] Found domain api file: /root/.acme.sh/dnsapi/dns_ali.sh
[Tue Sep 18 15:11:31 UTC 2018] Found domain api file: /root/.acme.sh/dnsapi/dns_ali.sh
[Tue Sep 18 15:11:32 UTC 2018] Sleep 120 seconds for the txt records to take effect

发现,当最后一行提示信息为 Sleep 120 seconds for the txt records to take effect 时,说明正在自动执行DNS绑定的操作。

当日志继续输出时,可以看到最后提示执行成功了 Cert success.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Tue Sep 18 15:11:32 UTC 2018] Sleep 120 seconds for the txt records to take effect
[Tue Sep 18 15:13:32 UTC 2018] Verifying:itfanr.cc
[Tue Sep 18 15:13:35 UTC 2018] Success
[Tue Sep 18 15:13:35 UTC 2018] Verifying:*.itfanr.cc
[Tue Sep 18 15:13:38 UTC 2018] Success
[Tue Sep 18 15:13:38 UTC 2018] Removing DNS records.
[Tue Sep 18 15:13:42 UTC 2018] Verify finished, start to sign.
[Tue Sep 18 15:13:44 UTC 2018] Cert success.
-----BEGIN CERTIFICATE-----
MIIGCjCCBPKgAwIBAgISA95TIaF4XRlosoA/zwdEbLRaMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMR34dcvKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0xODA5MTgxNDEzNDJaFw0x
...
...
A6l0KWm2/jjYcf5YPGIoK3jMzNm17B88yoPYoDwecxWC59t5+DQjpQo7iM7tyTV+
q4UZMY9jlrbaCJVSdrM=
-----END CERTIFICATE-----
[Tue Sep 18 15:13:44 UTC 2018] Your cert is in /acme.sh/itfanr.cc/itfanr.cc.cer
[Tue Sep 18 15:13:44 UTC 2018] Your cert key is in /acme.sh/itfanr.cc/itfanr.cc.key
[Tue Sep 18 15:13:44 UTC 2018] The intermediate CA cert is in /acme.sh/itfanr.cc/ca.cer
[Tue Sep 18 15:13:44 UTC 2018] And the full chain certs is there: /acme.sh/itfanr.cc/fullchain.cer
➜ acme.sh

查看 /etc/acme.sh 目录下:

1
2
3
4
5
➜  acme.sh ls
account.conf ca http.header itfanr.cc
➜ acme.sh ls itfanr.cc
ca.cer fullchain.cer itfanr.cc.cer itfanr.cc.conf itfanr.cc.csr itfanr.cc.csr.conf itfanr.cc.key
➜ acme.sh

其中, 证书文件是 fullchain.cer ,密钥文件是 itfanr.cc.key


配置Nginx

在域名的nginx配置文件中新增证书配置,例如我的 gogit.itfanr.cc 域名的配置文件 gogit.conf 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
server {
listen 443 ssl;
server_name gogit.itfanr.cc;

ssl_certificate /etc/acme.sh/itfanr.cc/fullchain.cer;
ssl_certificate_key /etc/acme.sh/itfanr.cc/itfanr.cc.key;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;

proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;

location / {
proxy_pass http://127.0.0.1:3000/;
}
}

server {
listen 80;
server_name gogit.itfanr.cc;
return 301 https://$server_name$request_uri;
}

然后更新nginx,重新载入配置:

1
$ sudo nginx -s reload

在浏览器中访问域名,可以看到地址栏中的小绿锁已经出现了。

相关参考

如有疑问或需要技术讨论,请留言或发邮件到 service@itfanr.cc