Josh Veitch-Michaelis bio photo

Josh Veitch-Michaelis

I'm a physicist/coder/space scientist/3D imager/optical engineer.

LinkedIn Github

The idea for this came when I decided that I’d try to blog more when I travel, but I didn’t want to have to faff around with ssh on my iPad (my current travel machine). Instead I wanted to be able to add new posts to a Dropbox folder and then have one of my machines at home rebuild and update the site for me. It would probably be easier to have everything running on the webserver itself, but that does assume that you have permission to install services (e.g. the Dropbox CLI) which isn’t always the case.

At the very least this is a quick guide on painlessly deploying a Jekyll site and I use this script on my local machine too.

The solution I ended up with performs the following steps, via a shell script which is called by cron twice a day:

  • Run the rakefile to rebuild the site
  • rsync the files to the webserver over ssh

Requirements

  • A home server running some flavour of *nix with rsync installed.
  • Jekyll
  • A Dropbox or other cloud account
  • SSH access to your webserver

Of course if you run your own webserver, this may be a good deal easier.

Automating the build

The first step is a quick shell script that will rebuild the site:

#!/bin/bash
    
rake deploy

Nothing more to it than that. This script is stored in my Jekyll folder which is synced with Dropbox.

The rakefile calls:

$ jekyll build --trace --config _config_production.yml

and the site gets rebuilt.

Uploading to the webserver

The second step is deploying the new site; we add one more line:

#!/bin/bash

rake deploy
rsync -avz ./_site/ -e ssh you@yourwebsite.com:public_html/

We simply rsync the contents of _site to the relevant directory on the webserver. In my case, I have it in the root of my public_html. Change the locations as necessary. The flags denote -a archive, for recursive copy, -z compress and -v verbose.

Make sure the script is executable too:

$ chmod +x /path/to/site/update.sh

It’s also convenient to have passwordless SSH; this is simple to set up. By far the quickest method I’ve seen is:

#press enter until you run out of things to agree to
$ ssh-keygen
$ ssh-copy-id -i you@yourwebsite.com
#log in without your password!
$ ssh you@yourwebsite.com

You’ll need to enter your SSH password once, when you copy the ID over, but after that you should be good to go.

Integration with git, and only rebuilding if necessary

It’s a good idea to keep track of your blog with a repository, at the very least you’ll be able to version your posts. git is as good a tool as any for this. I’ve got my blog set up so that whenever the server gets updated, I make a commit.

One solution is:

  1. Run git add -A as part of the cronjob
  2. Then run git diff --cached to check for any changes relative to the previous commit (such as a new file).
  3. If the result of the diff is nothing, then no need to rebuild.

Simply running git diff will only show you modified files that are already being tracked, no good for new posts. You could run git add before, but that spoils the point of only rebuilding and syncing if something’s actually changed.

#!/bin/bash

# Perform a diff, check if anything's changed
git add -A

CHANGED=`git diff --cached`

COMMITMSG="Autocommit on "
COMMITDATE=`date`
COMMITSTRING=$COMMITMSG$COMMITDATE

if [ "$CHANGED" != '' ]; then
	rake deploy
	RESULT=`rsync -az ./_site/ -e ssh struckby@ragnar.asmallorange.com:public_html/`
	if [ "$RESULT" == '' ]; then
		git commit -am "$COMMITSTRING"
		echo "Uploaded."
	fi
else
	echo "Nothing changed."
fi

In this case the commit message is Autocommit on [today's date]. You could make it a bit more descriptive, but this is enough for me to differentiate between proper commit messages (e.g. I’ve modified a layout or template) and automatic uploads.

If you get the error message: stdin: is not a tty then you need to add [ -z "$PS1" ] && return to your .bashrc file on your webserver. More info here. You want rsync to be quiet if everything goes well; the idea is that a failed upload will not result in a commit and rsync will retry next time the job is run.

Setting up cron

I chose to update twice a day, since I’m not posting urgently.

0 0,12 * * * /path/to/site/update.sh

Add that to your crontab and you’re good to go!

Usage

Simply add new posts to the Dropbox folder and the cron job does the rest!