Deploy Jekyll 4.2.0 in Docker Swarm, Behind Caddy v2.3

Deploy Jekyll 4.2.0 in Docker Swarm, Behind Caddy v2.3

Jekyll is a simple blog-aware static site generator for personal, project, or organization sites. You give it text written in your favorite markup language and it uses layouts to create a static website. You can tweak how you want the site URLs to look.

In this post, I am going to show you how to deploy Jekyll as a file server behind Caddy 2.3 to our Docker Swarm Cluster using the Docker Compose tool.

Jekyll is a static site generator. You give it text written in your favorite markup language and it uses layouts to create a static website. You can tweak how you want the site URLs to look.

Jekyll is a simple blog-aware static site generator for personal, project, or organization sites. Written in Ruby by Tom Preston-WernerGitHub’s co-founder, it is distributed under the open source MIT license

Please go through my previous post about Deploy Jekyll in Docker Swarm to learn more about Jekyll.

Let’s start with actual deployment…


Please make sure you should fulfill the below requirements before proceeding to the actual deployment.

  1. Docker Swarm Cluster
  2. Jekyll Dev Environment
  3. Caddy as reverse proxy to expose micro-services to external


I wrote the below articles with regards to Jekyll previously. Please find the links below if you didn’t go through them. It would be good to go through the links before proceeding further.

Jekyll Behind Traefik

Jekyll Dev Environment on Windows 10

Persist Jekyll Data

You must be familiar with Jekyll Dev Environment on Windows 10 article and section Build and Server the Site

After bundle exec jekyll build there will be _site folder created in our theme directory. All the html files will be there in _site folder. I will be persisting _site folder using GlusterFS and server the files using Caddy 2.3 as a file server.

As mentioned in previous articles, Containers are fast to deploy and make efficient use of system resources. Developers get application portability and programmable image management and the operations team gets standard run time units of deployment and management.

With all the known benefits of containers, there is one common misperception that the containers are ephemeral, which means if we restart the container or in case of any issues with it, we lose all the data for that particular container. They are only good for stateless micro-service applications and that it’s not possible to containerize stateful applications.

I am going to use GlusterFS to overcome the ephemeral behavior of Containers.

I already set up a replicated GlusterFS volume to have data replicated throughout the cluster if I would like to have some persistent data.

The below diagram explains how the replicated volume works.

GlusterFS Replicated Volume

Volume will be mounted on all the nodes, and when a file is written to the /mnt partition, data will be replicated to all the nodes in the Cluster


In case of any one of the nodes fails, the application automatically starts on other node without loosing any data and that’s the beauty of the replicated volume.

Persistent application state or data needs to survive application restarts and outages. We are storing the data or state in GlusterFS and had periodic backups performed on it.

Jekyll site will be available if something goes wrong with any of the nodes on our Docker Swarm Cluster. The data will be available to all the nodes in the cluster because of GlusterFS Replicated Volume.

I am going to create a folder jekyll-caddy in /mnt directory to upload _site directory files to it.

cd /mnt
sudo mkdir -p jekyll-caddy


Please watch the below video for the GlusterFS Replicated Volume Setup.

Upload files to Docker Swarm Cluster

I am using Windows 10 as Dev Environment and using the WinSCP tool to upload files to Docker Swarm Environment. (Upload the files to the Manager node and the files will be available throughout the cluster).

That’s it, you’re ready to use Jekyll on Windows 10 to develop sites.

Please download WinSCP using the below link if you are also using Windows 10 as your Dev Environment.


Those who use Linux as Dev Environment can use the scp command-line utility to upload files. Please find scp command below for your reference.

scp local/file/path user@host:server/file/path

Caddy File Server Directory

Caddy’s static file server works by appending the requests URI path to the site’s root path. Requests to directories will be redirected to have a trailing forward slash, and requests to the files will be redirected to strip the trailing slash.

Please go through the below link to learn more about Caddy’s Static File Server directory.

Caddy’s Static File Server

Caddyfile – Jekyll

The Caddyfile is a convenient Caddy configuration format for humans.

Caddyfile is easy to write, easy to understand, and expressive enough for most use cases.

Production-ready Caddyfile for Jekyll as Static File Server. You can use it for other static site generators as well, like Hugo.

Learn more about Caddyfile here to get familiar with it.

    default_sni jekyll
    cert_issuer acme
    # Production acme directory
    # Staging acme directory
    servers {
        protocol {
        timeouts {
            read_body   10s
            read_header 10s
            write       10s
            idle        2m
        max_header_size 16384
} {
    log {
        output file /var/log/caddy/jekyll.log {
            roll_size 20mb
            roll_keep 2
            roll_keep_for 6h
        format console
        level error
    root * /etc/caddy/html/
    file_server {
        hide .git
    try_files {path}.html {path}
    encode gzip zstd

Please go to Caddy Post to get more insight to deploy it in the docker swarm cluster.

Caddy Docker Compose

Please find the full docker-compose file below. You can deploy as many sites as you want using it.

Don’t forget to map site data directories like /mnt/jekyll-caddy:/etc/caddy/html/ in Caddy configuration caddy.yml.

I already wrote an article Caddy in Docker Swarm. Please go through if you want to learn more.

version: "3.7"

    image: caddy:alpine
      - "80:80"
      - "443:443"
      - caddy
      - ./Caddyfile:/etc/caddy/Caddyfile
      - /mnt/caddydata:/data
      - /mnt/caddyconfig:/config
      - /mnt/caddylogs:/var/log/caddy
      - /mnt/jekyll-cadyy:/etc/caddy/html/
          - node.role == manager
      replicas: 1
        parallelism: 2
        delay: 10s
        condition: on-failure 
    driver: "local"
    driver: "local"
    driver: "local"
    driver: "local"
    external: true

Here I used the Official Caddy Alpine Docker Image. If you want to utilize custom DNS providers, I built a custom caddy docker container with plugins, like Cloudflare DNS, Caddy Auth Portal, etc…

Please find the custom caddy docker image below.

Tuneit Caddy Docker Image

Deploy Caddy Stack using Docker Compose

Now it’s time to deploy our docker-compose file above, caddy.yml using the below command

docker stack deploy --compose-file caddy.yml caddy

In the above command, you have to replace caddy.yml with your docker-compose file name and caddy with whatever name you want to call this particular application

As mentioned earlier I named my docker-compose as caddy.yml and named my application stack as caddy

Check the status of the stack by using docker stack ps caddy

Check caddy stack logs using docker service logs caddy_caddy

One thing we observe is that it automatically re-directs to https with Letsencrypt generated certificate. The information is stored in /data directory.

I will be using this caddy stack as a reverse proxy / load balancer for the applications I am going to deploy to Docker Swarm Cluster.

Also I use docker network caddy to access the applications externally.

Access Jekyll Site

Now open any browser and type to access the site. You will be greeted with the Jasper Theme-based Jekyll site with automatic HTTPS.

Jekyll Site with Jasper Theme

If you enjoyed this tutorial, please give your input/thought on it by commenting below. It would help me to bring more articles that focus on Open Source to self-host.

Stay tuned for other deployments in coming posts… 🙄