Deploy a Hexo blog with Capistrano

Hexo has become a little flaky of late, but it’s still my goto software when I need to set up a new blog. It boasts One-Command Deployment, which would be great if I could figure out how to deploy it to anything other than GitHub or Heroku. There may be a way, but I’ve tried nothing and I’m all out of ideas. So instead I’ll deploy with Capistrano, because I want to try it with something other than Rails for a change.

Assumptions

You’re working on Ubuntu with the following installed on a remote machine on which to host a git repository and blog site:

Hit me up in the comments if I’ve missed any basic dependencies. The software immediately pertinent to this post (e.g., Hexo and Capistrano) will be installed as required.

I’m also assuming that you have a remote machine or cloud server on which to host a git repository and Hexo blog site. Your blog will be modified on a local machine and deployed to a production machine with Capistrano. As such, to make things easy, all the software named above needs to be installed locally and remotely.

Install Hexo on your local machine

Detailed instructions are found here, but this is how you do it in a nutshell:

1
npm install hexo-cli -g

npm should have been installed as part of the node installation.

Initialize a Hexo blog

This, of course, is not necessary if you already have a Hexo blog to work with. But if you don’t,

1
2
3
hexo init blog
cd blog
npm install

Set up a remote git repository

Capistrano talks to your blog’s remote repository when it comes time to deploy. See git remote repository SSH setup for help on how to set this up.

When the blank repository has been initialized on the remote machine, you will need to initialize git in your local Hexo blog directory (i.e., blog/ if you’re following from the previous step). This step is covered in the link provided and repeated here. Assuming you’re in the blog/ directory:

1
2
3
4
5
git init
git add .
git commit -m "Hello, my new Hexo blog"
git remote add origin git@example.com:/opt/git/my-hexo-blog.git # Change domain and project name as appropriate
git push origin master

If everything is set up correctly, you won’t even need to enter a password to push your first commit.

nginx

Add host:

1
2
3
sudo touch /etc/nginx/sites-available/my-hexo-blog.conf
sudo ln -s /etc/nginx/sites-available/my-hexo-blog.conf /etc/nginx/sites-enabled/my-hexo-blog.conf
sudo vim /etc/nginx/sites-available/my-hexo-blog.conf

Write the following to the file:

1
2
3
4
5
6
7
8
9
10
11
server {
listen 80;
server_name example.com www.example.com;
access_log /var/log/nginx/example.access.log;
error_log /var/log/nginx/example.error.log;

location / {
alias /home/deploy/example/current/public/;
try_files $uri $uri/ /index.html;
}
}

Restart:

1
sudo service nginx restart

Install Capistrano

1
gem install capistrano

Set up Capistrano

Just like hexo and git, Capistrano needs to be initialized in your project directory:

1
cap install

If successful, you will see something like this:

1
2
3
4
5
6
7
mkdir -p config/deploy
create config/deploy.rb
create config/deploy/staging.rb
create config/deploy/production.rb
mkdir -p lib/capistrano/tasks
create Capfile
Capified

With regard to the steps previously taken, modify the pre-cooked config/deploy.rb as appropriate. For example:

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
set :application, "my-hexo-blog"
set :repo_url, "git@example.com:/opt/git/my-hexo-blog.git"

# Default deploy_to directory is /var/www/my_app_name
set :deploy_to, "/home/deploy/my-hexo-blog"

# ...

namespace :deploy do

# 2015-4-14 https://gist.github.com/ryanray/7579912
desc 'Install node modules'
task :npm_install do
on roles(:web) do
execute "cd #{release_path} && npm install"
end
end

desc 'Compile markdown'
task :hexo_generate do
on roles(:web) do
execute "cd #{release_path} && hexo generate"
end
end

before :updated, 'deploy:npm_install'
after :deploy, 'deploy:hexo_generate'
after :finishing, 'deploy:cleanup'
end

Then, in config/deploy/production.rb, modify as appropriate once again (out of the box, it should be sufficient to tack this on to the end of the file):

1
server "example.com", user: "deploy", roles: %w{web}

Note: the above assumes that my remote production server has a user named deploy and that this user can write to the /home/deploy/my-hexo-blog directory. Ultimately, it is up to you to determine which user deploys and where your blog is located on the file system.

Deploy

1
cap production deploy

That should do it. If something goes wrong,

1
cap production deploy --trace

will give more details.