HOWTO: Host your jekyll site using apache web server

August 31, 2023

I finally have a personal blog just how I like it. I wouldn’t say it took a long time (just a couple of days) or that I’d rather have used an overkill alternative, like WordPress. But I should recognize that it wasn’t as easy as I thought it’d be. Besides the customizations I made to the theme I use, I think the main responsible of my suffering hosting this blog was apache.

And so I think that a guide of what to do to host a static site made in jekyll on a VPS with apache2 it’s a good idea for a first post, so let’s get to it. A heads up: I already assume that you have your jekyll site ready and you’re just looking on how to deploy it to your server, so I’ll omit the steps regarding a site’s generation.


  • A VPS, whether using a hosting provider like vultr or a PC turned on 24/7 in your home. Just be sure that it is accessible to the public internet (that it has a static public IP), which is the most important aspect of a web server.
  • Some linux distro installed in your server. I personally use Debian, but the instructions presented here are distro-agnostic.
  • Apache2
  • Ruby; I recommend rbenv


If you wish to host your site in the apache’s main directory (in the case of debian, it’s /var/www/html/), and, as a consequence, in your main domain (not a subdomain) then there’s no extra configuration besides the one I’ll show. If instead you’ll host your blog on a subdomain, just beware that there’re certain things to have in mind, like your server’s name and the directory that’s going to store your blog files.

I was looking for two things when setting up my server: internationalization and pretty URLs. The configuration I’ll show takes into consideration these two points, and it achieves them through mod_rewrite:

<VirtualHost _default_:443>

	DocumentRoot /var/www/html/
	DirectoryIndex index.html	
	RewriteEngine On
	RewriteRule ^/(page[1-9]+)$ %{DOCUMENT_ROOT}/$1/index.html
	RewriteRule ^/en/(page[1-9]+)$ %{DOCUMENT_ROOT}/en/$1/index.html
	RewriteRule ^/en/$ %{DOCUMENT_ROOT}/en/index.html
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteCond %{REQUEST_FILENAME} !-d	
	RewriteRule ^([^\.]+)$ $1.html [NC,L]
	ErrorDocument 404 "/not-found"

	ErrorLog ${APACHE_LOG_DIR}/error.log
	CustomLog ${APACHE_LOG_DIR}/access.log combined

The first two rules relate to pagination, using the jekyl-paginate rubygem. If you won’t use pagination, you can omit it. Although I recommend you use it.

The second one is a doozy, for now I’ll only host the blog in english and spanish, although if I wish to, in the future, add a third language, like french, I could change the regex to:


The same for the next one, which only takes care of serving the index of every internationalized index version. The last three rules take care of pretty URLs (URLs without the file extension, e.g. about-me instead of about-me.html)

The last configuration (ErrorDocument) is the page the server’ll show every time there is a 404 status response. Chances are the theme you’re using for your blog already has one, and if not, it’s worth it to create one because the apache’s default “Not found” page isn’t particularly pleasing.

User permissions

The /var/www/html directory usually belongs to the group (and user) www-data (in other distros this user is called apache), but if you like you can add yourself to this group or even better, become the owner. Be mindful of security though, this directory usually belongs to the root or www-data user, so it’s probably worth it to create an user just for this and nothing else, and to not have anything sensible in your /var/www/html directory, besides your blog’s files:

sudo chown -R $(whoami) /var/www/html

I did this because it’s useful if you wish to use git hooks, so that with every change you push, the site will update automatically, so it behaves like a dynamic site, like a WordPress instance for example.

Deploy hook

If you use a special user as the owner of your git repos, like me (my git user in my VPS doesn’t have access to an interactive shell for example) then you can add another remote repo and point towards it:


git --bare init your_blog.git
cd your_blog.git
touch hooks/post-receive

Client (where you write your posts)

git remote add deploy
git push deploy

Post-receive script

Now, the script that’ll be executed everytime you push any changes is the following, courtesy of the jekyll docs. I modified it as I use rbenv, it’ll be the same for you if you use it as well, but if you installed ruby and bundler with, for example, your package manager, then you won’t have to add your rubygems’ directory to your PATH, but if you installed ruby in any other way, it’ll be required.

#!/bin/bash -l

export GEM_HOME=$HOME/.rbenv/shims/

PUBLIC_WWW=/var/www/html # Use the directory apache uses for serving your blog.

BUNDLE_GEMFILE=$GEMFILE bundle exec jekyll build -s $TMP_GIT_CLONE -d $PUBLIC_WWW


Well, that was the setup of my website. I personally think there is a technical barrier to using jekyll, and it’s a shame because it covers a lot of use cases pretty well, but us technical users sometimes forget that what could be easy for us, like a git push, it’s kind of black magic to others, and let’s just not talk about that giant apache config file or having to write a git hook. Nevertheless, I enjoy jekyll, I enjoyed this process and I hope you do, too.