Jekyll, Docker, and Nginx Reverse Proxy for Static Blogs


I have no self control, so last week I bough I’m probably going to use it as a home for some sustainable energy/micro-grid/open hardware projects.

In any case, I thought I would use Jekyll to host a fairly unchanging static site. I’d found a theme I really liked, and some projects I’ve seen lately ( have made me more aware of the burden a really heavy site can have on the internet, and on users that don’t have a great connection. (Spoiler: is currently sitting at about 250kb of transfer, most of that Javascript and CSS, as opposed to the 3mb of the front page of this blog).

Here’s what I started out with:

Docker config

Here’s the docker-compose.yml the Jekyll Docker image recommends:

What are all the ports for? Digging into the Jekyll docs, it’s fairly simple to find that:

  • 4000 is the default port that Jekyll uses to serve pages via the jekyll serve command
  • 35729 is the port used by livereload, which you may or may not use? I’m not using it.
  • 3000? IDK
  • 80 is just remapping port 4000 externally.

nginx-proxy takes care of all the port issues, though, and uses internal networks to route the reverse-proxy HTTP traffic, so we don’t actually need to expose anything but 35729. We do need to tell nginx-proxy that we’re running on port 4000, though, and not port 80.

I had problems with jekyll simply returning 0 if I tried to cache gems. So I had to remove the gem caching directory. I couldn’t find any bug reports for this issue, and cached gems aren’t necessary (they speed up the initial load time of the container). Later, I discovered that in order for relative URLs to resolve properly, you must run jekyll in “production” mode (default mode is “development”), so I also added an environment variable to bring up jekyll in “production” mode. The final docker-compose.yml looks something like this:

The config sections for nginx-proxy and nginx-letsencrypt are really, really, really exactly from the tutorials for those two containers. They work really incredibly well, and I can’t recommend those two packages enough.

They key things are to include, in each proxied container:

    • This is a comma separated list of what URLs nginx will proxy. This means any incoming request for or will go to this container.
    • Same, but for pulling Let’s Encrypt certificates
    • Email address for bothering you if Let’s Encrypt fails for some reason. I haven’t had a failure yet, so I actually don’t know how well this function works!

Jekyll Bring-up

Okay, home free, right?

The jekyll docs and the docs included with the jekyll docker container are pretty unclear about bringing up a new site. The instructions read:

docker-compose run site jekyll new mysite, which works. But jekyll won’t, by default, be able to get to the generated _config.yml, so when you run docker-compose exec site jekyll build later,  you’ll get a bunch of errors, and a half-built site. Additionally, the half-built site will live at https://[YOURURL]/mysite, and you PROBABLY want it to live at https://[YOURURL]/.

What you really want to run is docker-compose run site jekyll new . which creates a new site at the root directory.

Now you end up with a _config.yml file at the /PATHTO/srv/ directory configured in the docker-compose.yml:

Most importantly, configure the “url” to the correct url, and you should be off to the races, and caught up with all the other Jekyll documentation that lives on the internet!

Any time you change your _config.yml, you’ll have to restart the jekyll container (docker-compose restart [containername]), but otherwise, changes will auto-refresh!

Add comment