koa2+mongodb搭建后台

目录 技术

前言

毫无疑问,目前nodejs里面用来开发后台的首选就是koa2+mongodb的组合了。参考过很多博客,都是零零碎碎不齐全,要么很简单只是教你如何运行一个demo,要么只讲了简单的一方面,要么就是一个复杂的koa项目生成器,我设想的一个最基础的后台应该具有以下内容:

此处只讨论前后端分离,后台项目提供接口,不考虑模板渲染之类的,毕竟你都用nodejs做后台了,还不做前后端分离也太说不过去了
– 对传入、返回及错误数据做统一处理
– 支持跨域
– 使用 token 做身份验证
– 完善的日志记录
– 支持发送邮件
– 上传文件
– 常见的数据库操作,对列表数据分页,返回指定行数据做封装
– 调试

所以在折腾完之后,就想把整个过程记录一下,如果你正好是刚开始摸索,应该能让你避免不少弯路。

创建基础项目

  • 创建koa-mongo目录,并运行 npm init 创建package.json
mkdir koa-mongo
cd ./koa-mongo
npm init
  • 安装基础包
npm install koa # koa,必须的
npm install koa-router  # 路由,必须的,这里要注意的是还有一个koa-route,这两个是不同的,不要用koa-route
npm install koa-static  # 静态资源,必须的
  • 创建app.js,填入以下内容:
// koa
const Koa = require('koa')
const app = new Koa()

// midleware
const serve = require('koa-static')

app.use(serve('./assets'))

var server = app.listen(3000, function (){
    const host = server.address().address;
    const port = server.address().port;
    console.log('app start listening at http://%s:%s', host, port);
});

此处创建了一个实例,监听3000端口,将assets目录作为静态资源运行,我们创建一个assets目录,里面创建一个index.html,然后我们运行起来试试:

node ./app.js

此时会打印一行日志:app start listening at http://:::3000,让我们来访问试试:

ok,koa启动一个项目就是这么简单。。

添加路由

在koa-router的使用说明中,我们可以看到是这样使用的:

var router = new Router();

router.get('/', (ctx, next) => {
  // ctx.router available
});

app
  .use(router.routes())
  .use(router.allowedMethods());

因为正常项目中,controller肯定不止一个的,所以我把目录写成这样:

├─ controller
    ├─ test-controller
├─ router.js

controller目录用来放置所有的controller,在router.js中统一汇总,app.js中只需要使用router.js即可。
test-controller:

const hello = async (ctx, next) => {
    ctx.body = 'hello world'
    ctx.status = 200;
}

module.exports = {
    'test/hello': hello,
}

router.js:

const Router = require('koa-router')
const router = new Router({
    prefix: '/api', // 统一前缀,接口全部为 /api/xxx 格式
})

const testController = require('../controller/test-controller')

Object.keys(testController).forEach(key=>{
    router.all("/"+key, testController[key]);   // router.all是允许所有的访问方式,如果需要限定则改为指定方式即可
})

module.exports = router;

app.js:

// router
const router = require('./router')
app.use(router.routes()).use(router.allowedMethods())

这个时候让我们重新启动一下,访问localhost:3000/api/test/hello试试:

可以看到正确返回了hello world。

调试

到这里了,有没有感觉哪里不对劲。每修改一次,都需要手动敲命令重启一次,这简直太烦了好嘛,我们程序猿哪能忍受这个。答案就是使用nodemon,这个玩意儿能监听我们的文件变更,自动运行命令重启应用。使用方式也很简单,这个我们直接全局安装就好了:

npm install -g nodemon

然后去package.json的scripts中添加一行脚本:

"dev": "nodemon ./app.js",

然后 npm run dev,把hello函数修改一下返回值,保存,就会看到nodemon自动帮我们重启应用了。

除了nodemon,类似的工具还有很多,这里就不展开说了,现在的你只需要知道开发用nodemon,线上用pm2就ok了

解决了自动运行之后,我们来说一下调试。其实nodejs自带了调试的,只需要一个inspect参数,调试的时候就跟我们在chrome中调试是一模一样的。
我们先去package.json的scripts中添加一行脚本:

"debug": "nodemon --inspect ./app.js",

然后我们运行 npm run debug,刷新我们的网页,用f12打开,此时我们能看到开发者工具上面多了一个nodejs的图标:

点击这个图标,就可以跟调试网页一样调试nodejs代码了:

