Nodejs多站点切换Htpps协议详解及简单实例


Posted in NodeJs onFebruary 23, 2017

Nodejs多站点切换Htpps协议详解

纯属赶个时髦,折腾了两天终于将个人小站的全部服务由http协议切换到了https,整个过程虽然也不算太麻烦,但也不得不承认,个人对互联网安全这方面的知识确认比较欠缺;

Letsencrypt是由Mozilla、思科和EFF等组织发起的,免费向广大互联网网站提供SSL证书,目的在于加速推进互联网由Http过渡到Https,很高兴周末能够与其不期而遇,这对于一个互联网散户来说,绝对是大大的福利,所以决定乘周末折腾一番:先搞到证书,再改程序;

获取letsencrypt颁发的免费的SSL证书也是相对比较简单的,我还是个windows服务器,目前没能耐去折腾Linux,所以要下载letsencrypt-win-simple的安装包,运行letsencrypt.exe就开始了:第一步输入邮箱,如果不是第一次申请会跳过前两步,然后有5个选项供你选择,一般选M,输入M,Enter就到了让你输入需要证书的域,接着输入这个域对应的站点的根目录,输入一个线上运行的域即可,指定的根目录需要是能够直接访问的,因为他会访问你输入的域以及根目录下的某个文件,我很纳闷他是怎么在我站点新建的那些目录和验证文件,也就是说,他会在你指定的目录下新建两层目录和一个他需要访问的验证文件,准确的说他要知道这个乱码文件里的一段乱码内容来完成认证;完成认证后就会在C:\Users\Administrator\AppData\Roaming\letsencrypt-win-simple\httpsacme-v01.api.letsencrypt.org目录下生成证书文件;接下来的步骤就相对可以随意些了;

如果你就一个主域和一个站点,那么就可以拿证书去改程序了;

如果真的这样就完事了,那么是否感觉太快了,以致于没啥体验了;按照上面的步骤一个域下面可以生成一次证书,那么重复这些步骤,生成多个域下面的多个证书自然也是可以的了,问题在于必要性,或许折腾就是在为你的天真弱知买单;

Ok,我很天真;我为主域和两个二级域各生成了一次证书,接下来改程序咯!

我的站点是用Nodejs搭建的,内部由http-proxy代理来串起来的3个小站点,没有使用Nginx完全是为了以业余的玩性多去理解一点Nodejs;接下来主站监听443端口,二级站点由http-proxy代理分发;

var https=require('https');
var http=require('http');
var fs=require('fs');

var server = http.createServer(app);
var httpsServer=https.createServer({
 key: fs.readFileSync('./privatekey.pem'),
 cert: fs.readFileSync('./certificate.pem')
},app);

httpsServer.listen(443);
server.listen(80);

  代理中间件大概的样子:

app.use(function(req,res,next){
  var proxy = httpProxy.createProxyServer({
    headers:{
      'x-forward-ip':req.ip.match(/([\w\.]+)/g)[1]    }
  });
  proxy.on('error', function (err, req, res) {
    res.writeHead(500, {
      'Content-Type': 'text/plain'
    });
    res.end('Something went wrong.');
  });
  
  switch (req.headers.host){
    case 'm.famanoder.cn':
    proxy.web(req, res, { target: 'https://localhost:2333' });
    break;
    case 'cdn.famanoder.cn': 
    proxy.web(req, res, { target: 'https://localhost:3222' });
    break;
    default: 
      next();
  }
});

  这样主域用https访问一点问题没有,问题在于二级站点的访问浏览器始终会提示网站的证书不受信任,没办法,只好这样访问二级站点:https://cdn.famanoder.com:4000/,是的,带端口访问当然没问题,这样的话就没走代理了,可始终感觉不太方便,别扭,只能重想办法了;

又是一个机缘巧合,准备起身下班时看到了一篇文章,除了标题,全英文的,但直觉告诉了我,内容有我想要的东西;一脸懵逼的走马观花的看了一遍,果然豁然开朗了:在命令行里启动letsencrypt加--san参数来申请证书,可以为一个域绑定多个附带的域,也就说多个域可以共用同一套证书,那么代理的问题自然就解开了;输入主域后,再输入多个域用逗号隔开,然后他会依次去每个域验证,最后生成共用的一套证书;于是我决定了:今晚加餐!

Letsencrypt的验证方式为访问这个格式的地址:

http://cdn.famanoder.com/.well-known/acme-challenge/RHha4Dx3YaUzi7tu_C6p9mPk-TNpuLVN5hMQro2N1_Q

他会依次访问每个域的这个乱码文件,估计这个文件里有他想要的另一段乱码内容,打开看看就知道了;主站用的Express,cdn站点使用的原生Nodejs,两个站点的访问结果都是直接下载了文件,可能MIME头要改改,因为现在是多个域要访问同一个目录下的文件,索性在填写根目录时别填真正的根目录,而是填一个多个根目录共同所属的目录,比如D:\,修改路由文件如下:

 

// www(Express)
app.get('/.well-known/acme-challenge/:ids',function(req,res,next){
  require('fs').readFile('D:/.well-known/acme-challenge/'+req.params.ids,function(err,data){
    err&&console.log(err);
    res.end(data);
  });
});
// www(Koa2)
router.get('/.well-known/acme-challenge/:ids',async (cx,next)=>{
  await next();
  let data=await fs.readFileSync('D:'+cx.request.url);
  cx.response.body=data;
});

