昨天把 biz-to-me 升级到支持 HTTPS 了,为此研究了一下如何让 Heroku 上跑的 Node.js 应用支持 HTTPS。我发现并没有任何文章描述这个具体的流程,只有零碎的信息,所以在此记录一下。

首先,Heroku 应用要支持 HTTPS 必须要是付费的等级,最便宜的是每月 $7 的 Hobby 级别。把应用升级到 Hobby 级别后,我们在应用设置里面添加的域名就能自动获得 SSL 证书,这个过程是全自动的,无需手动操作。(全自动不意味着实时,每次添加新域名都需要等一段时间才会看到「ACM Status」这一栏变成「Ok」的状态。背后实际使用的证书签发机构其实是 Let’s Encrypt。)

一般 Heroku 应用的「DNS Target」是 app-name.herokuapp.com,需要留意的是一旦升级到支持 SSL 后这一栏的内容会改变,变成 app.example.com.herokudns.com,也就是在 herokudns.com 之前加上应用的整个域名。如果之前 DNS 的 CNAME 指向还是 herokuapp.com,那必须记得更新为 herokudns.com,否则 herokuapp.com 不会使用正确的 SSL 证书提供服务。(herokuapp.com 永远只会用 *.herokuapp.com 的证书提供服务,而 herokudns.com 会根据前缀选择正确的证书。)

在大多数情况下,Heroku 应用升级到支持 HTTPS 后应用代码不需要更新,这是因为 SSL 连接在 Heroku 的负载均衡器那里就种终止了,负载均衡器用明文 HTTP 跟应用连接所以应用本身不需要具备处理 HTTPS 的能力。(Node.js 有 https 模块,但调用时需要访问证书私钥,所以还是用 http 模块比较方便。)如果需要在 Node.js 中判断上游请求是不是 HTTPS,可以通过读取 X-Forwarded-Proto header 来实现,这个 header 的取值可以是 "http""https",例如说在 biz-to-me 中我就通过这一行代码来进行判断。

最后简述一下如何验证配置是否成功。最简单的方法自然是测试一下 HTTPS 服务是否正常工作。biz-to-me 的服务很简单,如果我打开一个 http(s)://*.catchen.biz/* 的 URL,它返回 301 把我重定向到 http(s)://*.catchen.me/*。这篇文章的 URL 是 https://chinese.catchen.me/2018/07/heroku-nodejs-https.html,如果我 curl -i 对应的 catchen.biz URL 能得到正确的 301 重定向那就是成功了。

$ curl -i https://chinese.catchen.biz/2018/07/heroku-nodejs-https.html
HTTP/1.1 301 Moved Permanently
Server: Cowboy
Connection: keep-alive
Location: https://chinese.catchen.me/2018/07/heroku-nodejs-https.html
Date: Sun, 01 Jul 2018 21:29:36 GMT
Transfer-Encoding: chunked
Via: 1.1 vegur Permanently moved to <a href="https://chinese.catchen.me/2018/07/heroku-nodejs-https.html">https://chinese.catchen.me/2018/07/heroku-nodejs-https.html</a>.

留意 Location header 的值是 HTTPS 开头的而非 HTTP,因为在 Node.js 代码更新到支持 HTTPS 之前我们也能得到类似的 301 响应,只不过 Location 永远都只是 HTTP 的。

如果 curl -i 因为证书不正确而出错的话,可以用 curl --insecure 来忽略证书验证 Node.js 代码。然后再用 curl -v 来查看证书,看看到底为什么证书错误。curl -v 的结果关键看这一段:

* Server certificate:
* subject: CN=cantonese.catchen.biz
* start date: Jul 1 04:44:37 2018 GMT
* expire date: Sep 29 04:44:37 2018 GMT
* subjectAltName: host "chinese.catchen.biz" matched cert's "chinese.catchen.biz"
* issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
* SSL certificate verify ok.

如果 Heroku 应用只添加了一个域名,subject 那一行的域名必须是这个唯一域名。如果看到 subject 那一行显示的是 *.herokuapp.com,那意味着我们需要把域名 CNAME 改为 herokudns.com,或者是域名变更还没生效。(变更还没在本地 DNS 生效的话,可以用 curl --resolve 在本地强行覆盖。)如果 Heroku 应用有多个域名,subject 会是其中一个,但 subjectAltName 会有多个域名,至少应该找到有一个对的。

最后,如果你喜欢我的文章的话,欢迎通过邮件RSS/Atom 订阅我的博客。