配置化

代码就是一步步总结,边写边优化,重构。到目前为止,我们会发现有不少配置性的东西是散乱在不同文件中,比如说项目启动时监听的端口,接口的统一前缀,考虑到我们还会有很多配置项,我们应该把这些写到一个配置文件中集中管理。
新建一个config.js:

module.exports= {
    port: 3000,
    apiPrefix: '/api',
}

然后把用到的地方全部更改为变量

跨域

为了防止跨域问题,我们需要使用koa2-cors类库,使用方式很简单:

npm install koa2-cors

然后在app.js中添加以下内容:

const cors = require('koa2-cors')
app.use(cors())

一行代码搞定,cors的具体配置此处就不细说了,有兴趣的可以自己去看看

处理参数,上传文件

一般来说,我们是使用koa-bodyparser 和 koa-multer来分别处理表单数据和文件数据的。这两个分别集成也没什么问题,但我们可以直接使用koa-body来完成。koa-body是基于co-body和formidable做了封装,同时支持参数解析和文件上传。最后是把参数和文件分别放到ctx.request.body和ctx.request.files变量中。
我这里是把上传文件统一放到assets/upload目录中

const uploadDir = path.join(__dirname, 'assets/upload/')
// 其实此处还需要判断文件夹是否存在,不存在的话就创建
app.use(koaBody({
    multipart: true,
    encoding: 'utf-8',
    formidable:{
        uploadDir: uploadDir,
        keepExtensions: true,
        maxFieldsSize: 5*1024*1024,
        onFileBegin:(name, file)=>{

        }
    }
}))

token验证

使用jwt,待续

统一返回格式

待续

mongodb

待续

日志模块

待续

微信支付

待续

iisnode运行koa2项目

目录 技术

前言

前段时间在研究koa2+mongodb,捣鼓完一个项目之后,就是发布的问题了。一般来说,nodejs的项目,推荐开发用nodemon,生产用pm2。两者都可以监听文件变更重启node项目,而pm2则更为强大,更拥有性能监控,日志,负载均衡等等高级功能。

在linux服务器上,我们一般会选择使用pm2启动,然后使用nginx转发。而在windows上,我们首选的则是这个iisnode啦,不为别的,就因为这货是iis插件,使用更方便,也能够监听文件变更自动重启node项目,至于作者宣称的其他各种优点,我们就不用管了,毕竟真要说性能的话,我在stackoverflow上面还见过吐槽iisnode性能差的问题呢。

准备工作

  • iis7.x/8.x
    > 请注意不要低于iis7,至于iis express/WebMatrix,iisnode也是支持的
  • nodejs
    > 下载并安装nodejs的最新windows版本

安装url-rewrite

因为需要用到路由重写,所以必须为iis安装URL Rewrite插件,下载地址为:
https://www.iis.net/downloads/microsoft/url-rewrite

安装iisnode

https://github.com/Azure/iisnode

直接在github项目的release中下载最新版,我们直接下载iisnode-full系列就ok了。
这货最早是tjanczuk私人开发的,后面捐赠给微软了,旧地址为
https://github.com/tjanczuk/iisnode

初步使用

  • 具体安装步骤就不说了,直接让他下一步下一步安装完,默认安装路径为:C:
    \Program Files\iisnode

  • 然后我们直接运行setupsamples.bat文件,它会自动在default web site中添加一个node项目

  • 此时我们访问http://localhost/node,如果能看到下面的页面就说明大功告成了

部署koa2项目

还是老样子创建站点,然后将路径指向koa2项目的根路径,只需要添加一个web.config文件,填入以下内容:

<configuration>
   <system.webServer>

     <handlers>
       <add name="iisnode" path="app.js" verb="*" modules="iisnode" />
     </handlers>

     <rewrite>
       <rules>
         <rule name="app">
           <match url="/*" />
           <action type="Rewrite" url="app.js" />
         </rule>
       </rules>
     </rewrite>

     <security>
       <requestFiltering>
         <hiddenSegments>
           <add segment="node_modules" />
         </hiddenSegments>
       </requestFiltering>
     </security>    

     <iisnode
      nodeProcessCommandLine=""D:\Program Files\nodejs\node.exe"" 
      interceptor=""%programfiles%\iisnode\interceptor.js"" />

   </system.webServer>
 </configuration>

