利用 Let’s Encrypt 给 Hexo 博客上 HTTPS

写在前面

如今 HTTPS 对于一个网站来说几乎是必不可少的。但可惜的是关于 Hexo 使用 HTTPS 的教程比较稀少。咱当然可以根据网上的教程,为 Apache 或者 Nginx 上 HTTPS,并且把 Hexo 的文章部署上去。但如果是这样的话,我也没有必要写这篇教程了。又或者,咱其实可以查阅 Nodejs 官方提供的文档中关于 HTTPS 模块的内容,然后自己照着写 server.js , 不过谁想阅读文档呢?因此,咱以 为Hexo博客启用HTTPS协议 为基础,写了一篇几乎可以说是’step-by-step’的教程。当然,咱用的 SSL 是免费的 Let’s Encrypt.

准备工作

  1. 一台可以从外网访问的主机(当然,已经安装了 Hexo 以及必要软件。还有,你用的应该是 GNU/Linux 吧?)
  2. 一个域名
  3. Certbot

Certbot 部分

首先咱要安装 Certbot。官方文档给的方案是使用 snap,不过咱觉得这样并不有利于管理,所以建议大家选用原生的软件包管理来装吧。

  • Debian 系安装:sudo apt install certbot
  • 红帽系安装:sudo dnf install certbot

接下来我们在终端里运行 sudo certbot certonly, 跟着指引输入,需要的必要信息有邮箱地址和域名。
颁发证书后会 Certbot 会告诉你证书的位置,把它记录下来。一般形如 /etc/letsencrypt/live/bethaod.gleeze.com/fullchain.pem(证书),/etc/letsencrypt/live/bethaod.gleeze.com/privkey.pem(密钥)。其他的文件不需要去管。
不过呢如果咱现在不是 root 用户的话,是访问不了这两个文件的。 为了保证即使是以普通用户的身份运行服务器时,咱依然能访问这两个文件,此时要改变这两个文件的访问权限。
运行chmod 0755 /etc/letsencrypt/{live,archive}, 然后chmod 0644 /etc/letsencrypt/live/yourdomain.com/{privkey,fullchain}.pem。记得要用sudo,并且替换成你的目录。
到这里证书就已经准备好了。

编辑server.js

咱直接把改好的代码贴上来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
'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("/etc/letsencrypt/live/yourdomain.com/privkey.pem"),
cert:fs.readFileSync("/etc/letsencrypt/live/yourdomain.com/fullchain.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});
}

最后不要忘了把yourdomain.com替换掉。

结语

总的来说这一套操作还是很简单的,快来练习一下吧!
如果觉得写得不错的话,欢迎通过邮箱或者 Telegram 联系咱哦。
更新 实际上通过 Nginx 反向代理并配置 HTTPS 是更好的方式。或者阁下可以直接套 Cloudflare,也能有 HTTPS。