博客之前的更新方式是先在本地写好文章,push到Github,然后ssh连到服务器上,再pull下来,如果每次都要这样操作一遍实在麻烦,今天就试着用Github的Webhooks功能实现了Hexo博客的自动部署,过程记录如下。

整个过程主要有两个环节:

本地代码自动部署到Github

Hexo本身就有deploy功能,只要在_config.yml里面做一下配置,就可以部署到Github、Heroku等平台上,如果博客是托管在Github Pages上的话使用这种方式可以很方便的实现自动部署,不过通过这种方式发送到Github上的只有public静态文件目录,我这里希望托管整个应用的代码,就不能使用这种方式了,反正只要可以push就行了,我们搬出shell大法好。

创建文件deploy.sh

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
echo -e "\033[32m [AUTO DEPLOY] deploy hexo start \033[0m"
echo -e "\033[32m [AUTO DEPLOY] hexo generate... \033[0m"
hexo g
echo -e "\033[32m [AUTO DEPLOY] git commit... \033[0m"
d=`date +%x-%T`
git add .
git commit -m "auto deploy at "${d}
echo -e "\033[32m [AUTO DEPLOY] git push... \033[0m"
git push origin master
echo -e "\033[32m [AUTO DEPLOY] deploy hexo finish \033[0m"

然后增加权限

1
$ chmod +x ./deploy.sh

这样完成本地开发后,只要执行命令

1
$ ./deploy.sh

就可以让Hexo生成静态文件并push到Github上。

Github自动同步到服务器

为了让服务器可以自动同步Github上面的更新,我们需要用到Github的Webhooks。

首先创建文件sync.sh

1
2
3
4
5
6
7
#!/bin/bash
echo -e "\033[32m [AUTO SYNC] sync hexo start \033[0m"
cd /ppxu/blog
echo -e "\033[32m [AUTO SYNC] git pull... \033[0m"
git pull origin master
echo -e "\033[32m [AUTO SYNC] sync hexo finish \033[0m"

目标是每当Github有push的时候就自动调用这个脚本。

然后找到Github仓库的Settings页

/img/hook.png

添加一条Webhook,填写请求地址http://xx.xx.xx.xx:7777/webhook,这样每当Github收到push或者其他事件时就会自动向这个地址发送一条POST请求。

下面在服务器上补充这个请求地址,我们用Node搭一个简单的http服务,这里用到了github-webhook-handler处理hook消息,创建文件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
var http = require('http')
var exec = require('child_process').exec;
var createHandler = require('github-webhook-handler')
var handler = createHandler({ path: '/webhook', secret: '********' });
http.createServer(function (req, res) {
handler(req, res, function (err) {
res.statusCode = 404;
res.end('no such location');
});
}).listen(7777);
handler.on('error', function (err) {
console.error('Error:', err.message);
});
handler.on('push', function (event) {
console.log('Received a push event for %s to %s',
event.payload.repository.name,
event.payload.ref);
exec('/ppxu/blog/sync.sh', function(err, stdout, stderr){
if(err) {
console.log('sync server err: ' + stderr);
} else {
console.log(stdout);
}
});
});

这里的secret要和在Github上新建hook时设置的一样,请求时校验用的。

然后启动服务

1
$ node server.js &

这里也可以用forever之类的工具防止进程挂掉。

这样一套自动部署系统就建立好了,在本机和服务器的实际效果如下:

/img/deploy.png

/img/sync.png

感觉生活一下子美好起来了呢:)

参考资料