开坑了 & 搭建实况

趁着2015年年经的狗血还未消散,终于捣腾了一件去年就下定决心要完成、前年已计划开始而前前年就规划好的事儿——个人站点。偶总是不赶热潮,在这个写Blog已成坚持的年代,只希望偶这个坑不要太坑爹就是了……

第一篇总是想写些有逼格的,来点激励的,不能荒废了这大好的2015开篇呀!不过看着从大前年顺利延续至今的新年计划…… 那啥,我们还是来聊些轻松的吧…(>_<)…来说说这个站点的搭建全过程吧~

资源准备

做任何事儿都得有资源,对搭建个人站点而言有两个必不可少的东西:域名与空间。

域名服务提供商满大街都是,随便找找就成。推荐name.com,简单、方便、快捷,拿下一个中意的域名分分钟的事儿。目前.me的域名比较便宜的说。

空间选择就更多了,可以是各种云平台,也可以选择VPSGitHubPages是个不错的选择,而本小站使用的是由digitalocean提供的VPS,毕竟VPS可玩性要高很多。关于VPS的购买也有很多选择,google一大堆,这儿再广告下下,推荐digitalocean,理由同样是简单、方便,线路上国内访问选择新加坡机房速度最优,ping基本在100ms左右(北京地区测试),另外从这个链接注册可以优惠10刀的说~

框架选择

其实主要是书写方式、运营管理方式的选择。Blog系统有很多,老牌的WordPress,也有新宠ghost。这些都是完整的系统,有各种完备的功能(访问监控、多人协作等等),上手简单,不想折腾的可以好好选择下。

本站没有直接使用常见的Blog系统,而是本着折腾的目的,基于以下考虑选择了DIY的方式:

最先选定的是Hexo,由它来将markdown的文章转化为可访问的静态页面。然后是Web服务器,Apachelighttpdnginx都好,由于之前没有玩过ngnix,这次就选它了。关于文章的存放最早想到的是直接托管到GitHub上,至于自动部署可以使用GitHub的Webhooks来通知我们自己的Web服务器文章有更新,然后服务器再抓去最新的代码进行部署。在完成对WebHook的调试后突然想到何必这么麻烦呢,在VPS上直接建立Git代码仓库不是更直接、简单莫?

所有最终的选型方案是在VPS上搭建私有Git仓库存储文章,使用Hexomarkdown文章生成静态页面,最终由nginx提供Web访问服务。至于自动部署由GitHooks来完成,直接几句简单的shell脚本搞定,比搞Webhooks简单太多。

实施部署

由于在VPS配置的时候偷懒选择了最熟悉的Ubuntu操作系统,安装之前提到的相关软件就非常方便了,直接apt-get包管理就搞定了。

Nginx

1
$ apt-get install ngnix

安装完成后进行相关配置,配置文件在/etc/nginx目录下,核心配置文件是nginx.conf,其中需要注意的是第一行:

1
2
3
user www-data;
worker_processes 4;
...

它表示nginx实际的工作进程(worker)工作在哪个用户下。出于安全的考虑,最好不要使用root用户运行工作进程,默认使用的是www-data这个用户,也可以改成其它任意用户。由于后续我们还会涉及到静态页面的生成等工作,因此新建了一个work用户来完成日常的操作(如果不涉及软件安装等需要较高权限的操作,日常尽量都不要使用root账号,能减少误操作的悲剧也能提升系统安全性),所以将这里的user改为work

nginx.cong中还需要关注的一个地方是gzip_types,可以考虑开启此项配置来限定gzip的适用范围,降低对cpu的消耗。我们站点目前还只是静态服务,所以除了开启gzip外,对静态文件的缓存设置也很重要(提升网站访问速度的两大利器焉),不过限于刚刚开始,各种资源都还不稳定,提早设置缓存反而不利于开发、调试,那缓存问题就后续再表~

nginx.conf只是对nginx的全局设置,具体虚拟站点的设置实际是在/etc/nginx/sites-available目录下的配置文件中,推荐一个虚拟站点一个配置文件方便管理。但实际查看主配置文件nginx.conf会发现其中并没有对sites-available目录下各配置文件的引用,倒是有加载/etc/nginx/sites-enabled下的配置文件。第一眼看到这里的时候很纳闷为啥需要有两个目录来保存虚拟站点的设置,而且实际只使用其中的一个文件夹?在看过sites-enabled文件下的实际内容后才恍然大悟:sites-enabled下的配置文件都是对映sites-available目录下各配置文件的软链接。这样做能通过简单的删除、添加sites-enabled下的软链接来快速实现虚拟站点的增减而且又不必担心配置文件的丢失,好点赞~

