使用 Let's Encrypt 为网站制作ssl加密,启用https协议

2018-03-09


http是明文传输,存在泄露个人隐私的风险,虽然作为小站点一般不怎么关注这么深的部分,但新版chrome在登陆http站点的时候会提示说:”http协议的网站将被标记为不安全”,不得已赶紧将站点升级为https。

安装SSL证书很麻烦,而且收费,不过对于个人站点来说还有更多的选择,比如 Let's Encrypt 就是一个不错的方案,不仅免费,而且安装简单,几分钟就能搞定,因为证书有效期只有三个月,所以一定要加个定时更新任务。

安装 Let’s Encrypt

软件仓库一般都有,所以直接安装即可

1
2
3
4
5
# CentOS
yum install letsencrypt

# Ubuntu 或者 Debian
apt-get install letsencrypt

使用 Let’s Encrypt 获取证书

Let's Encrypt在验证的过程中会占用443端口,所以需要暂时关闭nginx以释放端口。以下以同时获取多个域名的证书为例子:

1
2
3
4
5
6
7
8
9
10
11
12
# 停止 nginx,释放端口
systemctl stop nginx

# 获取证书
letsencrypt certonly --standalone \
--email wenjinyu959@gmail.com \
-d wenjinyu.me \
-d www.wenjinyu.me \
-d monitor.wenjinyu.me \
-d drive.wenjinyu.me \
-d cloud.wenjinyu.me \
-d notes.wenjinyu.me

只要几秒钟的验证就可以了,然后会提示证书存放在域名相应目录,比如 /etc/letsencrypt/wenjinyu.me

Let's Encrypt成功获取证书时的提示.png

需要注意的是,证书存放目录以第一个输入的域名为准,例如,如果此次输入的是www.wenjinyu.me wenjinyu.me ...,那么存放目录就会变成/etc/letsencrypt/www.wenjinyu.me

如果不希望全部域名都放在同一个证书里,那么就需要一个个地添加认证,这样做的好处是多个域名的cookie不会共用,推荐逐个添加域名认证。

使用证书

nginx的配置文件有两个,一个是 /etc/nginx/nginx.conf ,另一个是 /etc/nginx/conf.d/default.conf (或者是该文件夹下以.conf为后缀其他文件),只要往里面添加一个433端口的server即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 编辑配置文件
vim /etc/nginx/conf.d/blog.wenjinyu.me.conf

# 添加443端口以及ssl证书路径
server {
listen 443 ssl;
server_name blog.wenjinyu.me;
ssl_certificate /etc/letsencrypt/live/wenjinyu.me/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wenjinyu.me/privkey.pem;
...
}

# 添加防火墙规则,放行443端口
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# 启动nginx
systemctl start nginx

此时可以在浏览器中输入 https://域名 ,进行访问,如 https://wenjinyu.me

http跳转

如果希望只受理https请求(最好这样做,既然要https加密,那就干脆全站加密),那么可以在 http 设置跳转,即把80端口的请求跳转至 443

1
2
3
4
5
6
7
8
9
# 编辑配置文件
vim /etc/nginx/conf.d/default.conf

# 在 80 的 server 里添加跳转,注意替换网址
server {
listen 80;
server_name blog.wenjinyu.me;
rewrite ^/(.*)$ https://blog.wenjinyu.me/$1 permanent; # 添加本行
}

证书更新

Let’s Encrypt 的 ssl 证书有效期只有三个月,所以必须在三个月内进行证书更新,不过在证书过期之前会有官方发邮件进行通知,所以不必担心忘记

1
2
3
4
5
6
7
8
# 停止 Nginx, 释放端口
systemctl stop nginx

# 更新证书
letsencrypt certonly --standalone

# 启动 Nginx
systemctl start nginx

自动更新证书

linux有自带的定时任务管理器cron,也可以用来设置定时更新证书,这样就不用一直惦记着了。目前自动更新证书基本只有两个选择,一个是用webroot模式,不过这个模式配置繁琐,而且还有这样的问题:

Let’s Encrypt 提供了多种身份验证方式。与 standalone 相比,webroot 模式最大的优势在于没有宕机时间。然而 webroot 存在一些隐含的问题,它们是新手不易解决的。例如,webroot 需要在 nginx.conf 中添加特殊的规则以允许外界访问,但即便如此,该路径依旧被部分防火墙封杀。此外,启用了 301 跳转的服务器无法直接使用 webroot 更新证书,这期间需要反复修改配置文件,比 standalone 模式更为繁琐。十几秒的宕机时间对一般的网站来说可以忽略不计,因此我建议新手优先使用 standalone 模式。

而使用插件就简单多了,两行命令搞定:

1
2
3
4
5
# 安装插件
yum install python2-certbot-nginx

# 使用插件进行更新
certbot --nginx renew

如果写进cron,那么就能实现自动更新了,记住要使用root用户的cron

1
2
3
4
5
6
7
8
# 切换到root
su -

# 编辑
crontab -e

# 每星期更新一次
0 5 * * 6 /usr/bin/certbot --nginx renew

看了一下网站数据,凌晨3~5点访问量相对较少,周末尤为明显,所以就挑这个人少的时间段更新就可以了。

删除证书

如果域名不在使用,那么就涉及到删除证书的问题,可以使用命令指定删除证书:

1
certbot delete --cert-name wenjinyu.me

也可以批量删除:

1
certbot delete

之后按照提示输入需要删除的序号,中间用空格隔开就行,例如:

1
1 2 3

错误解决

  1. 证书更新错误

如果在更新证书的时候遇到下面这样的错误:

1
Attempting to renew cert from /etc/letsencrypt/renewal/wenjinyu.me.conf produced an unexpected error: 'ascii' codec can't decode byte 0xe7 in position 2: ordinal not in range(128). Skipping.

可以参考Github上的Issue #5236提出的解决方法:

1
grep -r -P '[^\x00-\x7f]' /etc/apache2 /etc/letsencrypt /etc/nginx

此方法是找出非ASCII字符并删除掉,从而解决问题,具体原因参见这里,大意是certbot不能支持命令行中的非ASCII字符,甚至这些字符出现在注释中时都是不允许的。

然而本人习惯在配置文件中添加中文注释,所以退而求其次,用了另一个方法,即先删除原本的证书而后再次添加:

1
2
certbot delete --cert-name wenjinyu.me
letsencrypt certonly --standalone --email wenjinyu959@gmail.com -d wenjinyu.me


评论