Deploying a Jekyll site with Kamal

05 Nov 2024
Are you eager to elevate your security skills and safeguard your applications against cyber threats? I created a Rails Security course is designed specifically for developers like you who aim to build robust, secure Rails applications!
Buy my course: Security for Rails Developers.

Since Kamal 2 can host multiple sites on the same server, I am consolidating my apps into larger hosts so I have less servers to worry about. Most of my apps are Rails apps, but I have a few static jekyll sites like this blog and I decided to look into how could I move this site to a server I host other Rails apps on.

The first step of the process is to “dockerize” the jekyll site. Kamal Proxy will handle SSL and only requires something to process HTTP requests, so we will create a container with nginx, serving the static HTML files over port 80. To achieve this, we need to create the following Dockerfile in the root of the jekyll project:

# Dockerfile
# syntax = docker/dockerfile:1
FROM nginx

EXPOSE 80

I build my jekyll sites into the _site folder, so the next step is to copy that to default folder of nginx so it can serve those files:

# Dockerfile
# syntax = docker/dockerfile:1
FROM nginx

COPY ./_site /usr/share/nginx/html

EXPOSE 80

The next step is to setup Kamal for deployment. Once you installed the gem, run kamal init to create the default config file. We will adapt it to do the following:

  • load the .env file so we can set the KAMAL_REGISTRY_PASSWORD from that
  • set the service name to our static site
  • configure the image name
  • configure a web host
  • enable SSL for the proxy and setting the hostnames we want to use
  • set the healthcheck path to the root of the site
  • configure the registry
  • set the builder context to “.”, so we don’t need to commit the build to the git repository

This is how config/deploy.yml should look after doing all of the above:

# config/deploy.yml
<% require "dotenv"; Dotenv.load(".env") %>
# Name of your application. Used to uniquely configure containers.
service: mystaticsite

# Name of the container image.
image: registry/static-site

# Deploy to these servers.
servers:
  web:
    hosts:
      - 1.1.1.1 # server IP

# Enable SSL auto certification via Let's Encrypt (and allow for multiple apps on one server).
# Set ssl: false if using something like Cloudflare to terminate SSL (but keep host!).
proxy:
  ssl: true
  hosts:
    - domain.com
    - www.domain.com
  healthcheck:
    path: /
    interval: 3
    timeout: 30
# Credentials for your image host.
registry:
  server: registry.digitalocean.com
  username:
    - KAMAL_REGISTRY_PASSWORD
  # Always use an access token rather than real password when possible.
  password:
    - KAMAL_REGISTRY_PASSWORD

# Configure builder setup.
builder:
  arch: amd64
  context: .

Now you just need to put the KAMAL_REGISTRY_PASSWORD in the .env file and you are basically ready to deploy. But you should add a .dockerignore file and put everything else than your build directory into it:

# .dockerignore

# Ignore everything
*
# Allow build folder
!/_site

To make sure you always build before deployment, you can use a Kamal hook. Put the following to .kamal/hooks/pre-build:

#!/bin/sh
JEKYLL_ENV=production bundle exec jekyll build

All you have to do now is to deploy the app with kamal deploy.

Or follow me on Twitter

Related posts