Node.js 部署免費/自動續訂 HTTPS

隨着互聯網快速發展,互聯網信息安全愈來愈受到你們重視,HTTPS 應該是近兩年各大廠商都在盡力普及的技術之一。國內大廠基本上已經全面普及了 HTTPS。html

本文首發於個人我的網站:據說 - tasaid.com/,建議在個人我的網站閱讀,擁有更好的閱讀體驗。前端

前端開發 QQ 羣:377786580git

HTTPS 現狀

早在 2016 年末,我就寫過 《 從 HTTP 到 HTTPS 系列 》文章來說解 HTTPS。當時結合本站的部署經驗,給你們詳細介紹了 《 IIS 部署免費 HTTPS 》。github

這篇文章就跟你們介紹一下 Node.js 如何部署免費 HTTPS 以及簡單的部署 HTTP/2web

截止 2018 年 03 月 13 日,由 Let's Encrypt 實時統計報告 顯示,在統計的 6930 多萬活躍網站中,已經有 5350 萬(約 77%)的站點部署了 HTTPS 證書服務。chrome

lets encrypt stats

同時 Google 透明度報告 - 網絡上的 HTTPS 加密 中,統計了使用 Chrome 瀏覽器,訪問的站點統計中,HTTPS 使用率的增加狀況:typescript

google stats

而在今年 2 月份,Chrome 團隊也宣佈,將在 2018 年 7 月份發佈的 Chrome 68 中,將沒有部署 HTTPS 的網站標記爲 "不安全"。shell

chrome 68 status

簡而言之,HTTPS 大勢所趨。express

Node.js 部署 HTTPS

早在 《 從 HTTP 到 HTTPS - IIS 部署免費 HTTPS 》一文中,我就指出了 Let's Encrypt 免費證書的優點:npm

由 ISRG(Internet Security Research Group,互聯網安全研究小組)提供服務,免費、訪問速度快,穩定等。

因此此次部署的證書也是圍繞 Let's Encrypt 展開。

greenlock-express

因爲 js 生態圈的繁華,因此想找一個現有的包是件很輕鬆的事情,greenlock-express 這個包就幫助咱們封裝了 Let's Enctrypt 證書的部署,只須要引入這個包並使用,就能夠:

  1. 自動註冊 Let's Encrypt 證書
  2. 自動續訂( 80 天左右),且服務器無需重啓
  3. 支持虛擬主機

而且 greenlock 相關的證書生態圈十分完善,一樣有支持 koagreenlock-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 自簽證書同樣),用於在開發環境中調試。

API

greenlock-expresscreate(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/2HTTP/1.1 的升級版,主要來講改進了這些地方:

  1. 二進制協議:採用二進制流
  2. 多路複用:一次請求屢次複用管道
  3. 服務器推送:解決 HTTP/1.x 時代最大的痛點

值的注意的是,HTTP/2 是支持 HTTP 協議的,只不過瀏覽器廠商都不肯意支持 HTTP,因此基本上能夠認爲,用上 HTTP/2 的前置條件是必須部署 HTTPS。

SPDY

早在 2009 年,Google 開發了一個實驗性協議,叫作 SPDY,目的解決 HTTP/1.x 中的一些設計缺陷。在 SPDY 發佈幾年後,這個新的實驗性協議獲得了 Chrome、Firefox 和 Opera 的支持,應用愈來愈普遍。而後 HTTP 工做組 (HTTP-WG) 在這個 SPDY 的基礎上,設計了 HTTP/2,因此能夠說 SPDY 是 HTTP/2 的前身。

關於 HTTP/2 的詳情能夠參考 這篇文章

部署 HTTP/2

引入 HTTP/2Node.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

相關文章
相關標籤/搜索