0%

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

自从 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
2
export Ali_Key="AccessKeyId"
export Ali_Secret="AccessKeySecret"

注意,这里的 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
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