Last Updated: February 25, 2016
·
13.31K
· dommmel

Automatically build and deploy Jekyll sites to heroku (from github)

Alternative title: Building and deploying a jekyll site with an ajax contact form

Github pages are great for building and hosting jekyll sites. But sometimes they just don't cut it. For instance when you need jekyll plugins (Github turns them off for safety reasons) or you need some additional server-side logic - as I did for an ajax contact form.

The following is a write-up of the setup I use to automatically build and deploy a sinatra/jekyll-hybrid app to heroku whenever I push an update to the github repository where I host the source code.

Requirements

  • Build the site with jekyll
  • Implement an ajax contact form
  • Be able to deploy via a simple git push to github (so that http://prose.io can be used)

Possible solution

My solution (I am sure there are plenty of others) to the requirements above is the following

  • Sinatra app hosted on heroku (based on this template)
    • serve the static pages generated by jekyll
    • provide a POST endpoint for the embedded contact form
  • Heroku build server
    • fetches the github repo whenever it is pushed to (via webhooks)
    • builds the jekyll site
    • pushes the code to a production app on heroku

Ok ,let's do this…

Doing it

I use a small clojure app - github-heroku-jekyll-hook - running on heroku as the build server. You can use this build server for as many apps as you want.

Setting up the build server

To set it up you need to do seven things:

  1. Clone github-heroku-jekyll-hook via git clone https://github.com/dommmel/github-heroku-jekyll-hook.git and cd into the new folder
  2. Create a heroku app (heroku create)
  3. Add a secret heroku config:add ACCESS_KEY=supersecret
  4. Tell to use multiple buildpacks via heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git
  5. Generate keys to access the github repo and heroku apps via ssh-keygen -f deploy_rsa on your local machine
  6. Add the private key to heroku via heroku keys:add deploy_rsa
  7. Add the public key (./deploy_rsa.pub) to your github repo (via github's web interface, see this How-To)

Configure the build server for you app(s)

After setting up the build server you need to configure it for each app you want use it for. Each app needs the keys, and location of the github to fetch from and the heroku repository to push to.

Configuration for your app

heroku config:add appname_SSH_KEY="$(cat deploy_rsa)" appname_GITHUB_REPO=git@githup.com/dommmel/appname.git appname_HEROKU_REPO=git@heroku.com

(replace appname with the name of your app and set the correct github and heroku remote git repository urls)

Adding a github webhook

Then, set up a github webhook pointing to a URL like

https://github-heroku-jekyll-hook.herokuapp.com/deploy?app=appname&key=supersecret

Be sure to replace your secret with the one you set in step 3. of "Setting up the build server" above

For bonus points, you'll probably want to set up a Heroku deploy hook to let you know when your app was deployed.

Anatomy of the to-be-build-&-deployed app

This may be specific to my particular use case, but I am going to briefly lay out the cornerstones of the sinatra/jekyll app I first used this whole thing for.

You can find the template for this sinatra-jekyll-hybrid app on github. It uses jekyll-assets to compile sass files (via compass) to css and coffeescript files to javascript.

In the following I am going to point out some important bits.

If you are like me and you like to skip the talking, then just go ahead and try it for yourself first

  • clone the template via git clone https://github.com/dommmel/sinatra-jekyll-hybrid.gitand cd into the folder
  • install dependencies via bundle install
  • compile the site via jekyll build
  • and fire up the app via foreman start to test it locally
  • deploy it to heroku (heroku create) - Notice that we are not committing the generated pages nor pushing to heroku yet. This is done later by the the build server

Anyway… now the talking

Folder structure

Since I have a sinatra/jekyll-hybrid my folder structure looks like this

project_root
 |__ jeykll
 |    |__ …
 |__  sinatra
 |     |__ app.rb
 |__ Procfile
 |__ config.ru
 |__ _config.yml
 |__ Gemfile

Configuring jekyll

Jekyll needs find the sources located in the jekyll folder. You can configure this via the source option in your _config.yml

source: jekyll
assets:
  compress:
    js:   uglifier
    css:  sass

Add gems

Add all gems needed to build the site to your Gemfile, in my case it looks like this

source 'https://rubygems.org'

group :development do
  gem 'coffee-script'
  gem 'compass'
  gem 'uglifier'
  gem 'jekyll'
  gem 'jekyll-assets'
end

gem 'sinatra'
gem 'thin'

Serving the jekyll pages with sinatra

The part of app.rb that does this is:

get '/*' do
  file_name = "_site#{request.path_info}/index.html".gsub(%r{\/+},'/')
  if File.exists?(file_name)
    File.read(file_name)
  else
    raise Sinatra::NotFound
  end
end

Ignoring the generated site from git

To ignore your local _site folder (generated by jekyll) when pushing to github, but still have it being pushed to heroku later, add it to .git/info/excludes.

Fin

There you have it. Push to github and your site updates. What else?

BTW: If you found this kinda neat you might want to have a look at jekyll-hook
PS: English is not my native language and I wrote this down quickly; I am always thankful for correction and remarks

7 Responses
Add your response

Thanks, I will try it.

over 1 year ago ·

@eveevans : Yeah, give it a shot and let me know if you run into any troubles.

over 1 year ago ·

Thanks... Dommel.. I will try to understand it...

over 1 year ago ·

Update: I forgot to mention that the build server uses multiple heroku buildpacks. To configure the app accordingly run heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git (thanks Joe Martinez)

over 1 year ago ·

Thank you. I was updating my website but it kept failing when pushed to Heroku and I rebuilt it following your guide and everything worked out great.

over 1 year ago ·

Add the private key to heroku via heroku keys:add deploy_rsa

This step always fail cause my heroku can only upload Public key:

% heroku keys:add deploy_rsa                                      
 Uploading SSH public key deploy_rsa... failed
 !    Invalid public key.

Any advice? Thanks.

over 1 year ago ·

@coaku: Mhmm - looks like you found an error in my post. Thanks! I think this should say: "Public key" resp. "deploy_rsa.pub". Changing it now.
BTW: Nowadays I use a CI service (in my case wercker.com) to build and deploy my jekyll pages from github to heroku. I found this to be more convenient in my case.

over 1 year ago ·