起因是这样的,我喜欢用md文档记录一些零散知识,久而久之,太多内容层级结构太深不便于查询,于是就在想是否能将这些md文档转换成网页随时查看,这种站点我叫它个人维基(personal wiki)
我的md文档是托管在github上的,我们要做的是将md文档自动转换html文档并能通过浏览器访问,以后,只要有游览器的地方我就能随时查阅这些内容。首先看看效果:http://1024.services/wiki/
以后,只需要撰写md文档,然后往github提交就会自动生成静态站点(这里用到了hexo)
准备工作:
- 联网的电脑
- github账号
- md文档仓库,可以是私有仓库,毕竟有些内容不便于公开,下文称notepad
- wiki站点仓库,需要设置gitpages,gitpages能用过域名访问仓库中的html网页,相当于静态网站托管,下文称wiki
- 一台VPS(当然,如果用于手工部署,然后托管到wiki上是不需要VPS的)
快速开始
我将其中复杂的命令封装成了docker镜像,只需执行下列命令即可(把notepad中的md文档同步更新到wiki站点),注意每一行的含义,需要你自行更改
docker run -dit \ -p 8081:8080 \ -v ~/wiki/:/root/DREP \ -e OREP=https://github.com/scriptwang/notepad.git \ -e OB=master \ -e DREP=https://github.com/scriptwang/wiki.git \ -e DB=master \ -e URN=xxx%40gmail.com \ -e PASSD=xxxpwd \ -e SECRET=xxxsecret \ --name hexowikihook \ kimoqi/hexowikihook
命令解释:
-v ~/wiki/:/root/DREP => 在宿主机中挂载hexo博客生成的静态文件的仓库目录,生成的文件是html静态文件,通过nginx指向这个目录即可访问,不需要数据库,更多玩法自己可以挖掘 -e OREP=https://github.com/scriptwang/notepad.git => 原仓库,非hexo博客,md文档就可以,有目录层级的也可以 -e OB=master => 原仓库分支 -e DREP=https://github.com/scriptwang/wiki.git => 生成静态文件的仓库 -e DB=master => 生成静态文件仓库的分支,主干就写master -e URN=xxx%40gmail.com => github用户名,如果用户名中含有@,需要转义成%40,用于提交认证 -e PASSD=xxx => github密码 -e SECRET=xxxxxx =>github webhook的密码,用于比较签名是否一致
执行完命令后:
要在notepad仓库的settings页面找到webhooks,然后点击add webhooks,Payload URL填写http:yourip:8081,Content type选择application/json,Secret和-e SECRET=xxxxxx中xxxxxx保持一致,然后点击下面绿色Add webhook,此时github会向你的api(http:yourip:8081)发送一个ping请求。
小技巧:
如果你不希望一些md文档被公开,你可以改后缀名为非md,可以是大写的MD或者其他任意后缀名,这样Hexo就不会将该文件转换为网页文件,别人也不会访问到
Hexo
将md文档转换成html网页并且有丰富的主题可以选择,这一切都依赖于Hexo引擎,他是基于Node.js的博客引擎,它是一个转换程序,常用命令有
# 安装hexo,安装之前要安装nodejs和npm npm i -g hexo # 初始化Hexo hexo init # 本地预览,默认端口4000 hexo s # 清除文件 hexo clean # 生成html静态文件 hexo g # 发布博客 hexo d
技术细节
- 详情可见:https://cloud.docker.com/u/kimoqi/repository/docker/kimoqi/hexowikihook
Dockerfile
FROM alpine:latest # Set environment variables. ENV \ OREP="https://github.com/scriptwang/notepad.git"\ OB="master"\ DREP="https://github.com/scriptwang/wiki.git"\ DB="master"\ URN="xxx%40gmail.com"\ PASSD="xxx"\ PORT=8080\ SECRET="xxx" # Install packages. RUN \ apk add --no-cache --update\ nodejs\ nodejs-npm\ git\ && git config --global user.email "auto hook"\ && git config --global user.name "auto hook"\ && touch /root/.git-credentials\ && echo "https://$URN:$PASSD@github.com" > /root/.git-credentials\ && git config --global credential.helper store\ && npm i -g hexo # wiki包含了hexo博客文件和wiki主题,只需要将md文件放到../source/_posts目录即可自动生成静态html文件 COPY wiki/ /root/wiki/ COPY hook.js /root/hook.js # Set the default command. CMD cd /root/wiki/source/ \ && git clone -b ${OB} ${OREP} _posts \ && cd /root \ && git clone -b ${DB} ${DREP} DREP \ && PORT=${PORT} DB=${DB} SECRET=${SECRET} node /root/hook.js
- /root/.git-credentials可用于github认证,不用输入密码也可以提交,新安装一个git,然后按照下面命令执行和上面的效果是一样的
# 指定email和name,如果已经有了则不用指定 git config --global user.email "auto hook" git config --global user.name "auto hook" # 在root目录生成认证文件 touch /root/.git-credentials # 往认证文件里面写入内容,如果github用户名是邮箱,需要将@转义成%40 # 比如,用户名为1234@gmail.com 密码为1234,则命令为 # echo "https://1234%40gmail.com:1234@github.com" > ~/.git-credentials echo "https://$github用户名:$github密码@github.com" > ~/.git-credentials # 显示指定存储认证文件 git config --global credential.helper store
- COPY指令拷贝目录的时候,源目录和目标目录都要在最后加上/
- COPY指令拷贝文件的时候,目标位置要将文件名也写上
- CMD 指令可以执行多条命令
- PORT=${PORT} DB=${DB} SECRET=${SECRET} node /root/hook.js表示给通过命令行给hook.js传参
- 其中wiki目录下的内容可以通过git clone -b hexo https://github.com/scriptwang/demoHexo.git得到,其实就是一个包含了wiki主题的hexo博客
hook.js
不得不说node.js天生异步,特别适合做执行复杂shell命令这种耗时操作,立即就能给github返回而不会超时,要知道,github的webhook超时是15s,15s之内要完成更新源文件,创建html并提交这些操作是不可能的,期间还要等网络IO
const http = require('http'); const crypto = require('crypto'); const exec = require('child_process').exec; //从命令行读取的参数 const port = process.env.PORT || 8080; const DB = process.env.DB; const secret = process.env.SECRET; http.createServer(function (req, res) { res.writeHead(200, {'Content-Type': 'text/html'}); req.on('data', function(chunk) { //比对加密是否一样 let sig = "sha1=" + crypto.createHmac('sha1', secret).update(chunk.toString()).digest('hex'); console.log(sig); if (req.headers['x-hub-signature'] == sig) { //先更新notepad仓库,再向wiki仓库提交文件 var cmd = 'cd /root/wiki/source/_posts ' + '&& git reset --hard ' + '&& git pull ' + '&& cd /root/wiki ' + '&& hexo clean ' + '&& hexo g && cd /root/DREP ' + '&& rm -rf `ls | grep -v .git` ' + '&& cp -r /root/wiki/public/* . ' + '&& git add . ' + '&& git commit -m "update" ' + '&& git push origin ' + DB; console.log(cmd); //异步执行shell命令 exec(cmd, function(error, stdout, stderr){ if(error) { console.error('error: ' + error); return; } console.log('stdout: ' + stdout); console.log('stderr: ' + typeof stderr); }); res.write('success!'); } else { console.log("token not match!"); } res.end(); }); }).listen(port);
扩展
其实上面相当于把Hexo博客和wiki主题打包在了一起,notepad只管md文档,不管Hexo博客相关的内容,还有一种更为通用的办法是在notepad仓库放置Hexo博客原文件(包括里面的md文档),这样的好处是比用固定wiki主题,想用什么主题主需要改变Hexo文件即可,这种需求我也打成了docker镜像,详情见:https://cloud.docker.com/repository/docker/kimoqi/hexohook
参考
- https://www.digitalocean.com/community/tutorials/how-to-use-node-js-and-github-webhooks-to-keep-remote-projects-in-sync