请注意最后一段,我在里面指明了nodejs的执行路径,因为他的默认配置是指向C盘的,而我安装时安装在了D盘,所以会报一个无法执行nodejs的错误。
所有的可配置选项,在sample中也有列出来:
https://github.com/Azure/iisnode/blob/master/src/samples/configuration/web.config

mongodb开启身份验证

目录 技术

前言

此处记录一下mongodb开启身份验证的步骤

具体步骤

  • 安装mongodb
    > mac下直接使用homebrew安装即可:brew install mongodb,windows则下载对应的安装包
  • 创建用户
# 超级管理员
use admin
db.createUser({
    user: "root",
    pwd: "pwd",
    customData: {description: "管理员用户"},
    roles: ["root"],
})
# 业务数据库用户
use tradition
db.createUser({
    user: "tradition",
    pwd: "pwd",
    roles:[
        {role:"readWrite", db:"tradition"},
        {role: "dbAdmin", db:"tradition"},
    ]
})  
  • 开启验证
    > mac需要修改 /usr/local/etc/mongod.conf,windows修改安装目录下的mongod.cfg,添加以下两行配置
security:
  authorization: enabled

算法

目录 未分类

前言

很久没上来看了,此处来记录一下之前用js做的几个算法题。里面涉及动态规划、穷举、迷宫、路径等等。

jsfiddle

以下是题目

  1. 编程:断开链条
    给定一个包含N个整数的数组A,假设这个数组表示的是一条链条,其中每个元素表示链条上的一环。 现在我们想把这条链条断成3小部分。 我们需要做的就是断开不相连的两个环, 更确切的说,我们需要断开环P、 Q( 0<P<Q<N-1, Q-P > 1),得到三个小链条[0,P-1],[P+1,Q-1],[Q+1,N-1]。
    上述操作的成本是A[P]+A[Q]。
    例如:数组A为
    A[0] = 5
    A[1] = 2
    A[2] = 4
    A[3] = 6
    A[4] = 3
    A[5] = 7
    我们可以选择如下方式断开链条
    ( 1, 3):成本是 2+6 = 8
    ( 1, 4):成本是 2+3 = 5
    ( 2, 4):成本是 4+3 = 7
    写一个函数
    int breakchain(int A[], int N);
    对任一个给定的链条,返回断开链条的最低成本,比如上面的例子中,
    需要返回最低成本5
    假设:
    N是整数,范围[5,100000]
    A的元素是范围在[1,1000000000]的整数2. 编程: M个最大的数
    编程实现从N个无序数中选取M个最大的数( 0 < M < N )

  2. 编程: M个最大的数
    编程实现从N个无序数中选取M个最大的数( 0 < M < N )

  3. 编程: 最大方形
    给定一个元素是布尔型大小为N*M的矩阵A。 大小为L的方形可以放置在A
    中的( X,Y) 处, 如果满足:
    0 < L <= min(N,M)
    0 <= X <= N-L
    0 <= Y <= M-L
    A[X+i][Y+j] = true, 0 <= i < L, 0 <= j < L
    如果L能被放置在( X,Y)以及( X+1,Y)或者( X,Y+1), 我们说它可以被
    从( X,Y) 移动到( X+1,Y)或者( X,Y+1)。
    我们想找出满足以下条件的最大的L:
    L可以被放置在( 0,0)
    它可以被经过一系列的移动, 从( 0,0)到达( N-L,M-L)
    换句话说,我们想找到最大的方形,可以从左上移动到右下, 移动方式
    是向下或者向右移动。 一个极端情况是如果矩阵A中的元素全部是true,那
    么L = min(N,M)。
    写一个函数: int move_square(int **A, int N, int M);
    返回值为L。比如:
    A[0][0]=true A[0][1]=true A[0][2]=true A[0][3]=false
    A[1][0]=true A[1][1]=true A[1][2]=true A[1][3]=false
    A[2][0]=true A[2][1]=true A[2][2]=true A[2][3]=false
    A[3][0]=true A[3][1]=true A[3][2]=true A[3][3]=true
    A[4][0]=false A[4][1]=true A[4][2]=true A[4][3]=true
    A[5][0]=true A[5][1]=false A[5][2]=true A[5][3]=true
    返回 2
    A[0][0]=true A[0][1]=true A[0][2]=false A[0][3]=false
    A[1][0]=true A[1][1]=false A[1][2]=false A[1][3]=false
    A[2][0]=false A[2][1]=true A[2][2]=false A[2][3]=true
    返回 0
    A[0][0]=true
    返回 1
    假设:
    N和M是范围为[1,200]的整数

  4. 编程:顺时针环绕列印矩阵元素
    给定一个整数元素组成的矩阵,写一个函数,返回一个数组,数组中的元
    素是按照顺时针遍历矩阵中的元素而组成。例如如下的3×4矩阵:
    2, 3, 4, 8
    5, 7, 9, 12
    1, 0, 6, 10
    得到的数组的元素按照顺序是“2, 3, 4, 8, 12, 10, 6, 0, 1, 5, 7, 9”.

  5. 问答题
    假设你英姿飒爽的站在120层摩天大楼的天台,手握两个iphone(就是这
    么豪!),并且可轻易到达任一楼层的阳台。请用最少的尝试次数, 确定能
    够让iphone自由下落而不会摔坏的最高层数。比如20层摔不坏, 21层就摔
    坏了。在尝试中你可以摔坏这两个iphone,只要能得到答案。请说明最坏
    情况需要多少次尝试以及你的思路。

