准备工作
- CentOS/7虚拟机
- 申请域名,比如www.example.com,并将域名指向该虚拟机80端口(需要ICP备案)
- 保证80和443端口未被占用,
certbot
在运行过程中会使用这两个端口,当然如果安装了nginx并且你打算使用certbot-nginx插件,那么certbot会借用nginx,也即虽然nginx占用了80和443端口,也是ok的。
安装软件
- 安装epel-release:
sudo yum install epel-release
- 安装Nginx:
sudo yum install nginx
- 启动Nginx:
sudo systemctl start nginx
- 安装certbot:
sudo yum install certbot
- 安装certbox的nginx插件:
sudo yum install certbot-nginx
,certbot
在运行时会临时性地通过该nginx插件向nginx的配置文件中添加新的配置(server block),用于向Let's Encrypt提供访问端口以完成ACME协议验证。
Let's Encrypt的两种认证方式
在Let‘s Encrypt签发证书时,它需要确定你要申请证书的域名的确是你拥有的,此时Let's Encrypt将向certbot客户端发起挑战(challenge)以验证你对域名的拥有权,有两种方式:
- 通过运行certbot的服务器与Let's Encrypt服务器通信,如果你配置域名指向该certbot所在的服务器,Let's Encrypt通过直接访问该域名的方式来验证(URL格式为:http://domain/.well-known/acme-challenge/
)。这种方式通常用于单一域名的证书,需要certbot运行与域名所指向的服务器上。 - 通过DNS,如果你拥有该域名,那么Let's Encrypt会让你在该域名下设置一个TXT记录,记录值设置成Let's Encrypt所要求的(在运行certbot时会提示),做到这一点则可以证明你的确拥有对该域名的拥有权。这种方式通常用于通配符证书,certbot无需运行在域名指向的服务器上。
创建证书(以Nginx为例)
运行:
sudo certbot --nginx certonly
certonly
表示仅仅生成证书,而不自动更新nginx.conf配置文件。如果希望certbot在生成证书后自动更新nginx.conf文件,则可以:
sudo certbot --nginx
本文演示第一个命令,即sudo certbot --nginx certonly
,此时命令行显示:
Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator nginx, Installer nginx Enter email address (used for urgent renewal and security notices) (Enter 'c' to cancel):
此时输入你邮箱地址,命令行显示:
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please read the Terms of Service at
https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf. You must
agree in order to register with the ACME server at
https://acme-v02.api.letsencrypt.org/directory
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(A)gree/(C)ancel: A
回答A
,此时命令行显示:
Would you be willing to share your email address with the Electronic Frontier
Foundation, a founding partner of the Let's Encrypt project and the non-profit
organization that develops Certbot? We'd like to send you email about our work
encrypting the web, EFF news, campaigns, and ways to support digital freedom.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: N
回答Y
或N
无所谓,此时命令行显示:
No names were found in your configuration files. Please enter in your domain
name(s) (comma and/or space separated) (Enter 'c' to cancel): www.example.com
输入www.example.com
(请替换为你自己的域名),特别注意此时LetsEncrypt会尝试与该域名通信,因此请保证该域名可以正常访问。
如果一切正常,命令行将输出:
Obtaining a new certificate
Performing the following challenges:
http-01 challenge for www.example.com
Waiting for verification...
Cleaning up challenges
IMPORTANT NOTES:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/www.example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/www.example.com/privkey.pem
Your cert will expire on 2019-03-10. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
生成证书成功,包含以下文件:
- 证书文件:
/etc/letsencrypt/live/www.example.com/fullchain.pem
- 密钥文件:
/etc/letsencrypt/live/www.example.com/privkey.pem
读者也可以参考这篇文章。
命令行参数
如果需要在单台机器上为多个域名申请证书,可以在运行certbot
命令时指定域名:
sudo certbot --nginx -d admin.example.com certonly
前文中我们使用了certbot-nginx
插件,也可以不使用该插件而使用独立的certbot服务器:
sudo certbot --standalone --preferred-challenges http -d admin.example.com
这里的--standalone
告诉certbot使用内建的web服务器与Let's Encrypt完成ACME协议通信。而--preferred-challenges
可以取http
(使用80端口)或者tls-sni
(使用443端口)。
Certbot插件
至此,我们已经了解到了certbot有两种插件可以用于完成ACME协议通信,其实还有另外很多插件,比如apache和webroot:
- nginx:通过修改Nginx配置完成ACME协议
- standalone:通过certbot内建服务器完成ACME协议,需要占用80或者443端口,意味着先前运行的监听80/443端口的服务器必须停掉,比如tomcat。
- apache:通过修改Apache配置完成ACME协议
- webroot:将制定文件夹通过既有web服务器(比如Nginx)暴露给Let's Encrypt完成ACME协议
- DNS插件:通过调用DNS域名提供商的API接口自动完成ACME协议,
- Manual:手动完成
apache插件跟nginx原理相似,通过临时性修改apache的配置来完成ACME通信,而webroot通过制定某个目的路径来完成ACME通信。更多细节请参考这里。
查看所有已安装证书
sudo certbot certificates
更新证书
LetsEncrypt生成的证书有效期只有3个月, 因此在到期只看前你需要自己进行re-newal操作以更新证书。
要手动更新证书,再次运行:
sudo certbot --nginx certonly
此时命令行显示:
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator nginx, Installer nginx
Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org
Which names would you like to activate HTTPS for?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: www.example.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate numbers separated by commas and/or spaces, or leave input
blank to select all options shown (Enter 'c' to cancel):
此时certbot自动探测到已有域名证书www.example.com
(?好像即便安装了多个证书,此时也只会出现第一个安装的,其他的不在此列,如果要更新其他的证书可以通过certbot的-d
参数在命令行中指定),输入1
:
What would you like to do?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: Keep the existing certificate for now
2: Renew & replace the cert (limit ~5 per 7 days)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 1
此时可以选择是否保留原证书(选项1)或者覆盖原证书(选项2),可以根据需要完成余下步骤。
如果有多个证书而只想更新其中某个证书:
sudo certbot renew --cert-name www.example.com
使用cron自动更新证书
先保证certbot能够正常工作:
sudo certbot renew --dry-run
如果能看到以下字样:
...
Congratulations, all renewals succeeded.
...
表示certbot能够正常更新证书。
编写cron脚本:
# cat > /etc/cron.d/certbot <<- EOF
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
0 */12 * * * root test -x /usr/bin/certbot -a \! -d /run/systemd/system && perl -e 'sleep int(rand(3600))' && certbot -q renew
EOF
以上脚本每天运行2次,但是只有在证书即将过期的时候才会真正执行renew操作。
创建通配符证书
单域名证书在创建时需要将域名指向certbot运行的机器,而通配符证书由于采用了DNS方式进行挑战,因此没有这项限制,可以在任何机器上完成通配符证书的创建。
当前Let's Encrypt中只有https://acme-v02.api.letsencrypt.org/directory
向外提供通配符证书服务,如果要为*.example.com
生成证书,输入:
sudo certbot --server https://acme-v02.api.letsencrypt.org/directory -d *.example.com --manual --preferred-challenges dns-01 certonly
此时命令行显示:
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.
Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o:
告诉你你的IP将被记载公开日志中,比如回答Y
:
Please deploy a DNS TXT record under the name
_acme-challenge.example.com with the following value:
4dererVVTRBqzFp0sW1EHH343432B8-fegegdDFA
Before continuing, verify the record is deployed.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
为了验证你的确拥有该域名,此时需要你为自己的example.com
设置一个TXT记录,记录名为_acme-challenge
,记录值为4dererVVTRBqzFp0sW1EHH343432B8-fegegdDFA
,在笔者的阿里云上设置如下:
最后显示生成成功:
- Congratulations! Your certificate and chain have been saved at:
/etc/letsencrypt/live/example.com/fullchain.pem
Your key file has been saved at:
/etc/letsencrypt/live/example.com/privkey.pem
Your cert will expire on 2019-03-10. To obtain a new or tweaked
version of this certificate in the future, simply run certbot
again. To non-interactively renew *all* of your certificates, run
"certbot renew"
- If you like Certbot, please consider supporting our work by:
Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate
Donating to EFF: https://eff.org/donate-le
此时生成的证书包含:
- 证书文件:
/etc/letsencrypt/live/example.com/fullchain.pem
- 密钥文件:
/etc/letsencrypt/live/example.com/privkey.pem
请注意,虽然是通配符证书,但是证书文件目录中不是*.example.com
,而是example.com
。
更新通配符证书
有两种方式更新证书:
- 执行与创建时相同的命令,然后按照提示完成更新证书
- 使用
certbot renew
命令
对于第2中方式:
sudo certbot renew --cert-name example.com
如果执行dry run:
sudo certbot renew --cert-name example.com --dry-run
将报错:
Attempting to renew cert (wanghushengri.com) from /etc/letsencrypt/renewal/example.com.conf produced an unexpected error: The manual plugin is not working; there may be problems with your existing configuration.
The error was: PluginError('An authentication script must be provided with --manual-auth-hook when using the manual plugin non-interactively.',). Skipping.
All renewal attempts failed. The following certs could not be renewed:
/etc/letsencrypt/live/example.com/fullchain.pem (failure)
表示通配符证书不能自动完成更新,此时有两种方式:
- 手动更新
- 提供
authentication script
(笔者还没有研究过,读者可以自行研究)
重要知识点
- Certbot有2个命令,
certbot
和certbot-auto
,certbot
是包管理器(比如yum和apt-get等)安装后的命令,而certbot-auto
其实是个封装后的脚本,可以自动帮我们安装certbot
- 在2016年5月份之前,
certbot
和certbot-auto
命令为letsencrypt
和letsencrypt-auto
- 第一次运行certbot时需要输入你的邮箱地址(账户)和同意协议,如果不想要这些交互,也可以通过
--mail
和--agree-tos
命令行参数完成 - Cerbot有2种类型的插件完成证书申请,一种为Authenticator方式,表示通过ACME协议获得证书后,将证书保存到本地(
/etc/letsencrypt
目录下);另一种为Installer方式,表示在获得证书后会将证书安装到指定的服务器中,比如Nginx,此时需要启用相应的插件,比如certbot-nginx
。
在底层所有插件都使用以下方式之一完成ACME要求的挑战:
- http-01:使用80端口
- tls-sni-01:使用443端口
- dns-01:使用53端口修改DNS配置
有些插件可以完成多种挑战方式,比如standalone插件可以使用http-01或者tls-sni-01,另外,可以通过--preferred-challenges
指定挑战方式。
- 可以一次性为多个域名生产证书,但是此时所有域名的证书在同一份文件中,如果不想这样,便只有单独运行了
- 对于单一域名证书,多数情况下推荐使用webroot插件,因为它可以在不影响你的既有web服务器的情况下生成证书。webroot工作原理为:通过既有的web服务器向外暴露访问接口(需要通过域名能访问得到),在运行certbot命令时指定需要向外暴露访问的目录(通过
--webroot-path
或-w
指定),cerbot在于Let‘s Encrypt通信过程中会将挑战文件放在指定文件夹(${webroot-path}/.well-known/acme-challenge
)下,然后Let’s Encrypt会通过域名访问该文件,请求格式如下:
66.133.109.36 - - [05/Jan/2016:20:11:24 -0500] "GET /.well-known/acme-challenge/HGr8U1IeTW4kY_Z6UIyaakzOkyQgPr_7ArlLgtZE8SX HTTP/1.1" 200 87 "-" "Mozilla/5.0 (compatible; Let's Encrypt validation server; +https://www.letsencrypt.org)"
如果验证成功,即表示你对该域名具有拥有权。
比如web服务器是nginx,域名为www.example.com
,先保证http://example.com/
能正常访问到nginx资源,我们决定将webroot-path
设置成/var/share/html/certbot
,此时需要配置nginx:
location /.well-known {
root /var/share/html/certbot;
}
然后运行命令(这里的certonly
是必须的):
sudo certbot certonly --webroot -w /var/share/html/certbot -d www.example.com
- Certbot官方文档