给网站用上免费SSL:Let's Encrypt操作记录

看着别人网站上绿色的https标签很是心痒,而又不想花大价钱申请企业级的SSL方案,于是寻思着给网站申请了一个免费的沃通CA证书。谁知道前脚刚刚部署完证书,后脚却在网上发现沃通证书将不再被信任,心里很不是滋味。于是便重新上网搜寻其他获得SSL的方法。

经过短暂的搜寻,发现了这样一个免费的SSL证书授权机构(CA): Let’s Encrypt

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
2
$ sudo yum install epel-release
$ sudo yum install certbot

其中第一个命令是安装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.ism.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界面。

首先会提示键入用于找回私钥的邮箱,回车继续:

接着,需要同意协定用来注册ACME服务

接着便是短暂的安装过程:

唔,安装快要结束时竟然报出了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参数表示静默运行。

注意:官方建议计划任务的运行周期为每天两次,以保证证书能够随时更新。

# site

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×