C#的前世今生

目录 技术

前言

原文来自msdn,总结的非常好,so,翻译+部分补充注解了一下。。

你知道C#的前世是什么样的吗?你又知道它在这些年的衍变进化是怎样的吗?

C# version 1.0

回首看去,你会发现C# 1.0与java是非常相似的。作为ECMA规定的一部分,它试图成为一门“简单、现代化、面向对象的一门语言”。在那个时候,与java相似,意味着它已经达到了早期目标。

不过从现在的角度来看,1.0的语法是有点傻的。它既缺乏对异步操作的支持,也没有泛型,至于LINQ?更是几年以后的事情了。

对比现在来说,1.0是几乎没有什么特性的,以至于在当时不得不写很多累赘的代码。它给我们多了一个选择,在windows上我们可以用它来替代Java。

C# version 2.0

C# 2.0是在2005年随着 Visual Studio 2005一起发布的,从这个版本开始,它才开始变得更有意思。让我们来看看 2.0的主要特性:

C# 2.0的改变非常迅速,也非常重大,实实在在的解决了开发者实际中碰到到的很多问题。

通过泛型,你可以自由给数据指定任意类型,并且编译器层次就保证了数据安全和一致性。比方说,你使用List或List的时候,它就保证了你遍历出来的数据一定是string或int。这比定义一个新类型ListInt或者从Object类型转换要好的多。毕竟定义新类型太麻烦,而从object转化又会导致性能损失。

C# 2.0还引入了迭代器。简单来说,你可以通过foreach来遍历一个List(或者其他实现了IEnumerable的可枚举类型)。这个特性极大的提高了代码的可读性和可理解性。

不过,到目前为止仍然还只是在追赶java而已。泛型和迭代器在Java中已经被实现了。但是随着C#的不断进化,这种情况很快就改善了。

C# version 3.0

C# 3.0是在2007年随着Visual Studio 2008一起发布的,不过语言特性实际上大多是在C# 3.5中发布的。这个版本带来了非常大的提升,把C#变成了一门真正强大的语言。让我们来看看这个版本的主要特性:

回想起来,这里的许多特性都是必然而且无法分割的。他们在战略上来说都是结合在一起的。一般都认为这个版本的杀手级特性是查询表达式,也称之为语言集成查询(Language-Integrated Query:LINQ)。

另一角度来说,表达式树、拉姆达表达式和匿名类都是构建LINQ的基石。不管从哪个角度来说,C#3.0都是提供了一个革命性的概念。C#3.0已经开始为将C#转变成为混合面向对象/函数语言打下了基础。

具体来说,你现在可以像写sql那样来查询、操作集合了。可以直接用list.Average()来求和,而不用自己手动循环遍历数组来求和了。

这个概念需要时间来真正掌握,基于linq我们能写出能更简洁、实用的代码。

C# version 4.0

3.0开始,C#已经从Java的阴影中走出并凸显出来,这门语言正在迅速变得更优雅。

4.0版本主要新增了以下特性:

  • dynamic 动态绑定
  • 命名/可空参数
  • 泛型的协变/逆变
  • 嵌入组件交互类型
    > 开发com组件和vsx扩展程序时,一般都需要引入其他的PIA(Primary Interop Assemblies),这个选项指示是否把引用的PIA打包到项目dll中(也就是是否打包依赖)。在开发vsx之类的扩展程序时设置为false,因为vsx的依赖PIA在操作系统中都会是内置的。(好吧,COM组件已经是过去时了,个人感觉这个特性没啥意义了)

