NodeBB 5: 让你的网站全面使用HTTPS

Posted by River Yang on 2016-10-31

V2MM 上线后开始考虑支持 HTTPS, 毕竟现在这个网络环境, 单纯的 HTTP 就像在网络上裸奔一样,总会吸引一些恶狼。
Google 了一圈服务提供商,发现 Let’s encrypt 人气最高。

Let’s Encrypt 是由互联网安全研究小组(ISRG,一个公益组织)提供的服务。主要赞助商包括电子前哨基金会,Mozilla基金会,Akamai以及思科。2015年4月9日,ISRG与Linux基金会宣布合作。
—— 维基百科

Let’s encrypt 提供免费的 HTTPS 服务,通过软件申请,速度快,服务好,各种浏览器都兼容,还支持多域名,业界良心!

严重不推荐 StartSSL 和 沃通(Wosign)的证书,这两家其实是一家,背地里做了不少坏事,前阵子被火狐拉黑了, 现在用他们的证书简直是找死。

OK,开始签证书了,根据官网的向导一步一步操作。本文不赘述步骤,仅记录我遇到的一些坑和易犯的错。

准备工具: acme-tiny

打开 Let’s encrypt 官网,官网推荐的工具是 Certbot, 大概是官方的工具,也开源,但是坑跌的是在我的系统上运行不了,官方还未支持。大概因为其开源的特性,第三方工具不少,我选的 acme-tiny, github 赞好多!

acme-tiny 其实就一个 python 脚本,如它官网所说,不到200行,阅读一遍就了解 ACME client 的原理了。

使用 acme-tiny 申请证书

在验证之前,你需要先用 openssh 创建几个 key: account.key, domain.key. 然后通过 openssh 生成 csr 文件,acme-tiny 官网有介绍,不赘述。
生成 csr 文件时要注意,你需要签约的网站名称需要包含在 common name 或 Alternative Name, acme_tiny.py就是通过这两个地方读取 domain name 的。
生成 csr 除了按照 acme_tiny 的教程使用 openssl 的默认配置以外,还可以使用 openssl 的向导,一步一步配置:

openssl req -new -sha256 -key domain.key -out domain.csr

生成 csr 后可以检查一下 common name 和 Alternative Name:

openssl req -in domain.csr -noout -text

准备好 csr 文件后,就该向 Let’s encrypt 申请了。 Let’s encrypt 的免费证书是这样验证你对网站的掌控权的: 放置一个随机的文件到你的网站目录下,然后通过 HTTP 访问这个文件,如果成功则证明你是这个网站的所有者。它的验证 URI 是 /.well-known/acme-challenge/ , 所以我们还得在 nginx 下配置这个 location:

location /.well-known/acme-challenge/ {
        alias /var/www/challenges/;
        try_files $uri =404;
    }

要注意这个位置的权限, nginx 和 acme_tiny.py 都可以访问。

配置好后,就可以运行 py 脚本,申请证书了, Good luck!

python acme_tiny.py --account-key ./account.key --csr ./domain.csr --acme-dir /var/www/challenges/  > ./signed.crt

现实的情况是,我紧盯着程序的输出,发现很快就报错了,显示 Let’s encrypt 服务器返回的 500 错误。结果检查配置,重新运行了几遍,发现不是 500 internal server error 就是 404 challenges not found, 而且有时候错在 registering account, 有时候错在 checking challenge. 网上搜了一下,发现很多很多人都发生了同样的错。

于是根据官网的推荐,使用他们的 staging 服务器先测试一遍,这是供开发者使用的,在 acme_tiny.py 中注释掉 default-CA, 启用:

DEFAULT_CA = "https://acme-staging.api.letsencrypt.org"

通过 staging 可以检查你的配置是否正确。但是结果并无异常,我只能怀疑 Let’s encrypt 的服务器抽风了。
庆幸的是,我在尝试了十几次后,终于签出来了!
如果有人也发生了类似的问题,通过 Google 搜索到本文,希望你能仔细检查你的配置和服务器的返回, 还可以查看 nginx 的 access log 和 error log, 查看 Let’s encrypt 是否有正常的访问 challenge file, 然后多试几次 :)

nginx 启用 HTTPS

启用 443 端口,然后 配置 https 访问官网有教程,也不赘述。将 HTTP 访问强制转为 HTTPS 也很简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name v2mm.tech www.v2mm.tech;
root /usr/share/nginx/html;
location /.well-known/acme-challenge/ {
alias /var/www/challenges/;
try_files $uri =404;
}
location / {
return 301 https://$server_name$request_uri;
}
...

根据 Nginx 文档,这样做是最简单效率最高的,我还保留了 /.well-known/acme-challenge/ 的访问, 方便下次 renew Let’s encrypt 的证书。

如有疑问,欢迎来到 V2MM 上讨论。