隨着互聯網快速發展,互聯網信息安全愈來愈受到你們重視,HTTPS
應該是近兩年各大廠商都在盡力普及的技術之一。國內大廠基本上已經全面普及了 HTTPS。html
本文首發於個人我的網站:據說 - https://tasaid.com/,建議在個人我的網站閱讀,擁有更好的閱讀體驗。前端
前端開發 QQ 羣:377786580
早在 2016 年末,我就寫過 《 從 HTTP 到 HTTPS 系列 》文章來說解 HTTPS
。當時結合本站的部署經驗,給你們詳細介紹了 《 IIS 部署免費 HTTPS 》。git
這篇文章就跟你們介紹一下 Node.js
如何部署免費 HTTPS
以及簡單的部署 HTTP/2
。github
截止 2018 年 03 月 13 日,由 Let's Encrypt 實時統計報告 顯示,在統計的 6930 多萬活躍網站中,已經有 5350 萬(約 77%)的站點部署了 HTTPS
證書服務。web
同時 Google 透明度報告 - 網絡上的 HTTPS 加密 中,統計了使用 Chrome 瀏覽器,訪問的站點統計中,HTTPS 使用率的增加狀況:chrome
而在今年 2 月份,Chrome 團隊也宣佈,將在 2018 年 7 月份發佈的 Chrome 68 中,將沒有部署 HTTPS 的網站標記爲 "不安全"。typescript
簡而言之,HTTPS 大勢所趨。shell
早在 《 從 HTTP 到 HTTPS - IIS 部署免費 HTTPS 》一文中,我就指出了 Let's Encrypt 免費證書的優點:express
由 ISRG(Internet Security Research Group,互聯網安全研究小組)提供服務,免費、訪問速度快,穩定等。
因此此次部署的證書也是圍繞 Let's Encrypt
展開。npm
因爲 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 相關的技術應用,會在後續篇幅中再爲你們講解。
本文首發於個人我的網站:據說 - https://tasaid.com/,建議在個人我的網站閱讀,擁有更好的閱讀體驗。
前端開發 QQ 羣:377786580