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
rakefileto rebuild the site
rsyncthe files to the webserver over
- A home server running some flavour of *nix with
- 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.
$ 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 firstname.lastname@example.org:public_html/
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
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 email@example.com #log in without your password! $ ssh firstname.lastname@example.org
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:
git add -Aas part of the cronjob
- Then run
git diff --cachedto check for any changes relative to the previous commit (such as a new file).
- If the result of the diff is nothing, then no need to rebuild.
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 email@example.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!
Simply add new posts to the Dropbox folder and the cron job does the rest!