The major reference for this tutorial is 用Hexo+Vps搭建博客并用Dropbox同步自动发布.
Hexo suits all my needs, it is a great tool. Therefore it is worth all the pain to set up.

After some trial and fail, I finally figured out how to integrate my Digit Ocean CentOS VPS with Dropbox for Hexo to automate the publication process. With the help of this new setup, the Dropbox folder is the only thing I need to focus on. Whatever operation done there will be monitored by my VPS, publications will be automated by the script running on my server!

##Overall logic:

Run Dropbox on my VPS, set up a rule that monitors changes and trigger hexo g command to automatically publish changes to my site.

##What do you need

  • A VPS. I am using Digit Ocean’s 512MB 20GB VPS, which is $5/month.
  • Dropbox account.
  • A domain. I got mine from dot.tk.

##Install Nodejs We want to install Nodejs and have it run as a service from after boot.

To install it, according to my first reference, we need to install epel first. I do not know why we need epel for Nodejs, if you do, please let me know. To check if you have epel installed already:

1
yum repolist | grep epel

If you seee something like the following, it means you have it installed.

1
2
* epel: mirror.prgmr.com
epel             Extra Packages for Enterprise Linux 6 - x86_64           11,022

Otherwise you need to install epel.
Add epel key:

1
sudo rpm --import http://download-i2.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-6

Install the package
For 32bit:

1
sudo rpm -Uvh http://download-i2.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm

For 64bit:

1
sudo rpm -Uvh http://download-i2.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

Also, we need yum priority:

1
yum install yum-priorities

Use yum repolist again to make sure you have epel installed.

Then wen can start installing nodejs.

1
sudo yum install nodejs npm --enablerepo=epel

##Setup Dropbox
We want to have dropbox running on our VPS so that files changed in Dropbox folder will show up on our VPS.

###Create User For safety reasons I chose to create a new user dbox in dbox group to run Dropbox.

1
2
adduser dbox
passwd dbox

###Install Dropbox For 32bit users:

1
cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86" | tar xzf -

For 64bit users:

1
cd ~ && wget -O - "https://www.dropbox.com/download?plat=lnx.x86_64" | tar xzf -

###Verify Installation After installation you will be given a link to verify your installation. You just need to copy and paste the link to a browser and do as instructed.

Then you can kill the dropbox using Ctrl + C, we will choose what folder to synchronize using its official managment script.

###Configure Dropbox Download offcial management script from the Internet.

1
wget https://linux.dropbox.com/packages/dropbox.py

Modify the permission:

1
chmod +x dropbox.py

Select folders to synchronize:

1
./dropbox.py exclude add ~/Dropbox/Apps/ ~/Dropbox/back/ ~/Dropbox/Mycode/ ...

##Start Dropbox Service Here I mainly used this [Ubuntu]Dropbox命令行下安装与维护 as reference. In the post, there is a script for Fedora/CentOS users. The 60th line should be changed from

1
dbpid=<code>pgrep -u $dbuser dropbox</code>

to

1
dbpid=`pgrep -u $dbuser dropbox`

Please pay attention to the backquote(`), it is not single quote(‘). The backquote(`) is the key locates at the left top corner of laptop keyboard, the one next to number key 1; not the one on next to return key.

Save the script as /etc/init.d/dropbox and create file /etc/sysconfig/dropbox.
The latter file should be empty before you add the following line:

1
DROPBOX_USERS="dbox some_other_user"

Change file permission:

1
2
3
chmod 0755 /etc/init.d/dropbox
chmod 0644 /etc/sysconfig/dropbox
ls -l /etc/init.d/dropbox /etc/sysconfig/dropbox

Set SElinux permission:

1
2
3
chcon system_u:system_r:initr:c_exec_t /etc/init.d/dropbox
chcon system_u:object_r:etc_t /etc/sysconfig/dropbox
ls -lZ /etc/init.d/dropbox /etc/sysconfig/dropbox

Add Dropboxo to autostart list:

1
chkconfig dropbox on

Use the following command to check if the service is on:

1
chkconfig --list

Later when you need to do service check, here are some sueful commands:

1
2
3
4
service dropbox start
service dropbox stop
service dropbox restart
service dropbox status

You can check if Dropbox is going to start on boot now. Just reboot your system and run service dropbox status. If your setup is right, you will see somehting like this.

1
dropboxd for USER dbox: running (pid 904)

Let’s move on to installing hexo now.

##Install Hexo
This part is very easy, just follow the official tutorial.

1
2
3
4
5
npm install hexo -g  
hexo init blog  
cd blog  
npm install  
hexo server  

