为了方便做一些模拟验证,我们有时候需要在本地起 https 环境,比如调试验证一些协议是 https 的内嵌页面。
最先想到的方法当然是自签名证书,自己签发证书和密钥之后,启动一个 https 服务即可。这块网上资料比较杂乱,下面记录一下过程。
首先本地要安装一下 openssl,用来生成证书。mac 上的话 homebrew 安装即可,我本地安装过了,查看一下版本:
┌─(~)─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s004)─┐
└─(14:31:29)──> openssl version ──(三, 309)─┘
LibreSSL 2.8.3
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:14:47)──> openssl genrsa -out server.key 1024 ──(五, 211)─┘
Generating RSA private key, 1024 bit long modulus
....++++++
.............++++++
e is 65537 (0x10001)
可以看到 server.key
已经有了:
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:15:08)──> ll ──(五, 211)─┘
total 8
drwxr-xr-x 11 albert staff 352B 2 8 14:03 code
drwxr-xr-x 8 albert staff 256B 2 11 14:51 demo
drwxr-xr-x 4 albert staff 128B 1 19 17:00 github
drwxr-xr-x 3 albert staff 96B 12 20 10:57 gitlab
-rw-r--r-- 1 albert staff 887B 2 11 16:15 server.key
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:15:13)──> openssl req -new -key server.key -out server.csr ──(五, 211)─┘
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) []:CN
State or Province Name (full name) []:Shanghai
Locality Name (eg, city) []:Shanghai
Organization Name (eg, company) []:Company
Organizational Unit Name (eg, section) []:Company
Common Name (eg, fully qualified host name) []:*.localhttps.com
Email Address []:
Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
req 的时候需要根据命令行提示输入必要信息,前几个可以一路回车,直到 Common Name
这里需要输入 localhost
,也可以天 *.domain.com
申请通配符域名证书。最后的 password
也可以放空。
执行完之后可以看到申请文件 server.csr
已经生成:
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:18:02)──> ll ──(五, 211)─┘
total 16
drwxr-xr-x 11 albert staff 352B 2 8 14:03 code
drwxr-xr-x 8 albert staff 256B 2 11 14:51 demo
drwxr-xr-x 4 albert staff 128B 1 19 17:00 github
drwxr-xr-x 3 albert staff 96B 12 20 10:57 gitlab
-rw-r--r-- 1 albert staff 668B 2 11 16:18 server.csr
-rw-r--r-- 1 albert staff 887B 2 11 16:15 server.key
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:18:05)──> openssl x509 -req -in server.csr -out server.crt -signkey server.key -days 3650 ──(五, 211)─┘
Signature ok
subject=/C=CN/ST=Shanghai/L=Shanghai/O=Company/OU=Company/CN=*.localhttps.com
Getting Private key
这里可以通过-days
设置有效期,比如我这里生成了一个十年有效的 server.crt
:
┌─(~/Documents/Code)──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────(albert:s002)─┐
└─(16:18:19)──> ll ──(五, 211)─┘
total 24
drwxr-xr-x 11 albert staff 352B 2 8 14:03 code
drwxr-xr-x 8 albert staff 256B 2 11 14:51 demo
drwxr-xr-x 4 albert staff 128B 1 19 17:00 github
drwxr-xr-x 3 albert staff 96B 12 20 10:57 gitlab
-rw-r--r-- 1 albert staff 883B 2 11 16:18 server.crt
-rw-r--r-- 1 albert staff 668B 2 11 16:18 server.csr
-rw-r--r-- 1 albert staff 887B 2 11 16:15 server.key
由于要响应静态资源,并且起 https 服务的时候我不想再写端口,所以比起 https.createServer
我们还要再多写点代码。
方便起见,我就用 koa 了,先起一个大家经常写的 http 服务:
const path = require('path');
const fs = require('fs');
const Koa = require('koa');
const BodyParser = require('koa-bodyparser');
const serve = require('koa-static');
const mount = require('koa-mount');
const cors = require('@koa/cors');
const Router = require('@koa/router');
const PORT = 3002;
const sdkConfig = {...};
const app = new Koa();
const static_pages = new Koa();
static_pages.use(serve(__dirname + '/build'));
app.use(mount('/', static_pages));
app.use(BodyParser());
app.use(cors());
const router = new Router();
router.get('/api/data',async (ctx, next)=>{
ctx.status = 200;
ctx.body = { data: 1 };
await next();
});
app.use(router.routes()).use(router.allowedMethods());
app.listen(PORT, function () {
console.log("==> Listening on port %s. Visit http://localhost:%s/", PORT, PORT);
});
再把他改造成 https 服务:
+ const http = require('http');
+ const https = require('https');
const path = require('path');
const fs = require('fs');
const Koa = require('koa');
const BodyParser = require('koa-bodyparser');
const serve = require('koa-static');
const mount = require('koa-mount');
const cors = require('@koa/cors');
const Router = require('@koa/router');
const PORT = 3002;
const sdkConfig = {...};
const app = new Koa();
const static_pages = new Koa();
static_pages.use(serve(__dirname + '/build'));
app.use(mount('/', static_pages));
app.use(BodyParser());
app.use(cors());
const router = new Router();
router.get('/api/data',async (ctx, next)=>{
ctx.status = 200;
ctx.body = { data: 1 };
await next();
});
app.use(router.routes()).use(router.allowedMethods());
- app.listen(PORT, function () {
- console.log("==> Listening on port %s. Visit http://localhost:%s/", PORT, PORT);
- });
+ http.createServer(app.callback()).listen(PORT);
+ const options = {
+ key: fs.readFileSync('./config/server.key', 'utf-8'),
+ cert: fs.readFileSync('./config/server.cert', 'utf-8'),
+ };
+ https.createServer(options, app.callback()).listen(443, () => {
+ console.log('==> Listening on port 443. Visit https://localhost');
+ });
相比之前这里稍作了改动。先照常启动一个 http 服务,把之前生成的签名证书和密钥读取之后,在启动一个相同的 https server 监听 443端口。这样就可以通过 https://localhost
,不用加端口直接访问服务了。
直接用 chrome 访问试试,大概率会显示 SSL error: ERR_CERT_INVALID
,老版本 chrome 可以选择跳过,新版 chrome 对这方面限制的并且无法跳过。
chrome://flags/#allow-insecure-localhost
开启允许无效证书选项。thisisunsafe
告诉 chrome 你知道的,不用管。我比较喜欢解法二。