Creating a Personal Website with Jekyll
If you’re someone like me and like to host various services, you might also want to have your own personal website. There are many approaches to this, for example you could use a CMS like WordPress or ghost, you could use a static site generator like Jekyll (that’s what GitHub Pages use) or you could program your own site if you want.
I’ve tried a bit of all of them, but it never really worked for me. Eventually I landed on Jekyll, so this is also where you’re reading this on now. To be honest, I don’t have too much expertise on the topic, but I made it work, and a Blog needs posts.
Pros of Jekyll
Dead Simple
Usage of Jekyll is really easy in my opinion. You kind of just write markdown files and add some front matter. That is if you’re using a pre-made template of course, you can make it as complicated as you want, just note that Jekyll generates static sites, so no fancy server side computation.
A lot of modern themes
There are a lot of modern and good-looking themes for Jekyll. At the time this post is written, cscherr.de uses chirpy.
A large collection of Jekyll themes can be found here (note: this site does not use HTTPS for some reason).
The ones I’d recommend:
- Chirpy - This is what this website uses too!
- Digital Garden - Excellent for notes instead of a blog, I’m customizing this for a private novel. This template even features a graph showing the relationships between the notes!
Insane extendability
As Jekyll is just a generator for static html pages, we can make use of the endless amount of web technologies without worrying how they will play with our backend. Want to use your favorite CSS framework, or even add your own CSS? No problem. Using existing template websites is easy too! Jekyll even has builtin SCSS support, which makes adding your own custom CSS much more comfortable.
Cons of Jekyll
Multilingual sucks
With the chirpy theme at least, I couldn’t get Multilingual content to work without going into the rabbit hole. You can select from a good amount of main languages, but you cannot have multiple versions of your website for various languages in a single project.
Various projects for multilingual Jekyll sites exist, but the only one that seems to be still maintained is polyglot.
Deployment with Docker
Docker is a really useful program that can be used to deploy many services, Jekyll too. I won’t go into the details here, but the idea is that your kernel runs a separate mini OS, which reproduces the same environment every time and streamlines deployment. It’s also good for security, as someone who takes over the webserver will only have the rights of the webserver inside the docker container, instead of on your real OS.
The “official” Jekyll Docker container is unmaintained since 2022, so if you want to deploy Jekyll with docker you need to create your own container. I based this on the standard ruby image.
We can use a Dockerfile
like this:
1
2
3
4
5
6
7
8
FROM ruby:3.4
WORKDIR /app
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
RUN git config --global --add safe.directory /app
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 4000
We need to mount our Jekyll project to /app
, it is not included with this Dockerfile.
1
2
3
4
5
6
7
#!/bin/bash
set -e
bundle install
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
In the entrypoint.sh
, we need to install the dependencies of our actual project. This will take a while…
We can then use a docker-compose.yml
file to deploy our config.
1
2
3
4
5
6
7
8
9
10
services:
jekyll:
build: .
volumes:
- .:/app
container_name: mysite
ports:
- 127.0.0.1:4000:4000
- 127.0.0.1:35729:35729
command: bundle exec jekyll serve --host 0.0.0.0 --port 4000 --livereload --watch
This is a docker compose file for a development environment. It may work for production, but it is likely inefficient and less secure.
The
--livereload
flag makes it so that your browser reloads everytime there is a change. This requires port35729
to be open.
Now you should be able to start the docker container with Jekyll inside by using docker compose up
. Access your site on localhost:4000.
Update
After running my site for a while, I have been made aware that basically just having jekyll serve
is maybe not the best way to do things. Jekyll also provides the command jekyll build
, which exports your website without all the data used to build it, so that any regular webserver can serve the static site.
Having a static website be built and then just be served as files, without an additional process seems to make more sense, so that’s what I will do from now on.
For that purpose, I have made a small build script:
1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
GID=$(id -g)
set -e
rm -rf _site
echo "
set -e
echo doing the building
JEKYLL_ENV=production bundle exec jekyll build --no-watch
rm -vrf /app/_site/docker* /app/_site/*.sh /app/_site/entrypoint.sh
chown $UID:$GID /app/_site -R
" \
| docker run -iv "$PWD:/app" krata /bin/bash
After this script, just serve the _site
directory with a webserver of your choice. (My recommendation is caddy)
If you do this, be careful not to let your webserver expose your
.git
directory, otherwise your (possibly private) repository gets leaked.
I’m still using docker to make sure the versions match. The ruby version in the repositories of my Linux Distribution is rather outdated and not suitable for building with jekyll. You don’t strictly need docker to build, but in my opinion at least, it makes things easier.
That being said, you definitely don’t need docker to actually make the site accessible.
To upload the build dir to the remote server, you may use the following script. You just need to have ssh access to a user that can control the webroot directory.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#!/bin/bash
UNIXTIME=$(date +%s)
DEPLOY_TO=cscherr.de
WEBROOT=/srv/caddy/site # if you unset this, everything will explode
TMP_FILE=$(printf "/tmp/%s_site.tar.gz" "$UNIXTIME")
set -e
echo building website
bash ./build.sh
echo making archive...
tar czf $TMP_FILE _site
echo uploading archive to $DEPLOY_TO : "$TMP_FILE"
scp $TMP_FILE $DEPLOY_TO:"$TMP_FILE"
echo installing archive in webroot: $WEBROOT
echo "
set -e
mkdir -p $WEBROOT
rm -rvf $WEBROOT/* $WEBROOT/.*
tar xvf $TMP_FILE --directory $WEBROOT
rm -vf $TMP_FILE
mv -fv $WEBROOT/_site/* $WEBROOT
rmdir -v $WEBROOT/_site
" \
| ssh $DEPLOY_TO /bin/bash
echo removing local upload file
rm -f $TMP_FILE
There we have it! Now we can make changes, run our deploy.sh
, and things are up to date on the webserver, without the need for docker stuff or something extra on the server.
If you have more questions, feel free to comment below or write me an E-Mail.