Running Jekyll on Docker - For Easy Local Development

This website was create using Jekyll. If you wanna know more details, including how I am hosting this website on AWS S3 you can find all the details on How This Site Was Made article.

While working with Jekyll is super easy, the process of writing a post, building it, running a local server, having to use localhost:4000 every time, is not super optimal from my perspective and can be done easier.

A few pain points I noticed while writing posts in Jekyll:

  1. I have to start the server locally every time I want to write a post.
  2. Dealing with localhost and port numbers.
  3. I have to use a code editor to make the writing and building more convenient, although there might be better alternatives to only focus on the writing part.

In this article, I’m sharing with you an easy solution for the first 2 pain points.

Solution for: I have to start the server locally every time I want to write a post.

For this one, you can make use of Docker in order to create a docker image that once running will keep Jekyll’s server running with --livereload enabled for as long as you want. (I just leave it running all the time).

Fortunately, that’s not a hard task to accomplish.

Create a Dockerfile in the root of your project and copy the content below:

FROM ruby:3.0.1-slim

RUN apt-get update && apt-get install -y build-essential openssl bundler

RUN mkdir -p /www
WORKDIR /www

COPY Gemfile Gemfile.lock ./
RUN bundle install
COPY . ./

EXPOSE 4000

ENTRYPOINT ["bundle", "exec"]
CMD jekyll serve --host 0.0.0.0 --livereload

Note: In order to run Jekyll with Ruby 3.x you’ll have to add the Webrick gem to your Gemfile as Ruby 3+ does not bundle Webrick by default anymore. If you are using Ruby 2.x then it’s not necessary to add Webrick to your Gemfile.

gem 'webrick', '~> 1.7'

Latest version can be found at https://rubygems.org/gems/webrick.

Create the docker image by typing:

$ docker build -t image-name .

Wait for the process to finish and at the end your image will be ready to run!

Docker Image size
Docker image created with around 470mb in size.

Runing the image:

Before you run your docker container, you should create a mapping between your current working directory and the working directory inside the docker container so that you can edit the blog files locally and see the results immediately.

As we don’t have a multi-container application here, I recommend you do the mapping as part of the docker run command.

$ docker run --name container-name -dp 4000:4000 -v "$(pwd)":/www image-name

Wait the command to finish, and access localhost:4000 and you should be able to see your Jekyll website up and running :)

The best thing, if you edit an existing post or create a new one, you will be able to see it immediately on your browser :) Yay!!

Note: Live reloading, although enabled, is not triggering a reload on the hosting machine’s browser (your local machine), for now you’ll have to refresh the browser. If I find a solution for that I’ll update this post or if you know the solution, please share with me :)

Solution for: Dealing with localhost and port numbers.

I usually run multiple services on my machine assigned to different ports. Having to type the port on the browser’s address bar it’s not the most pleasant task to do. Adding a mapping to the etc/hosts file is not enough in this case as you cannot map ports there, just hosts.

Fortunately, again, there’s an easy solution for that. You can install and configure a reverse proxy such as Nginx to redirect a particular domain to a particular server on a specific port! That’s just what we want! Perfect! (There are other methods, but I find this one a very easy one).

Install Nginx:

$ brew install nginx

Configure a server for your local domain:

On Mac:

$ cd /usr/local/etc/nginx/servers

On Linux:

$ cd /etc/nginx/sites-available

Create a file with your domain name:

$ touch your-domain.local

Add the following content to your server file:

server {
    listen 80;

    server_name your-domain.local;

    location / {
        proxy_pass http://127.0.0.1:4000/;
    }
}

The configuration above is creating a virtual server in Nginx which will resolve the domain your-domain.local to the address http://127.0.0.1:4000/.

Now, start your Nginx server:

On Mac:

$ brew services start nginx

Note: If you want to stop Nginx for any reason:

$ brew services stop nginx

On Linux:

Replace brew services with sudo systemctl and start/stop with enable/disable.

Alternatively you can just use sudo systemctl reload nginx

Open the /etc/hosts file with your preferred text editor (will require admin privileges to save the file):

I’m using vi in the example below:

$ sudo vi /etc/hosts

Go to the end of the filePress i to enter in INSERT mode and add:

127.0.0.1 your-domain.local

Press ESC, :wq to write the change.

Now, head to http://your-domain.local in your browser and you’ll be able to access your Jekyll website running on Docker with live reload enable using a local domain!

That’s it, with this simple setup, you’ll be one step further to being able to only focus on writing your posts while enjoying the easiness of using Jekyll as your static site generator.


If you’re interested on video tutorials as well, I have a couple of them published on my Independent Pixels youtube channel. Check it our to see if you like it :)