至于虚拟站点的配置就比较简单了,设置好端口、站点域名、访问日志地址及其路径映射就好了,比如这样:

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
server_name treelite.me;

access_log /var/log/ngix/treelite.me/access.log;

location / {
root /somewhere;
index index.html;
}
}

其中server_name是指实际站点的域名,nginx是会检查HTTP请求头中的Host的,如果不匹配是不让访问的。更进一步还会可以让多个虚拟站点同时都监听80端口再通过server_name来区分不同请求,这样就能使同一台服务器在80端口上同时为多个不同域名的站点提供服务。推荐读读这篇官方的Nginx如何处理一个请求

配置完成后就可以使用/etc/init.d/nginx start启动服务器,当然了,还有stoprestart等指令

Git

1
$ apt-get install git

如果只是普通使用Git的话,到此就搞定了,不过我们的目的是搭建私有的Git仓库,所以还需要让Git作为一个服务器来运行,继续配置~

添加git专用用户

1
$ adduser git

后续所有对本仓库的远程访问都会由此用户来完成,名字随意啦(顶多影响访问地址…)。关键是要让这用户成为Git的专用,不能进行其它操作(当然是出于安全考虑啦),所以需要取消该用户的shell登陆,修改/etc/passwd文件,将该用户的默认shell改成/usr/bin/git-shell

1
git:x:1000:1000:git,,,:/home/git:/usr/bin/git-shell

建立仓库

在恰当的目录(取名字太要命… By the way 服务器端上的仓库基本都是以.git结尾的…)下执行以下命令初始化服务器端仓库

1
$ git init --bare

假如仓库在/home/git/blog.git目录下,那就可以使用git clone git@xxx.xx:/home/git/blog.git来克隆代码了~

RSA验证

每次远程Git操作还要输入密码好烦哟… 改用RSA验证吧,密码神马的滚粗。至于原理嘛就是将客户端的RSA公钥保存在服务器端,登陆的时候服务器端生成一个随机数并使用客户端的公钥加密后传输给客户端,之后客户端使用自己的私钥解密随机数再将得到的原始数据传回服务器端,最后服务器端通过验证随机数的正确性来判断是否是有效的身份登陆。

先在客户端上使用$ ssh-keygen来生成密钥与公钥,然后将~/.ssh/id_rsa.pub文件中的公钥拷贝到服务器/home/git/.ssh/authorized_keys文件中,搞定~

Hexo

这货是用node写的,所以安装之前还需要先搞定node

1
$ apt-get install nodejs

Ubuntu的包仓库中已经有一个叫node的模块了,所以在该平台下node的包名就改成了nodejs,而且安装后可执行文件也叫nodejs而非常用的node,所以图顺手还是在安装完后在/usr/bin/目录下建立一个node的软链接方便

1
$ ln -s /usr/bin/nodejs /usr/bin/node

node的包管理工具npm并没有初始安装,所以继续装npm

1
$ apt-get install npm

搞定后就可以安装hexo

1
$ npm install -g hexo

hexo有很多、很多的样式主题可供选择,本站点的theme也在一步一步开发中

自动部署

期待的自动部署方式是在往代码仓库提交时就能自动更新页面。这个就需要Git Hooks帮忙了,在仓库目录的hooks目录下有各种不同命名的hook,各自运行在不同阶段。我们需要的是post-receive,表示接受到客户端的提交(push)后执行。所以只需要在post-receive中执行git pull拉取最新的代码,然后执行hexo generate更新页面就好啦:

1
2
3
4
5
cd /somewhere/public
git pull

cd /somewhere
hexo generate

看上去好简单的哇,but, but, but …

首先会出现权限问题,because Git Hooks执行的用户是git,而静态页面是所属其它用户(比如work)的。最粗暴的解决方式是将虚拟站点的目录权限修改为所有人都可写chmod a+w /somewhere。不过作为一个有操守的猿类对此等low行为还是要坚决反对滴,所以呢相对安全的方式是将git用户加入到work所在的用户组中,让git有权操作work的数据:usermod -a -G work git

然后还会遇到一个问题:Not a git repositorygit pull执行失败了。先有cd /somewhere进入相应目录,然后执行git pull,怎么看都没有错呀?百思不得其解,google之,原来是Git Hook执行时的环境有所不同,此时WORK_TREEGIT_DIR都已经有预设了,即使进入了某某目录也没用,所以需要使用git --git-dri=/somewhere/.git --work-tree=/somewhere pull的方式来重置GIT_DIRWORK_TREE为正确的路径

总结

至此,一个基于markdown的自动化文章发布系统就算是搭建完成了,拿来做个人站点那还是极好滴~