嵌入组件交互类型减轻了部署的痛苦。泛型的协变/逆变让泛型变得更强大,不过这个特性可能主要是被框架、类库作者所使用。命名和可空参数可以免去许多方法重载,写起来更遍历。但这些都不是主要的特性。

主要的特性是新增的dynamic关键字。通过dynamic可以像javascript那样创建动态结构。比如你可以创建一个 dynamic x=”a string”,然后给他加上6,runtime会自动判定类型并计算结果。

dynamic可能会导致潜在的错误,但也让你拥有更大的自由度和能力了。

C# version 5.0

5.0也同样有着巨大的改变,几乎每一个都是开创性的。以下为主要新增特性:

调用者属性让你可以非常容易地得知调用当前方法的上下文,比如调用当前方法的方法名是什么、在哪个文件、第几行等等。这个在日志和诊断中非常有用。

不过async和await才是这个版本的真正明星。这个特性是在2012年出来的,从此异步操作也成为了C#的一等公民。如果你曾经处理过长耗时任务和网络回调的实现,相信你会喜欢上这个特性的。

C# version 6.0

通过3.0和5.0的两次更新,C#作为一门面向对象语言,已经提供了非常亮眼的特性。在6.0中,没有发布开创性的语言特性,而是改为完善语法糖,让C#用起来更为简洁、舒服。以下是主要特性:

这个版本中新增的每个特性都很有意思。从整体上来看,这些特性使得C#写起来更为简洁、可读性更高,这是一个巨大的进步。

对了,他们还发布了一个用C#写的编译器,名字为Roslyn,传统的编译器你是无法得知编译过程中的数据,但它允许你访问。

C# version 7.0

C#最近的一个版本为7.0.这个版本在6.0的基础上进化出了一部分有趣的特性。以下为主要特性:

  • out变量
    以前调用参数为out,必须先定义再传入,而现在不用了
  • Tuple和解构
    var (name, value) = tuple;
  • 匹配模式
    多了is操作符,switch可以自动转化:case int val, case MyType myType
  • 本地函数
    方法内部定义方法:int LocalMethod(){return 1;}
  • 进一步扩展的拉姆达方法
    方法析构没有尝试出来,不知道是怎么回事
  • 引用返回方法
    public ref int TestMethod(object o){ return ref o; }; var data = ref TestMethod(paramO); ref定义,ref返回,ref前缀调用,缺一不可

这些特性都都为开发者提供了很酷的新功能,基于这些特性我们能写出更干净整洁的代码了。其中一个最大的两点是out变量可以不用预先定义了,并且能通过tuple返回多个值。

C#正在被广泛使用,而且现在的.net core目标是任何操作系统,非常关注云和可移植性。在提出新功能之外,这些关注点肯定也会占据语言设计师大量想法和时间的。

使用docker搭建ngrok服务器

目录 技术

前言

前面有一篇文章已经写了如何搭建frp:使用docker搭建frp服务器,但对于ngrok这个用的最久的转发工具也忍不住想搭个试试,所以也就有了这篇文章。

准备工作

  • ngrok客户端、服务端

    我没有自己编译,直接用的sunny编译好的ngrok客户端,已经全部放到了这里:github地址

  • 具有外网ip的服务器

  • 域名

    我这里用的是*.tunnel.thyiad.top,需要把这个域名解析到服务器上,具体的子域名在客户端配置,服务端配置前缀域名为tunnel.thyiad.top

  • docker

    需要注意的是,我这里是基于ngin-proxy镜像来解析域名的,此处不再赘述,可参照之前的文章:使用docker搭建wordpress

docker file

镜像已经上传到docker的hub上了,所以你也可以跳过docker file直接使用compose

创建工作目录与之前frp类似,dockerfile在这里就更简单了:

FROM ubuntu
MAINTAINER Thyiad <1520583107@qq.com>

COPY conf/ngrokd /ngrokd

RUN chmod +x /ngrokd

ENTRYPOINT /ngrokd --domain="tunnel.thyiad.top"

其实就是直接把conf下面的ngrok服务端复制过来,然后运行起来

docker compose

