Node.js + Nginx 部署 HTTPS 服务

12,255

今天,经过无数次折腾,向往已久的域名备案终于下来了。于是迫不及待地将个人博客网站进行 HTTPS 部署迁移,中间遇到一些坑,在此做个记录。

原因

之所以要将网站从 http 迁移到 https,原因有:

  • https 更安全,相对于 http 可以较为有效防止中间人攻击,每个项目都希望安全托底。博客虽然没有重要数据,但不失为练兵的好地方。
  • 如今 HTTP2 越来越受人关注,它可以提高访问速度,而 HTTP2 的前提就是 HTTPS

步骤

  1. 安装证书
  2. nginx 反向代理
  3. 更改前端连接方式

安装证书

为什么需要证书?这和 HTTPS 协议的设计有关。 HTTPS,指的是 Hypertext Transfer Protocol Secure,另外也也可以称为 HTTP over SSL 或者 HTTP over TLS。通俗一点,HTTPS 通过 Http 协议传输数据,SSL/TLS 加密数据。

它是如何实现加密的呢?

首先,浏览器厂商预先安装了各个 证书颁发机构 的证书,用于对访问网站进行安全验证 然后,个人向 证书颁发机构 申请个人证书,并将证书应用于服务器配置中。 之后浏览器访问服务器,获取公钥,将其与已有的证书列表匹配,决定是否继续。 如果通过,浏览器通过公钥与服务器通信,协商两个非对称私钥,用于各自的数据传输加密,从而建立的加密通道,防止中间人窃听。

如何安装证书? 向证书颁发机构申请证书即可。目前的机构有Symantec、Comodo、GoDaddy 以及 Let's Certbot。这里我们选择免费的 Let's Certbot

在官网上有详细的说明。我的环境是 Linux 16.04 Nginx,其他的环境可以参照官网说明:

#####安装:

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx 
开始
$ sudo certbot --nginx certonly
自动续期

可以参考 这里

根据提示,顺利安装完毕。这里有个前提,就是服务器要有域名,而国内的域名都需要按照工信部要求备案,这也是为什么我需要等待大半个月的原因。

反向代理

证书安装完毕,如果部署在 nginx 中的是静态页面,那么此刻已经顺利部署了 HTTPS 服务。但是更多的应用场景中,我们一方面提供静态服务,如 img、js、css 等等,另一方面我们也需要 REST 服务。 但是此刻,当我们通过 axios 或者 vue-resource 这样的 HTTP client 库来访问 Node.js 服务 API 来获取数据,发现浏览器禁止了该连接。原因是在部署 HTTPS 服务后,整站都要使用 https 来进行数据传递,包括资源的获取,GET/POST 请求等等。

如何解决?我在这走了一些弯路。当时想,因为是访问 Node.js 服务器的 API,我知道 Node.js 是支持 HTTPS 服务的,所以想当然在 Node 中使用 Openssl 来进行自认证。网上有很多类似的教程,但是在浏览器中,对于自认证的证书并不认可。所以这种方法可行但不适用于其他用户访问,更不能应用于生产环境。这里推荐几个工具:

第一个是可以发送模拟浏览器发送各种请求,对于测试 API 来说十分方便 第二个之所以在这里推荐是因为我一开始使用 Chrome,但给出的错误提示很模糊,而 Firefox 在 Network 中对于 Request/Response 错误信息会更直白,在这个问题上帮了我很多忙。

正是 Firefox 给出的提示:xxxx 提供了不支持的自签名证书..,我知道自签名走不通,于是往 Nginx 上考虑了一下,想到 nginx 有反向代理功能,如果说,做一个 api 的反向代理,导航到 node 服务端口,会不会有用呢?于是在网上查找了 Nginx 反向代理的教程,操作如下:

/ete/nginx/site-available/default 中:

location /api {
    proxy_pass      http://localhost:8089;
    proxy_buffering on;
}

重启 nginx,重启 node 服务。

success!

这样,我们通过反向代理让 REST 服务无需担心证书问题,因为 Nginx 已经做了这一部分工作。

更改前端连接方式

这一部分可选,因为我之前使用的是 vue-resource,连接使用 this.$http 所以无法对 HTTPS 进行连接,解决该问题,可以:

  • 使用 axios,简单优雅处理

最后

整个过程写的比较乱,原因还是自己对 SSL/TLS 的底层协议不熟悉,而且 Nginx 也是新学,反向代理之前只有所耳闻,并没有实际操作过。但不得的说,Nginx 的配置方式比较友好,一看就明白它是什么意思。所以配置起来也不复杂。

接下去会把这部分在深入一点,写一个系列吧。