I love us­ing Jekyll. I use it for this blog, my per­sonal site, and it’s the first thing I sug­gest when peo­ple want some­thing with con­tent that needs to be up­dated. However, de­ploy­ing gets com­pli­cated when you’re us­ing a va­ri­ety of plu­g­ins and you don’t want to host with GitHub Pages.

I had setup Deploy to do this au­to­mat­i­cally when new com­mits were pushed to the mas­ter branch. But I wanted some­thing bet­ter; some­thing that did­n’t feel like so much of a hack. I was hav­ing to com­pile the whole site lo­cally, and some­times I’d for­get to use the right con­fig file, so things would break and I’d have to scram­ble to fix quickly.

One day, the light­bulb when off, and I started to won­der if I could use Heroku to host my Jekyll sites. After do­ing some cal­cu­la­tions, I felt like I could im­prove the de­ploy work­flow, and save a lit­tle money.

Well, it was a big­ger pain in the butt to fig­ure out than I thought, but once you un­der­stand the pieces, it ac­tu­ally is pretty sim­ple. Unfortunately, most of the ar­ti­cles that walk you through this process were pub­lished a while ago, so they were us­ing out-of-date gems, and dep­re­cated com­mands.1 But by com­bin­ing the process of this ar­ti­cle and this ar­ti­cle, you find your­self with a great so­lu­tion. Hopefully you’ll find this use­ful.

Ignore the Site Folder #

First things first, you’ll want to ig­nore your _site folder. You’ll be build­ing the site on the server now, so there’s no need for these files to be clut­ter­ing up your repo. In your .gitignore add the fol­low­ing line:

# .gitignore

Exclude Vendor in _config.yml #

You’ll also want to ex­clude vendor in your _config.yml file. This folder is gen­er­ated by Heroku I be­lieve. I did­n’t ac­tu­ally test why this needs to be done, but I did it.

# _config.yml
excluded: ['vendor']

Add Gemfile #

If you don’t have one al­ready, you’ll want to cre­ate a Gemfile. I rec­om­mend you visit RubyGems.org for the lat­est ver­sions.

How to Create a Gemfile

In your ter­mi­nal cd into the di­rec­tory of your Jekyll site and type bundle init. You’ll need to have the bundler gem to do this, so if you don’t have that, type gem install bundler into your ter­mi­nal to in­stall.

# Gemfile
source "https://rubygems.org"
gem 'foreman'
gem 'jekyll'
gem 'rack-contrib'
gem 'rake'
gem 'thin'

Once you’ve got these gems in your Gemfile, run bundle install and make sure your Gemfile.lock is checked into your repo. The build process will fail with­out the Gemfile.lock.

Add Procfile #

Next, add a Procfile. We’ll be us­ing thin to serve up our site. You do that with the fol­low­ing lines:

# Procfile
web: bundle exec thin start -p $PORT -V
console: echo console
rake: echo rake

Add Rakefile #

We need to tell Heroku to build our site, and we’ll do that by at­tach­ing a com­mand to the rake assets:precompile task that Heroku runs. Create a Rakefile, and add these lines:

# Rakefile
namespace :assets do
task :precompile do
puts `bundle exec jekyll build`

Add con­fig.​ru #

Now, we need to tell Rack how to serve up our files. We want it to do this sta­t­i­cally so we’ll add a config.ru file and add the fol­low­ing lines:

# config.ru
require 'rack/contrib/try_static'

use Rack::TryStatic,
:root => "_site",
:urls => %w[/],
:try => ['.html', 'index.html', '/index.html']

run lambda { |env|
return [404, {'Content-Type' => 'text/html'}, ['Not Found']]

Lastly, make sure you’re us­ing rel­a­tive URLs for as­sets. I ran into a javascript er­ror for call­ing jQuery over an in­se­cure con­nec­tion. Which meant chang­ing the line.2

<!-- You'll change a line like this -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<!-- To this -->
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

That’s it! Now just push your repo to Heroku, and it’ll build the site and serve it. If you’d like to dig through the repo for this site, it’s on GitHub.

  1. Not to men­tion, it was dif­fi­cult to find a pat­tern of how peo­ple do this. You’ll usu­ally do re­search on some­thing like this and all the blog posts will point you to the same steps. Not here. There were like four dif­fer­ent ways, some that seemed sim­ple, and oth­ers that were quite com­plex and re­quired knowl­edge of routes in Sinatra. Craziness. ↩︎

  2. I add this in­for­ma­tion be­cause my JS was­n’t work­ing and I spent like 20 min­utes just scratch­ing my head as to why. Opened the con­sole, and found the is­sue im­me­di­ately. Should’ve done that in the first place. ↩︎

Series Jekyll with Heroku

Hacks to get your Jekyll site deployed and thriving on Heroku.

View Series →