创建工作目录与之前frp类似,compose文件为以下内容:

version: '3'

services:
  ngrok:
    image: thyiad/my-ngrok:latest
    container_name: my-ngrok
    ports:
      - "4443:4443"
    expose:
      - 80
      - 443
    restart: always
    environment:
      VIRTUAL_HOST: '*.tunnel.thyiad.top,tunnel.thyiad.top'

networks:
  default:
    external:
      name: nginx-proxy

运行我们的compose:

docker-compose up -d

此时,我们的ngrok服务器就已经OK了。

ngrok客户端

服务端搭好之后,我们就可以使用客户端来进行使用了,解压对应的平台客户端,执行命令进行隧道连通。我这里是windows x64,执行以下命令:

ngrok.exe -server_addr=tunnel.thyiad.top:4443 -subdomain=test -proto=http 52485

敲完回车后会出现以下界面:

我们来访问test.tunnel.thyiad.top试试:

OK,现在就已经大功告成了!

以上文件已经上传到github:
https://github.com/Thyiad/docker

使用docker搭建frp服务器

目录 技术

前言

  • 把本地的开发环境映射到外网,这是我们经常会碰到的一个要求,比方说展示给别人看啦,临时测试啦。尤其在微信开发中,因为微信必须要求80端口,所以不转发的情况下,我们只能把代码部署到服务器之后才能验证测试,非常麻烦。
  • 最早的时候是花生壳,不过这家公司贼恶心。。后面开始用ngrok,然后现在又有了frp,相比来说frp的配置要更简单一点。
  • 因为没有找到合适的docker镜像,所以在参考很多之后,就有了如下自写的image及compose

准备工作

  • 具有外网ip的服务器
  • 域名

    我这里是准备了一个子域名,*.frp.thyiad.top,把这这个域名解析到服务器,这样可以支持同时映射多个域名到外网,具体的子域名在frp客户端配置,服务端配置前缀域名为frp.thyiad.top

  • docker

    需要注意的是,我这里是基于ngin-proxy镜像来解析域名的,此处不再赘述,可参照之前的文章:使用docker搭建wordpress

docker file

镜像已经上传到docker的hub上了,所以你也可以跳过docker file直接使用compose

创建工作目录:

cd /usr
mkdir frp && cd frp
mkdir frp_image && cd frp_image

先创建一个frp的默认配置文件:

mkdir conf && vim conf/frps.ini

把以下内容填入 frps.ini:

[common]
bind_addr = 0.0.0.0
bind_port = 7000
kcp_bind_port = 7000
vhost_http_port = 80
vhost_https_port = 443
dashboard_addr = 0.0.0.0
dashboard_port = 7500
dashboard_user = admin
dashboard_pwd = admin
authentication_timeout = 0
subdomain_host = frp.thyiad.top

创建dockerfile:

vim dockerfile

把以下内容填入dockerfile:

FROM ubuntu
MAINTAINER thyiad <1520583107@qq.com>

ARG FRP_VERSION=0.16.0

RUN apt update \
    && apt install -y wget

