Hosting a Jekyll Website on S3 with SSL

iRonin IT Team - Experts in software development
devops, infrastructure, web

When you have Jekyll-built static websites and want to easily host them, you can do it on Amazon S3. We outline the exact process + all the code necessary.

Jekyll is an excellent tool for creating static sites (from plaintext, markdown, and other basic styles) that can be easily hosted on Amazon S3, GitHub pages, Heroku or any other provider that can serve HTML files. In this article we will show you how to deploy an existing Jekyll-based website to S3 with CDN for improving the site’s performance, using CloudFront.

CloudFront for serving content over HTTPS

Serving static websites directly from S3 or GitHub pages works fine as long as you don’t need to serve it over HTTPS - neither allows custom SSL certificates for HTTPS. As far as we know, putting a load balancer, reverse-proxy or CDN, such as CloudFront, in front is the only solution (but if you know more do not hesitate to mention them in the comments!).

So with that, let’s dive into our solution. We will start by creating a new Content Distribution on CloudFront. Visit the AWS CloudFront Management Console, click Create Distribution, and select Web as the Delivery Method. Fill the Origin Settings section as outlined in this screenshot:

In the field where we put your_domain_or_bucket type the S3 endpoint that can be found in the Hosting Website section (ie: This allows you to respect the S3 redirect rules when accessing the website through CloudFront. Other sections can be left with default settings for now.

In the Distribution Settings section specify the SSL certificate you want to use:

If you don’t have a certificate added yet, then go to the Certificate Manager service on AWS and upload one there. It’s better to do it this way than import it directly in the Distribution Settings, because it makes managing the certificate easier (uploading updated versions, etc.).

Versioning static files

Before we start using CDN for serving content, we also need to make sure we have correct caching headers - so that unmodified files can be loaded from the browser’s cache. Despite this, we will need to be able to deliver new versions whenever they are updated (even when the cache headers are still valid). To do this, we will fingerprint file names - so the browser won’t find the new file in its cache, triggering a request to fetch it from our CDN.

For managing assets we will use the jekyll-assets gem. Add it to your Gemfile, run bundle install and update the _config.yml as below:

  - jekyll-assets

      - "last 2 versions"
      - "IE > 9"
  prefix: '/assets'
    - "main.css"
    - "*.js"
    - "*.png"
    - "*.jpg"
    - "*.eot"
    - "*.ttf"
    - "*.woff"
    - _assets

Migrating stylesheets

We also need to move all the stylesheet files from the _sass directory to assets/css and then update main.scss to be our entry point for importing other files:

@import "variables";
@import "global";

In the above example we assume you have the following structure in your _assets/css directory:

  • _global.scss
  • _variables.scss
  • main.scss

Remember to update your path to the assets in your templates and stylesheets:

  • Replace <img src="path/to/image.jpg" alt="some alt" />{% endraw /> with {% endraw /> with {% raw %}<img src="path/to/image.jpg" alt:'some alt' />
  • Replace <script src="path/to/script.js" /> with {% js 'path/to/script' %}
  • Replace <link rel="styleshee" href="path/to/stylesheet.css" /> with %{ css main.css %}
  • If you reference any files (fonts, images) in your stylesheets replace url('path/to/file') with url(asset_path('path/to/file'))

For more info visit the jekyll-assets page.

Migrating javascripts

We also need to move our scripts to assets/scripts folder and create a main.js file to reference our other files:

//= require jquery
//= require bootstrap

And include that main.js file in the template:

{% js main.js %}

Now when you build your website with the JEKYLL_ENV set to production the gem will concatenate, compress, and fingerprint your asset files automatically.

Deploying to S3

In order to deploy our static website to s3 we use the s3_website gem. It allows us not only to push the files to the bucket, but also to create invalidation in our distribution for our *.html files. HTMLs can’t be fingerprinted because we don’t want to change the links every time we deploy a new version.

Add the s3_website gem to your Bundle file and run the bundle install command. You’ll also need to have Java installed because the gem is using Scala under the hood.

Now create a basic config file in the project root:

s3_secret: AWS_SECRET_KEY
s3_bucket: your-bucket-name

index_document: index.html
error_document: error.html

max_age: 3600

gzip: **true**

s3_endpoint: eu-central-1

"assets/*": **public**, max-age=3600
"*": no-cache, no-store, max-age=0 must-revalidate

cloudfront_distribution_id: YOUR_CLOUDFRONT_DISTRIBUTION_ID

min_ttl: <%= 60 * 60 * 24 %>
quantity: 1

cloudfront_wildcard_invalidation: **false**

We disable caching (no-cache, no-store, max-age=0 must-revalidate) for all files except assets (those will be HTML files anyway unless you use a custom setup) .

Let’s apply those settings to our CloudFront distribution to check if everything is configured correctly:

bundle exec s3_website cfg apply

If you get something similar to the message below, it means the website is ready to be deployed:

Applying the configurations in s3_website.yml on the AWS services ...
Bucket your-bucket now functions as a website
No redirects to configure for your-bucket bucket
Bucket your-bucket is now readable to the whole world
Detected an existing CloudFront distribution (id 123456789) ...
  Applied custom distribution settings:
    :caller_reference: '123456789'

To deploy the website to S3, simply use the push command:

bundle exec s3_website push

If you would like to check which files are going to be sent first, then you can pass the --dry-run flag to the above command.

This will create invalidation on CDN. To check its status, go to CloudFront, select your distribution and visit the Invalidations tab. Usually it takes a few minutes before the HTML file is invalidated in CDN and a new version from your S3 bucket is fetched.

For more deployment configurations, organizing your website infrastructure, or website development in general, you can ask the experts at iRonin for assistance. Our team of highly skilled specialists have deep experience and are available to take a closer look at all your web development needs.

Author's Bio
iRonin IT Team

Experts in software development

We are a 100% remote team of software development experts, providing web & mobile application development and DevOps services for international clients.

Similar articles

Bulletproof your development with remote team augmentation

Read how
This page is best viewed in portrait mode
Our websites and web services use cookies. We use cookies and collected data to enhance your experience, provide additional communication channels, improve marketing materials and enhance our offer. IRONIN SP. Z O.O. SP. K. is committed to protecting all the data that we collect or process in any way, especially data of personal nature. By accepting these terms you agree to our usage of cookies and processing your data, according to our Privacy Policy, and you declare that your browser settings reflect your preferences. Read more You have the right to revoke this agreement at any time, based on the terms of our Privacy Policy. You can change cookies settings in your browser. If you do not agree with us using cookies and processing your data, please change your cookies settings in your web browser and reject these terms. You can find more information about cookies, your data privacy This site uses cookies. By continuing to browse the site, you are agreeing to our use of cookies. data processing, and your rights in our Privacy Policy.