随着互联网快速发展,互联网信息安全愈来愈受到你们重视,HTTPS
应该是近两年各大厂商都在尽力普及的技术之一。国内大厂基本上已经全面普及了 HTTPS。html
本文首发于个人我的网站:据说 - tasaid.com/,建议在个人我的网站阅读,拥有更好的阅读体验。前端
前端开发 QQ 群:377786580git
早在 2016 年末,我就写过 《 从 HTTP 到 HTTPS 系列 》文章来说解 HTTPS
。当时结合本站的部署经验,给你们详细介绍了 《 IIS 部署免费 HTTPS 》。github
这篇文章就跟你们介绍一下 Node.js
如何部署免费 HTTPS
以及简单的部署 HTTP/2
。web
截止 2018 年 03 月 13 日,由 Let's Encrypt 实时统计报告 显示,在统计的 6930 多万活跃网站中,已经有 5350 万(约 77%)的站点部署了 HTTPS
证书服务。chrome
同时 Google 透明度报告 - 网络上的 HTTPS 加密 中,统计了使用 Chrome 浏览器,访问的站点统计中,HTTPS 使用率的增加状况:typescript
而在今年 2 月份,Chrome 团队也宣布,将在 2018 年 7 月份发布的 Chrome 68 中,将没有部署 HTTPS 的网站标记为 "不安全"。shell
简而言之,HTTPS 大势所趋。express
早在 《 从 HTTP 到 HTTPS - IIS 部署免费 HTTPS 》一文中,我就指出了 Let's Encrypt 免费证书的优点:npm
由 ISRG(Internet Security Research Group,互联网安全研究小组)提供服务,免费、访问速度快,稳定等。
因此此次部署的证书也是围绕 Let's Encrypt
展开。
因为 js 生态圈的繁华,因此想找一个现有的包是件很轻松的事情,greenlock-express 这个包就帮助咱们封装了 Let's Enctrypt
证书的部署,只须要引入这个包并使用,就能够:
Let's Encrypt
证书而且 greenlock
相关的证书生态圈十分完善,一样有支持 koa
的 greenlock-koa。
经过 npm
安装 greenlock-express
:
$ npm install --save greenlock-express@2.x
复制代码
使用起来很是简单,这是 greenlock-express
默认提供的 demo:
const greenlock = require('greenlock-express')
require('greenlock-express').create({
// 测试
server: 'staging',
// 联系邮箱
email: 'john.doe@example.com',
// 是否赞成 Let's Encrypt 条款... 这必须为 true 啊,否则走不下去
agreeTos: true,
// 申请的域名列表,不支持通配符
approveDomains: [ 'tasaid.com', 'www.tasaid.com' ],
// 绑定 express app
app: require('express')().use('/', function (req, res) {
res.end('Hello, World!');
})
}).listen(80, 443)
复制代码
证书存在 ~/letsencrypt
。
固然上面代码只能用于测试/开发环境,由于它并无申请一个有效的证书,而是生成了一个自签名的证书(跟之前的 12306 自签证书同样),用于在开发环境中调试。
greenlock-express
的 create(options)
函数参数签名以下:
interface Options {
/** * Express app */
app: Express
/* * 远程服务器 * 测试环境中可用为 staging * 生产环境中为 https://acme-v01.api.letsencrypt.org/directory */
server: string
/** * 用于接收 let's encrypt 协议的邮箱 */
email: string
/** * 是否赞成协议 */
agreeTos: boolean
/** * 在注册域名获取证书前,会执行这个回调函数 * string[]: 一组须要注册证书的域名 * 函数: 第一个参数跟 Options 格式差很少,第二个参数是当前自动获取的域名信息,第三个参数是在处理完以后传递的回调函数 */
approveDomains: string[] | (opts, certs: cb) => any
/** * 更新证书最大天数 (以毫秒为单位) */
renewWithin: number
/** * 更新证书的最小天数(以毫秒为单位) */
renewBy: number
}
复制代码
通过测试,在真实的生产环境中, approveDomains
必须为函数,传数组的话不会生效。
生产环境中部署还须要作一些配置改动和引入一些包。
更新包:
$ npm i --save greenlock-express@2.x
$ npm i --save le-challenge-fs
$ npm i --save le-store-certbot
$ npm i --save redirect-https
复制代码
生产代码:
const greenlock = require('greenlock-express')
const express = require('express')
const app = express()
const lex = greenlock.create({
// 注意这里要成这个固定地址
server: 'https://acme-v01.api.letsencrypt.org/directory',
challenges: {
'http-01': require('le-challenge-fs').create({ webrootPath: '~/letsencrypt/var/acme-challenges' })
},
store: require('le-store-certbot').create({
webrootPath: '~/letsencrypt/srv/www/:hostname/.well-known/acme-challenge'
}),
approveDomains: (opts: any, certs: any, cb: any) => {
appLog.info('approveDomains', { opts, certs })
if (certs) {
/* * 注意这里若是是这样写的话,必定要对域名作校验 * 不然其余人能够经过将域名指向你的服务器地址,致使你注册了其余域名的证书 * 从而形成安全性问题 */
// opts.domains = certs.altnames
opts.domains = [ 'tasaid.com', 'www.tasaid.com' ]
} else {
opts.email = '你的邮箱@live.com'
opts.agreeTos = true
}
cb(null, { options: opts, certs: certs })
},
})
// 这里的 redirect-https 用于自动将 HTTP 请求跳到 HTTPS 上
require('http').createServer(
lex.middleware(
require('redirect-https')()
)
).listen(80, function () {
console.log('Listening', `for ACME http-01 challenges on: ${JSON.stringify(this.address())}`)
})
// 绑定 HTTPS 端口
require('https').createServer(
lex.httpsOptions,
lex.middleware(app)
).listen(443, function () {
console.log(('App is running at http://localhost:%d in %s mode'), app.get('port'), app.get('env'))
console.log('Press CTRL-C to stop\n')
})
复制代码
若是没有生效,能够检查下 ~/letsencrypt
的证书信息,和 443 端口是否打开。
HTTP/2 是 HTTP/1.1 的升级版,主要来讲改进了这些地方:
值的注意的是,HTTP/2 是支持 HTTP 协议的,只不过浏览器厂商都不肯意支持 HTTP,因此基本上能够认为,用上 HTTP/2 的前置条件是必须部署 HTTPS。
早在 2009 年,Google 开发了一个实验性协议,叫作 SPDY,目的解决 HTTP/1.x 中的一些设计缺陷。在 SPDY 发布几年后,这个新的实验性协议获得了 Chrome、Firefox 和 Opera 的支持,应用愈来愈普遍。而后 HTTP 工做组 (HTTP-WG) 在这个 SPDY 的基础上,设计了 HTTP/2,因此能够说 SPDY 是 HTTP/2 的前身。
关于 HTTP/2 的详情能够参考 这篇文章。
引入 HTTP/2
在 Node.js
中也十分简单,只须要引入 spdy
包便可:
$ npm i --save spdy
复制代码
而后咱们把上一节的代码作一点修改便可支持 HTTP/2:
const greenlock = require('greenlock-express')
const express = require('express')
// HTTP/2
const spdy = require('spdy')
const app = express()
const lex = greenlock.create({
// 注意这里要成这个固定地址
server: 'https://acme-v01.api.letsencrypt.org/directory',
challenges: {
'http-01': require('le-challenge-fs').create({ webrootPath: '~/letsencrypt/var/acme-challenges' })
},
store: require('le-store-certbot').create({
webrootPath: '~/letsencrypt/srv/www/:hostname/.well-known/acme-challenge'
}),
approveDomains: (opts: any, certs: any, cb: any) => {
appLog.info('approveDomains', { opts, certs })
if (certs) {
/* * 注意这里若是是这样写的话,必定要对域名作校验 * 不然其余人能够经过将域名指向你的服务器地址,致使你注册了其余域名的证书 * 从而形成安全性问题 */
// opts.domains = certs.altnames
opts.domains = [ 'tasaid.com', 'www.tasaid.com' ]
} else {
opts.email = '你的邮箱@live.com'
opts.agreeTos = true
}
cb(null, { options: opts, certs: certs })
},
})
// 这里的 redirect-https 用于自动将 HTTP 请求跳到 HTTPS 上
require('http').createServer(
lex.middleware(
require('redirect-https')()
)
).listen(80, function () {
console.log('Listening', `for ACME http-01 challenges on: ${JSON.stringify(this.address())}`)
})
// HTTP/2
spdy.createServer(lex.httpsOptions, lex.middleware(app)).listen(443, function () {
console.log('Listening https', `for ACME tls-sni-01 challenges and serve app on: ${JSON.stringify(this.address())}`)
})
复制代码
至于 HTTP/2 相关的技术应用,会在后续篇幅中再为你们讲解。
本文首发于个人我的网站:据说 - tasaid.com/,建议在个人我的网站阅读,拥有更好的阅读体验。
前端开发 QQ 群:377786580