Jekyll Static Website with Continuous Deployment/Delivery to S3/Heroku
Develop a static website with Jekyll and deploy it automatically to S3 and/or Heroku
Requirements
- jekyll
- jekyll-assets (optional)
- bootstrap-sass (optional)
- s3_website
- Amazon S3
- Heroku
- CodeShip.io (optional)
Intro
As a Ruby (on Rails) developer, I sometimes wonder if a web application is always the right solution for all my problems. Most of the time it is not, a simple HTML static website would be enough. But then it would be nice to have some of the nice tools that you can use developing a web application, like templates and partials, an assets pipeline, easy deployment and some sort of intermediate markup or scripting language to dynamically generate pages and assets (like markdown, ERB, SCSS/Less and Coffescript).
To find a viable solution to these needs, I would recommend jekyll: an awesome and really popular gem to build static websites with powerful tools, like markdown syntax, liquid templates, assets pipeline and many more. Github uses it to provide simple to mantain pages to be hosted for free on their servers.
But what if you don’t want to use Github to host your static websites or you want other options instead of hosting them on your own servers?
This tutorial will explain how to use Jekyll and some of its plugins to develop a static website with a Rails-like assets pipeline and deploy it to Amazon S3 and/or Heroku with a Continuous Deployment/Delivery system.
Let’s start by installing and configuring the basics.
Basic setup
Install the Jekyll gem
Create a new jekyll project
Run the jekyll server
and visit http://localhost:4000
: you will see a nice looking page with some examples of the potentialities of Jekyll.
Configure the project
For the pourpose of this tutorial, I want to start from a clean slate. I will remove the boilerplate files created by Jekyll and create a slightly different directory structure. You are free to skip this passage, if you wish to keep the example files.
The project directory structure:
Create a Gemfile
in the root directory and add these gems.
Install the gems
Assets Pipeline
Add the jekyll-assets
plugin to the _plugins/ext.rb
file. This plugin allows to use a Rails-like assets pipeline in a Jekyll project, including using CoffeScript, Sass, Less and ERB as intermediate languages to write your assets and pages, automatic minification of code, cache busting and many other cool features that you can discover on the Github repository of the plugin.
We also added the bootstrap plugin to automatically use the framework in the project. Feel free to skip this if you want to start from scratch or with an other framework/library.
More information about Jekyll plugins can be found in the Jekyll documentation.
To use the assets pipeline, we need to add the assets
configuration to the _config.yml
file.
If you set the debug
flag to true, you skip the minifications of the assets. It can be useful during development to debug the Javascript.
Add some content
JQuery is required to use the bootstrap JS components, so you can download the latest version (1.11.1 at the time of writing) of the library and put the file in _vendors/javascripts/
. As a convention, it’s better to put external libraries, stylesheets and files in the _vendors
directory and keep your own files separated from them.
Require both the jquery minified file and bootstrap in the _assets/javascripts/application.js.coffee
file. You can add more files and require them in this one.
Similar to the javascripts, we import the main bootstrap stylesheet in the _assets/stylesheets/applications.css.scss
file. We added just a little style to account the fact that we use a fixed navigation bar and we need to push the main content a bit down.
Finally let’s setup the default layout _layouts/default.html
template. As you can see we are using some helpers to include other html files that you can find in the _includes
directory. We us also the javascript
helper provided by jekyll-assets
to include our application javascript file.
Nothing special here apart the usage of the stylesheet
helper, always provided by jekyll-assets
in order to include the application stylesheet in the _includes/head.html
file.
Our _includes/header.html
file with just a basic nav-bar provided by bootstrap.
And a simple _includes/footer.html
file.
Finally add some content to the index.html
file. It will be the default page diplayed when accessing your website.
And we are done for this part. Run the server (if you haven’t already).
Visit localhost:4000
and check the results.
Deploy to S3
Amazon S3 is mostly used as an external storage for assets or files, but can also be configured to serve an entire static website in a scalable, cheap and performant way. To deploy our static website to it, we can use the s3_website
. To start using it, add the gem to the Gemfile
.
and bundle it.
We are going to use a YAML file to hold the information that the s3_website gem will use during the deployment process. Create a new file called s3_website.yml
in the root dir with this content.
As you can see we are not going to store any sensitive information - like your AWS keys - in the repositories file. Create an .env
file in the root dir of the project and add there the credentials that you want to use. Remember to add the .env
file to the .gitignore
. In this way you can have other environment variables on your servers. More information about storing your variables in the enviroment can be found on the 12factor website.
More information about setting up a IAM user on AWS for s3_website
can be found on the github repository
Create a new bucket in your S3 account. Open the Static Website Hosting
menu in the properties for the new bucket and check Enable website hosting
and adding index.html
as the Index Document.
In order to upload correctly the compiled files with s3_website
we need to give the permission to do so to the IAM user we just created. Go to the Permissions
tab and click on Add more permissions
. Select Authenticated Users
and grant at least List
and Upload/Delete
.
We need also to setup the bucket policy to allow every page to be seen as public. To so click on Add bucket policy
in the Permissions
tab again and paste this code in the textarea. Remember to substitute BUCKET_NAME
with your correct bucket name.
You can try if your AWS setup and configuration is ok by running
It will execute all the commands to build the files from Jekyll and test the permissions to upload them on S3, without actually doing it and cleaning up afterwise.
If everything went ok, you can push your website for real, by removing the --dry-run
option.
You can now check on your AWS management console if the files were uploaded and visit the S3 url to see your new shiny pages. The url will be composed by your BUCKET_NAME
and the REGION
were you created your bucket. More information on the S3 documentation about website endpoints.
Deploy the static website to Heroku with Rack
If for whatever reason you don’t want to deploy your static website to S3 (or not only), you have another option by deploying it to Heroku as a simple Rack
application.
This tutorial is not about setting up an Heroku app, more information on how to get started with Heroku can be found in the official documentation.
Start by adding these gems to the Gemfile
:
And run the bundle install
command.
We are going to render a 404 page for all the requests that don’t exist. Create a 404.html
file in the root directory.
To run our static website as a Rack application, we need a config.ru
file to specify the configuration. In this case we are going to use Rack::TryStatic
from the rack-contrib
gem. It similar to the standard Rack::Static
middleware, but it allows us to specify which files should be tried to be loaded for a request: for example a url like /about
will try to load an about.html
, about/index.html
file or render the 404 page.
Credits to Matthew Manning for the tutorial on how to deploy a static website to Heroku with Rack::TryStatic
.
Add some new files to the exclude key in your _config.yml
file.
To try if our configuration is working you can either use the rackup
command or a server like thin
(that we bundled in the Gemfile). With rackup
just visit localhost:9292
, while thin
runs the server by default on localhost:3000
, but first remember to build the website with jekyll build
.
For the purpouse of this guide, let’s assume that you have already an Heroku account and everything ready to create a new app. First thing we need to create a git repository inside the project directory and create the first commit to be deployed.
First create a simple .gitignore
file in which we specify not to commit the _site
and .sass-cache
directories and the .env
file. We will build the files during the deployment with the clever trick of using the assets:precompile
rake task to actually build the website with Jekyll.
Then initialize the git repository, add and commit the files.
In order to compile our files and not needing to commit them to repository, we are going to use a clever trick. Create a Rakefile
in the root directory of the project and add these two tasks:
As you can see, we are overriding the usual assets:precompile
task that is run to compile the assets during deployment to actually build the whole website with Jeyll. In this way Heroku will build the website for us!
Credits for this solution have to be given to Jesse B. Hannah.
To tell Heroku how to run our Rack application, we need to create a Procfile
file in the root directory. We are going to use thin and let the Heroku environment picks up the right port.
Finally we came to the point where we can create the Heroku app and push our website to it! We can pass the name that we want to use for the app, example-static-jekyll
in my case. Remember to change it with your own. The app will be then available at the url YOUR_APP_NAME.herokuapp.com
. In my case I also create the app on the European region, if you are somewhere else, just skip it.
If everything went right, you should be able to reach your website at YOUR_APP_NAME.herokuapp.com
. For more information on how use your own domain and other things that you can do with your Heroku app, please refer to the official documentation.
Continuous Deployment/Delivery with Codeship.io
Whether you choose to deploy your website to S3 or to Heroku or both, it would be nice if you can have a Continuous Deployment/Delivery process in place: you do some changes to your source code, commit and push and automatically some external system deploys/delivers your compiled website somewhere.
I use Codeship for my own company and personal projects and I will recommend you to try it. You can signup for a free account with 100 included deploys a month (more than enough for a side project) and the setup is really easy if you host your repository on Github or Bitbucket and deploy to Herou or similar system. With a little bit of configuration you can also put complex continous integraion and delivery processes for big applications.
If you want to try out this way of deploying your website, just create an account and setup your project by giving the possibility to Codeship to pull your repository, depending if you are using Github or Bitbucket.
You need then to specify your build command to test and deploy your application/website. First select Ruby
from the technology dropdown in the Test
section and add these commands to the Setup Commands
area:
In order to “test” our application we will use the s3_website push --dry-run
command in the case of S3 deployment. You can leave the test commands section empty if you plan to deploy to Heroku.
If you want to deploy to S3 with s3_website
we need to specify our credentials in the Environment
section in the sidebar. Just copy the variables that you set in the .env
file.
Finally we need to configure the actual deployment process: go to the Deployment
section and select Custom Script
for S3 or Heroku
for that. In the custom script (for S3 deployment) just add s3_website push
and you are done.
For the Heroku setup you need to specifiy the name of the Heroku app that you created some steps before and give the Heroku api key that you can find following the instructions. You can also specify the url to check to confirm the proper deployment of the app.
This is it! To test the final process that you’ve just configured, just edit something in the project repository and push to Github or Bitbucket. Codeship will start the test and deployment process as soon it finds a new commit to the repo.
Bonus: Add Basic HTTP Authentication
One of the reasons to move from a simple S3 hosting to an Heroku app, is because we can leverage on the amount of Rack middlewares, for example to add a basic HTTP authentication to our static website with three lines of code.
To do so, add the Rack::Auth::Basic
middleware to the config.ru
file, before the Rack::TryStatic
configuration.
Remember to change the username and password with something less trivial. Commit and push your app to Heroku and enjoy an added layer of security to your website.
Conclusion
Whoa! It was a long ride, wasn’t it?
You can find the code generated for this tutorial on Github.
I hope I gave you some good tips on how to leverage the potentialities of the awesome Jekyll gem, S3, Heroku and Codeship. If you have any question feel free to comment on this page or send me and email to luca.tironi@gmail.com.
Bye,
Luca
^Back to top