为Hexo博客启用HTTPS协议

前言

随着HTTP协议的越来越不被待见,以及各大浏览器厂商对于HTTP采取的打压措施,举个栗子,当我在服务器上同时启用HTTP以及HTTPS监听的时候,访问HTTP服务的时候,就会被重定向到HTTPS的链接上,但是HTTPS的链接又不存在,然后就会出现如下报错:

所以每次都需要通过chrome://net-internals/#hsts进行缓存的删除。 至此,我不得不将我的博客更新为HTTPS协议。

一开始我以为Hexo是依赖Nginx的,直到我花了很长时间才搞明白,Hexo是完全不依赖Nginx或者Apache的,它是一个静态站点,通过NodeJs生成web server来展示数据,所以我感觉很多使用Hexo框架的小伙伴可能需要此博客。

关键词

步骤

之前写过一个Broswer-Sync的HTTPS启用方法,BS就很好,它提供了一个default-config.js的配置文件,我们直接配置HTTPS的证书即可。参考如下:

但是Hexo并没有提供类似的配置文件,我们需要编写自己的HTTPS Server。

Hexo

Hexo中的Server

与大多数WEB服务器一样,Hexo可以通过nodeJS创建一个connect Server,路径位于$PWD/node_modules/hexo-server/lib/server.js,参考如下:

话不多说,我们直接上代码 server.js

js
'use strict';

const connect = require('connect');
const http = require('http');
const chalk = require('chalk');
const Promise = require('bluebird');
const open = require('open');
const net = require('net');
const url = require('url');
const https = require("https");
const fs = require("fs");

module.exports = function(args) {
  const app = connect();
  const { config } = this;
  const ip = args.i || args.ip || config.server.ip || undefined;
  const port = parseInt(args.p || args.port || config.server.port || process.env.port, 10) || 4000;
  const { root } = config;

  //$PWD is your actual file path 
  const options = {
    key:fs.readFileSync("$PWD/www.majun.fun.key"),
    cert:fs.readFileSync("$PWD/www.majun.fun.pem")
  };
//enable Https server
//Using https.createServer()
//
  return checkPort(ip, port).then(() => this.extend.filter.exec('server_middleware', app, {context: this})).then(() => {
    if (args.s || args.static) {
      return this.load();
    }

    return this.watch();
  }).then(() => startServer(https.createServer(options,app), port, ip)).then(server => {
    const addr = server.address();
    const addrString = formatAddress(ip || addr.address, addr.port, root);

    this.log.info('Hexo is running at %s . Press Ctrl+C to stop.', chalk.underline(addrString));
    this.emit('server');

    if (args.o || args.open) {
      open(addrString);
    }

    return server;
  }).catch(err => {
    switch (err.code) {
      case 'EADDRINUSE':
        this.log.fatal(`Port ${port} has been used. Try other port instead.`);
        break;

      case 'EACCES':
        this.log.fatal(`Permission denied. You can't use port ${port}.`);
        break;
    }

    this.unwatch();
    throw err;
  });
};


function startServer(server, port, ip) {
  return new Promise((resolve, reject) => {
    server.listen(port, ip, resolve);
    server.on('error', reject);
  }).then(() => server);
}

function checkPort(ip, port) {
  if (port > 65535 || port < 1) {
    return Promise.reject(new RangeError(`Port number ${port} is invalid. Try a number between 1 and 65535.`));
  }

  const server = net.createServer();

  return new Promise((resolve, reject) => {
    server.once('error', reject);
    server.once('listening', resolve);
    server.listen(port, ip);
  }).then(() => { server.close(); });
}

function formatAddress(ip, port, root) {
  let hostname = ip;
  if (ip === '0.0.0.0' || ip === '::') {
    hostname = 'localhost';
  }

  return url.format({protocol: 'http', hostname: hostname, port: port, path: root});
}

注意事项

  • 需要添加2个新的引用,分别是httpsfshttps用来创建https Serverfs用来读取证书信息:
js
const https = require("https");
const fs = require("fs");
  • 添加一个新的变量,options,用来存放证书:
js
 const options = {
   key:fs.readFileSync("$PWD/5792506_www.majun.fun.key"),
   cert:fs.readFileSync("$PWD/5792506_www.majun.fun.pem")
 };
  • 最后我们只需要创建一个https的服务器就可以了:
js
https.createServer(options, app).listen(443);

Q&A

小朋友,你是否喜欢本博客呢?

如果想要我的帮助,可以email我,并描述清楚你的问题,[📧](mailto:jason@majun.fun)

Additional resources

后记

下一篇博客是基于树莓派的私人云盘——OwnCloud,我已经使用一段时间了,非常好用!

私 人 云 盘 - OwnCloud
Microsoft 365 Graph Explorer