##Publication Automation Here is the underlining logic:
1. VPS runs a server. nginx for instance and set its root as $hexo_root/blog/public 2. Create a system service to monitor a Dropbox folder. _posts for instance. 3. Once some file operation happens in _posts, run hexo g automatically. The command will generate files in $hexo_root/blog/public( which happens to be the same position as the root of nginx server).

##Install nginx My choice is to use the LNMP package. It sets up Nodejs for me as user www in group www.
My default location for nginx configure file is /usr/local/nginx/conf/nginx.conf.
My conf file for nginx is (only the most important part):

 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
server
     {
         listen 80 default;
         #listen [::]:80 default ipv6only=on;
         server_name .goqqy.tk;

         location / {
             index index.html index.htm index.php;
             root /home/dbox/Dropbox/blog/public;
         }

         error_page   500 502 503 504 /50x.html;
         location = /50x.html {
             root /root;
         }

         location ~ [^/]\.php(/|$) {
             # comment try_files $uri =404; to enable pathinfo
             try_files $uri =404;
             fastcgi_pass  unix:/tmp/php-cgi.sock;
             fastcgi_index index.php;
             include fastcgi.conf;
             #include pathinfo.conf;
         }

         location /nginx_status {
             stub_status on;
             access_log   off;
         }

         location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
             root /home/dbox/Dropbox/blog/public;
             expires      30d;
         }

         location ~ .*\.(js|css)?$ {
             root /home/dbox/Dropbox/blog/public;
             expires      12h;
         }

         access_log  /home/wwwlogs/access.log  access;
     }

Setup the Rule

For the nginx server, what really matters is the folder and files in the folder it is monitoring. Therefore, we need to automatically copy files into it.

Linux offers a kernel feature to monitor the files changes, it is called inotify. One can choose to use this feature directly like this post linux下使用inotify实时监控文件变更,做完整性检查, or we can use a command based on that feature. Incond is one of that command.

incond is a service works very much like cron. Cron periodically invokes some command( you get to choose what that command is). incond instead invokes command on file change event. For instance if you create, delete, modify files.

A note for Ubuntu, the hexo comand is by default not installed under /usr/bin, therefore when you run incrond, you will not have hexo command in the search path by default. You need to add something like this in your script PATH="path/to/your/hexo/executable".

Install incrond

1
yum install incrond

start incrond on boot

1
2
service incrond start  
chkconfig incrond on

Now we can consider how to write synchronization rules. For me I need to monitor the Dropbox/hexo folder so the rule will be like this:

1
2
/home/dbox/Dropbox/hexo/source/_posts/ IN_MODIFY,IN_ATTRIB,IN_CREATE,IN_DELETE,IN_MOVE /root/runhexo.bash  
/home/dbox/Dropbox/hexo/themes/ IN_MODIFY,IN_ATTRIB,IN_CREATE,IN_DELETE,IN_MOVE /root/runhexo.bash

Things like IN_MODIFY, IN_ATRRIB, ... are for incrond. Other available flags can be found by man 5 incrontab:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
       IN_ACCESS           File was accessed (read) (*)
       IN_ATTRIB           Metadata changed (permissions, timestamps, extended attributes,
       etc.) (*)
       IN_CLOSE_WRITE      File opened for writing was closed (*)
       IN_CLOSE_NOWRITE    File not opened for writing was closed (*)
       IN_CREATE           File/directory created in watched directory (*)
       IN_DELETE           File/directory deleted from watched directory (*)
       IN_DELETE_SELF           Watched file/directory was itself deleted
       IN_MODIFY           File was modified (*)
       IN_MOVE_SELF        Watched file/directory was itself moved
       IN_MOVED_FROM       File moved out of watched directory (*)
       IN_MOVED_TO         File moved into watched directory (*)
       IN_OPEN             File was opened (*)    

Also the content of the script is :

1
2
3
4
5
#!/usr/bin/env bash
exec 200<$0
flock -n 200 || exit 1
sleep 4
cd /home/dbox/Dropbox/hexo && rm db.json && hexo generate && rsync -a --delete /home/dbox/Dropbox/hexo/public/ /home/wwwroot/public/

flock is used to acquire file lock, such that there could be only one bash script run at a time. This lock is used to avoid race condition.
From the answer from StackOverflow is a good reference to understand the exec 200<$0.
Also this link talks in general about how to create a library using flock: Elegant Bash Locking.

Reference

用Hexo+Vps搭建博客并用Dropbox同步自动发布
[Ubuntu]Dropbox命令行下安装与维护
linux下使用inotify实时监控文件变更,做完整性检查