Heroku + Node.js + HTTPS的更多相关文章

  1. Node.js HTTPS

    稳定性: 3 - 稳定 HTTPS 是基于 TLS/SSL 的 HTTP 协议.在 Node 里作为单独的模块来实现. 类: https.Server 这是 tls.Server 的子类,并且和 ht ...

  2. Node.js之路【第一篇】初识Node.js

    什么是Node.js 1.Node.js就是运行在服务端的JavaScrip. 2.Node.js是一个基于Chrome JavaScrip运行时简历的一个平台. 3.Node.js是一个非阻塞I/O ...

  3. rabbitmq, windows/linux, c/c++/node.js/golang/dotnet

    官网:http://www.rabbitmq.com/ zeromq 相当于 message backbone,而rabbitmq相当于message broker.有的应用系统中,二者并存. (1) ...

  4. aix 上搭建node.js 环境

    下载nodejs:ibm-4.4.3.0-node-v4.4.3-aix-ppc64.bin IBM已经适配最新版本的node.js  :https://developer.ibm.com/node/ ...

  5. Node.js:JavaScript脚本运行环境

    Node.js https://nodejs.org/ 2016-08-03

  6. 安装Node.js

    1.window下安装Node.js 安装git,方便使用命令行. 网址:http://www.git-scm.com/download/ 下载后直接安装即可 接着安装Node.js https:// ...

  7. 【 js 模块加载 】深入学习模块化加载(node.js 模块源码)

    一.模块规范 说到模块化加载,就不得先说一说模块规范.模块规范是用来约束每个模块,让其必须按照一定的格式编写.AMD,CMD,CommonJS 是目前最常用的三种模块化书写规范.  1.AMD(Asy ...

  8. 使用node.js 脚手架搭建Vue项目

    1.安装node.js https://nodejs.org/zh-cn/ 下载安装node.js 在命令行测试 node -v 输出版本号说明安装成功 2.使用npm更新安装cpnm npm ins ...

  9. Node.js作web服务器总结

    1.为什么Node.js用JS开发    Node.js 含有一系列内置模块,使得程序可以脱离 Apache HTTP Server 或 IIS,作为独立服务器运行. 首先,我们都清楚的是,同时接收数 ...

随机推荐

  1. python 饥饿的小易(网易笔试题)

    本周早些时候,学弟给我发了一道网易的笔试题,饥饿的小易,感觉有点意思-分享给大家 题目描述: 小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃.最开始小易在一个初始位置x_0.对于小易所处的当前 ...

  2. MySQL mysqlbinlog解析出的SQL语句被注释是怎么回事

    MySQL mysqlbinlog解析出的SQL语句被注释是怎么回事   一网友反馈使用mysqlbinlog解析出的二进制日志中的内容中,有些SQL语句有#注释的情况,这个是怎么回事呢?我们通过实验 ...

  3. spring4笔记----依赖注入的两种形式

    设值注入:通过<property.../>元素驱动Spring执行setter的方法 构造注入:通过<constructor-arg.../>元素驱动Spring执行带有参数的 ...

  4. create table 使用select查询语句创建表的方法分享

    转自:http://www.maomao365.com/?p=6642 摘要:下文讲述使用select查询语句建立新的数据表的方法分享 ---1 mysql create table `新数据表名` ...

  5. Lua保留指定小数位数

    默认会四舍五入 比如:%0.2f 会四舍五入后,保留小数点后2位 print(string.format("%.1f",0.26)) ---会输出0.3,而不是0.2 Lua保留一 ...

  6. 如何进行Apache虚拟机设置

    摘要:虚拟机Apache设置很多用户都遇到过,具体如何进行虚拟机Apache设置?怎样才能让虚拟机Apache设置达到最简单,最优化?本文为您讲解. Apache虚拟机设置有两种方法: 基于主机名的虚 ...

  7. ThreadLocal源码调试——“this”作为key

    前言:在一次面试过程中被问到ThreadLocal,大家都知道ThreadLocal可以为每个线程单独提供一个副本,从而实现变量间的隔离.在ThreadLocal中set和get操作的key是什么,T ...

  8. Java基础知识点(二)

    前言:Java的基础知识点不能间断. 1.Array和ArrayList的区别 关于Array的用法,参看:http://blog.csdn.net/b_11111/article/details/5 ...

  9. ElasticSearch(四):使用Java连接ElasticSearch集群

    public class ESIndexMapping { private static String host="192.168.56.3"; // 服务器地址 private ...

  10. 2.05-random-uesr-proxy

    import urllib.request def proxy_user(): proxy_list = [ {"https":""}, # {"ht ...