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:
- Clone github-heroku-jekyll-hook via
git clone https://github.com/dommmel/github-heroku-jekyll-hook.git
andcd
into the new folder - Create a heroku app (
heroku create
) - Add a secret
heroku config:add ACCESS_KEY=supersecret
- Tell to use multiple buildpacks via
heroku config:add BUILDPACK_URL=https://github.com/ddollar/heroku-buildpack-multi.git
- Generate keys to access the github repo and heroku apps via
ssh-keygen -f deploy_rsa
on your local machine - Add the private key to heroku via
heroku keys:add deploy_rsa
- 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.git
andcd
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
Written by dommmel
Related protips
7 Responses
Thanks, I will try it.
@eveevans : Yeah, give it a shot and let me know if you run into any troubles.
Thanks... Dommel.. I will try to understand it...
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)
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.
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.
@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.