// cdn
if (req.url.indexOf('acme-challenge')!=-1) {
  var pathname=url.parse(req.url).pathname;
  fs.readFile('D:'+pathname,function(err,data){
    err&&console.log(err);
    res.writeHead(200,{
     'content-type':'text/html'
    });
    res.end(data);
    return false;
  });
}
return false;

  这样,多个域依次验证通过了,生成了同一套证书,有效期3个月,有效期内系统正常的话,3个月后会自动续期;那么就可以继续走http-proxy代理了,二级站点的https访问也不需要带端口了;接下来就是替换所有的http为https了,或者直接去掉协议,//www.famanoder.com格式也可以,浏览器会自动识别采用相应的协议;

由于Letsencrypt的验证域必须是线上可访问的,所以本地开发要另外配置,比如用Git自带的openssl生成一套证书作为开发调试时用也是可以的,只是浏览器会提示证书不受信用;

总之,说复杂也不复杂,说简单也不是那么简单,事情就是那么个事情,折腾就是为天真弱知买单嘛!

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

NodeJs 相关文章推荐
nodejs教程 安装express及配置app.js文件的详细步骤
May 11 NodeJs
Windows系统中安装nodejs图文教程
Feb 28 NodeJs
nodejs调用cmd命令实现复制目录
May 04 NodeJs
nodejs加密Crypto的实例代码
Jul 07 NodeJs
nodejs连接mongodb数据库实现增删改查
Dec 01 NodeJs
详解nodejs微信公众号开发——1.接入微信公众号
Apr 10 NodeJs
理解nodejs的stream和pipe机制的原理和实现
Aug 12 NodeJs
NodeJs项目中关闭ESLint的方法
Aug 09 NodeJs
nodejs读取本地中文json文件出现乱码解决方法
Oct 10 NodeJs
NodeJS 将文件夹按照存放路径变成一个对应的JSON的方法
Oct 17 NodeJs
PHPStorm中如何对nodejs项目进行单元测试详解
Feb 28 NodeJs
Nodejs异步流程框架async的方法
Jun 07 NodeJs
NodeJs下的测试框架Mocha的简单介绍
Feb 22 #NodeJs
基于Nodejs利用socket.io实现多人聊天室
Feb 22 #NodeJs
NodeJS配置HTTPS服务实例分享
Feb 19 #NodeJs
解决nodejs中使用http请求返回值为html时乱码的问题
Feb 18 #NodeJs
利用nodejs监控文件变化并使用sftp上传到服务器
Feb 18 #NodeJs
详解nodejs中exports和module.exports的区别
Feb 17 #NodeJs
Nodejs+Socket.io实现通讯实例代码
Feb 13 #NodeJs
You might like
PHP如何利用P3P实现跨域
2013/08/24 PHP
基于thinkPHP实现的微信自定义分享功能示例
2016/09/23 PHP
仅Firefox中链接A无法实现模拟点击以触发其默认行为
2011/07/31 Javascript
js去除空格的12种实用方法
2013/11/08 Javascript
js数组操作常用方法
2014/05/08 Javascript
JS实现FLASH幻灯片图片切换效果的方法
2015/03/04 Javascript
jQuery解析XML与传统JavaScript方法的差别实例分析
2015/03/05 Javascript
jquery实现点击其他区域时隐藏下拉div和遮罩层的方法
2015/12/23 Javascript
Vuejs在v-for中,利用index来对第一项添加class的方法
2018/03/03 Javascript
前端防止用户重复提交js实现代码示例
2018/09/07 Javascript
Vue多环境代理配置方法思路详解
2019/06/21 Javascript
如何在node环境实现“get数据解析”代码实例
2020/07/03 Javascript
Openlayers绘制聚合标注
2020/09/28 Javascript
修改NPM全局模式的默认安装路径的方法
2020/12/15 Javascript
[03:18]DOTA2亚洲邀请赛小组赛第一日 RECAP赛事回顾
2015/01/30 DOTA
Python 拷贝对象(深拷贝deepcopy与浅拷贝copy)
2008/09/06 Python
详细介绍Python语言中的按位运算符
2013/11/26 Python
基于Django的ModelForm组件(详解)
2017/12/07 Python
python 文本单词提取和词频统计的实例
2018/12/22 Python
使用Django2快速开发Web项目的详细步骤
2019/01/06 Python
python抓取搜狗微信公众号文章
2019/04/01 Python
解决python3 requests headers参数不能有中文的问题
2019/08/21 Python
浅谈python元素如何去重,去重后如何保持原来元素的顺序不变
2020/02/28 Python
在Anaconda3下使用清华镜像源安装TensorFlow(CPU版)
2020/04/19 Python
HTML5 Web Database 数据库的SQL语句的使用方法
2012/12/09 HTML / CSS
三只松鼠官方旗舰店:全网坚果销售第1
2017/11/25 全球购物
关于Java String的一道面试题
2013/09/29 面试题
门诊挂号室室长岗位职责
2013/11/27 职场文书
文明寝室标语
2014/06/13 职场文书
现实表现材料范文
2014/12/23 职场文书
体育活动总结
2015/02/04 职场文书
水电施工员岗位职责
2015/04/11 职场文书
幼儿园托班开学寄语(2016春季)
2015/12/03 职场文书
Mysql 如何实现多张无关联表查询数据并分页
2021/06/05 MySQL
Python字典和列表性能之间的比较
2021/06/07 Python
Pytorch中expand()的使用(扩展某个维度)
2022/07/15 Python