WORKDIR /tmp
RUN set -x \
    && wget https://github.com/fatedier/frp/releases/download/v${FRP_VERSION}/frp_${FRP_VERSION}_linux_amd64.tar.gz \
    && tar -zxf frp_${FRP_VERSION}_linux_amd64.tar.gz \
    && mv frp_${FRP_VERSION}_linux_amd64 /var/frp \
    && mkdir -p /var/frp/conf \
    && apt remove -y wget \
    && apt autoremove -y \
    && rm -rf /var/lib/apt/lists/*

COPY conf/frps.ini /var/frp/conf/frps.ini

VOLUME /var/frp/conf    # conf被配置成了卷,方便以后修改frps.ini

WORKDIR /var/frp
ENTRYPOINT ./frps -c ./conf/frps.ini

这个dockerfile执行了以下操作:
– 从github上下载frp的release版本
– 解压
– 从conf目录中读取替换默认的frps.ini

此时就可以使用docker build命令进行编译镜像了,命令为:

docker build -t="thyiad/my-frp" .

docker compose

在镜像编译好后,我们就可以开始compose文件了,毕竟compose比直接docker run要方便的多

创建工作目录:

mkdir /usr/frp/frp_compose && cd /usr/frp/frp_compose
vim docker-compose.yml

把以下内容填入docker-compose.yml:

version: '3'

services:
  frp:
    image: thyiad/my-frp:latest
    container_name: my-frp
    ports:
      - "7000:7000"
      - "7500:7500"
    expose:
      - 80
      - 443
    volumes:
      - frp_conf:/var/frp/conf
    restart: always
    environment:
      VIRTUAL_HOST: '*.frp.thyiad.top,frp.thyiad.top'   # 指定需要绑定的域名

volumes:
    frp_conf:

networks:
  default:
    external:
      name: nginx-proxy # 此处的nginx-proxy为之前创建的docker network

运行我们的compose:

docker-compose up -d

此时,我们的frp服务器就已经OK了。
我们访问一下test.frp.thyiad.top试试:

显然,frp已经在运转了,只是该域名并没有绑定转发

frp客户端

服务端搭好之后,我们就可以下载客户端进行使用了。需要前往frp的github上下载对应的版本,我这里是16.0,windows x64。

下载解压后,我们修改frpc.ini为以下内容:

[common]
server_addr = 你的服务器ip
server_port = 7000
# protocol = kcp

[web]
type = http
local_port = 52485
subdomain = test

然后打开cmd,运行frpc:

cd /d d:\frp
frpc

此时会出现以下界面:

说明已经连接成功了,我们再来访问test.frp.thyiad.top试试:

此时,我们的frp就已经搭建好了,很简单吧?

ngrok的服务器搭建在这里:
使用docker搭建ngrok服务器

以上文件已经上传到github:
https://github.com/Thyiad/docker

使用docker搭建ss服务器

目录 技术

前言

shadowsocks是一个开源的vpn工具,客户端囊括PC、android、ios各大主流平台,你既可以去买别人的ss服务器,也可以自己搭建一个。我们既然有docker了,那自然是优先使用别人写好成熟的镜像啦。

此处不详细介绍ss的客户端使用,请自行查阅文档

oddrationale/docker-shadowsocks

oddrationale/docker-shadowsocks是我找到的第一个镜像,使用方法也很简单:

docker run --restart=always --name=myshadowsocks -d -p 12345:12345 oddrationale/docker-shadowsocks -s 0.0.0.0 -p 12345 -k 111111 -m aes-256-cfb
  • -p 指定端口,记得要在服务器的安全配置中开启该端口的访问权限
  • -k 指定密码
  • -m 指定加密方式

mritd/shadowsocks

mritd/shadowsocks是我找到的第二个镜像,使用方法如下:

docker run -dt --name ss -p 6443:6443 mritd/shadowsocks -s "-s 0.0.0.0 -p 6443 -m aes-256-cfb -k test123 --fast-open"

17年下半年有段时间封锁特别严格,vpn服务器基本被屏蔽了,连购买的ss服务器也不能幸免。后来购买的ss服务器可用时,已经切换了加密方式,改为chacha20-ietf-poly1305。而上面的目测是不支持该加密方式的(我也不确定),为了以防万一,就找到了这个镜像。
这个镜像的更新非常频繁,从更新日志中可以看出来,每次ss有更新,他这边马上也更新了,几乎是同步的。而且这个镜像还集成了kcptun(一个用来加速ss的工具,我也没用过),有兴趣的可以试试。

参考链接:
oddrationale/docker-shadowsocks
mritd/shadowsocks

使用docker搭建wordpress

目录 技术

前言

去年在学习docker,在看完菜鸟教程和第一本docker书后,一直想实战用一下这个技术,多用用才能熟能生巧,真正体验它的利弊。正好傅老板用docker搭完了wordpress,我也就手痒跟着搭建了一下(也就是现在的这个博客网站)。
此处记录一下搭建过程。

搭建环境

  • 阿里云ECS

    去年双11买的,720/3年,1核1G1M香港服务器,centos 7.4
    有个小插曲,阿里云的工作人员还给我打电话,问我用的怎么样。。阿里云什么时候有这种回访了。。。

  • 域名

    阿里云购买即可,像我申请的 .top 域名更是便宜,丧心病狂只要2块钱。。

  • ssl证书

    https用的证书,我是在腾讯云免费申请的,地址为:腾讯云证书管理,此处就不详细描述申请过程了,很简单的

  • Docker

    这里要注意,centos中不要直接使用yum install docker,yum中的是旧的docker版本,升级参考我的这篇博文:CentOS更新Docker至最新版本

  • Docker Compose

    compose原本是一个第三方公司写的,用来在docker中定义和运行复杂应用的小工具,后来被docker收购了,正式用来替代最早的fig。
    通过以下命令安装:

    # 下载compose
      curl -L https://github.com/docker/compose/releases/download/1.18.0/docker-compose-`uname > -s`-`uname -m` -o /usr/bin/docker-compose
      
      # 赋予可执行权限,确保compose可执行
      chmod +x /usr/bin/docker-compose
      

添加一个docker network

网站需要占据80端口,显然,我们的服务器不可能只有一个网站,所以部署一个nginx容器是必须的,让这个nginx来监听80以及443端口,再根据域名转发到对应的网站容器。容器之间的通信是通过network的,所以我们需要先添加一个network:

 docker network create nginx-proxy

compose部署WordPress和MySql容器

  • 创建工作目录,创建docker-compose.yml文件:
cd /usr
mkdir myblog && cd myblog
vim docker-compose.yml
  • docker-compose.yml输入以下内容:
version: '3'
services:
   db:
     image: mysql:5.7
     volumes:
       - db_data:/var/lib/mysql
     restart: always
     environment:
       MYSQL_ROOT_PASSWORD: your-mysql-root-password    # 在这里输入你要设置的mysql密码
       MYSQL_DATABASE: wordpress
       MYSQL_USER: wordpress
       MYSQL_PASSWORD: wordpress
   wordpress:
     depends_on:
       - db
     image: wordpress:latest
     volumes:
        - wp_site:/var/www/html     # 定义卷后,compose down之类的操作不会导致你的文章等数据丢失
     expose:
       - 80
     restart: always
     environment:
       VIRTUAL_HOST: www.thyiad.top,thyiad.top
       WORDPRESS_DB_HOST: db:3306
       WORDPRESS_DB_USER: wordpress
       WORDPRESS_DB_PASSWORD: wordpress
   nginx-proxy:
     image: jwilder/nginx-proxy
     container_name: nginx-proxy
     restart: always
     ports:
       - "80:80"
       - "443:443"
     volumes:
       - /var/run/docker.sock:/tmp/docker.sock:ro   # docker.sock是docker守护进程默认监听的Unix域套接字,容器进程通过它与守护进程进行通信。以后添加新的站点时,nginx将会自动发现并重启服务
       - nginx_certs:/etc/nginx/certs:ro    # nginx的证书目录,:ro指定为只读
volumes:
    db_data:
    wp_site:
    nginx_certs:
networks:
   default:
     external:
       name: nginx-proxy

添加ssl证书

# 列出所有的卷信息,查找到xxx_wp_certs(xxx是docker自动添加的)
docker volume ls

# 查询出xxx_wp_certs的真实路径,一般是在 /var/lib/docker/volumes/xxx_wp_certs/_data
docker volume inspect --format '{{ .Mountpoint }}' xxx_wp_certs

# 创建www.thyiad.top.key,并且把ssl证书的xxx.key内容复制粘贴进来
cd /var/lib/docker/volumes/xxx_wp_certs/_data && sudo vim www.thyiad.top.key

# 创建www.thyiad.top.crt,并且把ssl证书的xxx.crt内容复制粘贴进来
cd /var/lib/docker/volumes/xxx_wp_certs/_data && sudo vim www.thyiad.top.crt

nginx-proxy如果发现在certs文件夹中存在当前域名的.crt和.key文件,将自动转为https协议

运行wordpress

docker-compose up -d

此时,我们的网站就可以访问了,很简单吧?

参考资料:
傅老板的博客
docker-compose
nginx-proxy

PV IP UV

目录 技术

PV(访问量)

  • Page View,页面浏览量。
  • 具体的说,就是在一天内,该网站的页面总共访问了多少次

IP(独立IP)

  • 一天内访问网站的IP数量

UV(独立访客)

  • Unique Visitor
  • 一般是通过cookie来确认,就算使用不同账号登陆网站,都只算一个UV

一般的设计标准

  • 小型:日均PV 10W,IP/UV 1.5W;每秒PV 1,峰值5。
  • 中型:日均PV 100W,IP/UV 25W;每秒PV 10,峰值50。
  • 大型:日均PV 1000W,IP/UV 250W;每秒PV 100,峰值500。
  • 超大型:日均PV 10000W,IP/UV 3000W;每秒PV 1157,峰值5000