看着别人网站上绿色的https标签很是心痒,而又不想花大价钱申请企业级的SSL方案,于是寻思着给网站申请了一个免费的沃通CA证书。谁知道前脚刚刚部署完证书,后脚却在网上发现沃通证书将不再被信任,心里很不是滋味。于是便重新上网搜寻其他获得SSL的方法。
经过短暂的搜寻,发现了这样一个免费的SSL证书授权机构(CA): Let’s Encrypt
据官网介绍,Let’s Encrypt服务由Internet Security Research Group (ISRG)推出,通过向网站自动签发和管理免费SSL证书,旨在降低互联网进行安全通信的门槛。该项目托管于Linux基金会,得到了来自诸如Mozilla, Akamai, Cisco, Electronic Foundation Frontier, OVH.com, Google Chrome等大咖加持,来头实在不小。
为什么最终选择使用这个方案呢?首先当然是因为免费了。其次就是官网所宣传的“自动化(automated)”了。要知道当时给网站上CA证书的时候,生成私钥上传证书,各种麻烦事儿。Let’s Encrypt仅需要一条指令即可完成续签,根本不用进行文件操作,实在是极其吸引人。
不多说废话,立刻进行操作。
本文使用CentOS 7+Nginx
的组合。
注意:不同的OS和Web服务器所使用的命令不尽相同,有关其他系统和Web服务器的操作指南可以查看这里。
官网提到,上证书和续签的过程都是使用Certbot来进行的。由于服务器使用的是CentOS 7,所以直接运行以下命令即可完成安装。
1 | $ sudo yum install epel-release |
其中第一个命令是安装EPEL源,也称为“企业版Linux的额外软件包(Extra Packages for Enterprise Linux)”。EPEL源了提供许多在CentOS自带源上没有的软件,而这次用到的certbot就是从EPEL源中获取的。而第二个命令则是安装certbot本身。
Certbot的官网提到,CentOS 7并不支持证书的自动安装,所以我们使用手动方式安装证书。获取证书使用certonly
命令。具体参数如下:
1 | certbot certonly --webroot -w <网页路径> -d <域名> |
--webroot
参数适用于使用Web服务器(如Nginx、Apache等)的网站。关于这个参数的具体使用说明可以查看这里。
-w
参数后面接的是服务器请求数据的目录(“web root”)。一条命令后面可以接多个-w
参数。
-d
参数后面接这个目录的域名(“domain”)。同样地,一条命令后面也可以接多个-d
参数。
一个简单的示例如下:
1 | $ certbot certonly --webroot -w /var/www/example -d example.com -d www.example.com -w /var/www/thing -d thing.is -d m.thing.is |
这条命令将生成单个证书颁发给 example.com , www.example.com , thing.is 和 m.thing.is ,而域名目录分别为 /var/www/example 和 /var/www/thing 。
注意:
--webroot
参数的原理是在指定的web root位置(由-w
指定)生成一个临时文件.well-known/acme-challenge
,接着由Let’s Encrypt服务器向指定的域名(由-d
指定)发起一个HTTP请求,验证DNS服务器是否能正确解析到该目录,从而验证域名的真实性。所以请在使用--webroot
参数之前检查以下项目是否正常:
- 保证Web服务器能够请求到隐藏目录(如
.well-known
这样目录名前带“点”的目录)里面的内容(如.well-known/acme-challenge
)。- 保持80端口正常访问。
- 当网站使用的是国内DNS时,如DNSPOD、阿里云DNS、CloudXNS等,有几率出现
DNS query timed out
问题导致证书获取不成功。这时候重新执行一遍命令即可。
键入命令回车后,进入Certbot的UI界面。
首先会提示键入用于找回私钥的邮箱,回车继续:
接着便是短暂的安装过程:
唔,安装快要结束时竟然报出了UnicodeEncodeError
:
由于python的默认编码是ascii,而当目标字符的编码不是ascii的时候,python会尝试使用解码器(’ascii’ codec)将其转换为ascii编码再继续执行。当程序中出现非unicode的编码的时候,由于解码器并不能转换非unicode的编码,于是就会报这样的异常。
于是手动设置环境变量更改系统的编码,命令如下:
1 | $ export LANG=en_US.UTF-8 |
接着重新使用certonly
命令重新获取证书:
1 | certbot certonly --webroot -w <网页路径> -d <域名> |
问题解决,成功获取证书:
接下来是证书的装载。这点和一般SSL证书的装载操作大致相同,不同点在于使用Let’s Encrypt并不需要手动上传证书,仅需要把证书路径指向它给出的路径即可。
Let’s Encrypt的证书位置
最新的证书默认存放在
/etc/letsencrypt/live/{域名}
中。当使用renew
命令续签证书时,该目录下的证书总是最新的。该目录存在以下文件:
privkey.pem
私钥文件fullchain.pem
证书文件(包含证书链)cert.pem
本站点的证书文件及chain.pem
证书链文件(这两个文件需搭配使用)证书归档在
/etc/letsencrypt/archive/{域名}
中。所有证书的改动都会归档在这里。文件名后面的序号表示文件的版本。
为了将来方便续签,我们把证书路径定在/etc/letsencrypt/live/{域名}
下。
Nginx的配置示例如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
server{
listen 80;
server_name localhost;
rewrite ^(.*)$ https://$host$uri permanent;
}
server {
listen 443 ssl;
server_name localhost;
ssl on;
ssl_certificate /etc/letsencrypt/live/{域名}/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/{域名}/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1;
ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP;
ssl_prefer_server_ciphers on;
location / {
root html;
index index.html index.htm;
}
}
使用这样的配置,可以将用户对http(80端口)的请求通过rewrite
全部重定向至https(443端口),以实现全站https。(经测试这种设置并不会影响Let’s Encrypt验证服务器的HTTP请求。)
更改好后保存文件并重启nginx服务:
1 | $ nginx -s reload |
大功告成。接下来放心大胆地开启HTTPS之旅吧!!!
等等,聪明的你可能发现了,为什么证书有效期那么短呢?
没关系,虽然证书的有效期短,可是简单一条命令即可搞定续签:
1 | $ certbot renew |
怎么回事?原来,为了保证续签系统的效率,还没到期的证书是不会允许进行续签操作的。那么如果我想测试续签操作到底能不能正常运行该怎么办?可以使用--dry-run
参数进行模拟运行:
1 | $ certbot renew --dry-run |
注意:续签过程和前面申请的过程一样,都需要HTTP验证域名的真实性。所以请保持80端口的畅通。
当成功完成模拟运行时,我们就可以把真实的续签命令写进系统计划了。这里我使用crontab来进行任务计划。关于crontab的配置可以看这里。网上也有一个在线Cron表达式生成器,可以预览任务执行的时机,个人感觉也非常有用。
使用vim命令打开cron的任务计划表crontab:
1 | $ vim /etc/crontab |
按i
进入编辑模式,输入任务计划后,输入:wq
保存并退出vim:
1 | 0 0 0/12 1/1 * ? root certbot renew --quiet |
其中--quiet
参数表示静默运行。
注意:官方建议计划任务的运行周期为每天两次,以保证证书能够随时更新。