Moving from GitHub pages to self-hosted
Initially, this blog was hosted with GitHub pages.
It’s a great way to serve static content via Jekyll, but it lacks any traffic analytics if you’re not willing to include it yourself, which I didn’t want to.
So I decided it’s time to move the blog to its own little space in the cloud.
Table of Contents
Advantage of self-hosting
The most significant benefit for me is having rudimentary traffic reports based on server logs without needing to include anything like Google Analytics. So I don’t even need a cookie notice, because the site won’t use any cookies!
Any external hosted source was also removed from the blog (like Google Fonts).
Sure, I lose some information about my users and can’t use a flashy UI like Google Analytics. But I strongly believe the privacy gains for my readers are worth it.
How did I do it?
Where to host
GitHub pages are free, and it’s hard to beat free.
But free often comes with some trade-offs.
If you’re willing to go with almost free as in “a cup of coffee per month”, there are plenty of options for non-high-traffic sites:
- Hetzner Cloud (~2.50 €)
- Linode (~5$)
- Digital Ocean (~5$)
- AWS Lightsail (~$3.50)
At my company, we’re using mostly Hetzner for our server-needs, so I’ve chosen the smallest Hetzner Cloud server at the time, the CX11.
With 1 vCPU, 2 GB RAM, 20 GB SSD, and 20 TB traffic, it’s more than capable of hosting my small, static-content blog.
Docker
Containers can make things easier, so first, we need Docker:
Dedicated user
Due to docker images using a dedicated user instead of root
, we need an additional user that is allowed to use docker
and sudo
Docker Compose
To handle our 2 containers at the same time we use [docker-compose](https://docs.docker.com/compose/)
.
Create a file docker-compose.yaml
with the following content:
What is happening here?
We defined 2 services, an Nginx web server, and a Certbot for creating/renewing our SSL certificate.
The mapped volumes should be created before starting the containers, or the docker daemon will create them as root
, which might lead to permission errors later on.
Nginx
Create ~/docker-data/nginx/conf.d/site.conf
and replace <your domain>
:
We configured port 80 to accept 2 locations:
/.well-known/acme-challenge
: needed for certbot/
: redirect non-https to https
The actual https-server isn’t configured yet, because Nginx won’t start without the actual SSL certificate, but we need Nginx up and running to request them.
Start the containers:
SSL
To request an SSL certificate, we need to run certbot:
Use the follwing answers:
- webroot (2)
- your domain names (without and with www)
- /var/www/certbot
Now you have an SSL certificate!
Add the following location into your Nginx config file and replace <your domain>
:
Redirect https www to non-www
Restart the containers:
Auto-deploy on git push
One of the advantages of GitHub pages is the auto-deployment as soon as you push something to the repository.
Let’s recreate this for our server!
Makefile
To simplify the different steps I’ve created a Makefile, which incidentally requires you to have make
installed:
Make sure to use tabs for indention, not spaces.
Just a wrapper around jekyll
with added rsync
to the correct location.
A simple make deploy
is now all we need to build and deploy our website.
Git hook
To not call git pull -r
and make deploy
manually on the server every time we have some changes we need to allow the repository to receive data even if it’s not a bare repository:
This way, the repository will update the working directory on receiving a push instead of denying it.
Adding a post-receive
hook will trigger the make deploy
, so create <repo path>/.git/hooks/post-receive
with a small script inside:
Now every time you push to the repository (e.g. as an additional origin) the site will be automatically generated and deployed.
Log rotation
Without Google Analytics we can analyze our log files, so lets rotate them:
Create /etc/logrotate.d/nginx-site
with the following content:
logrotate
scripts will be run automatically by cron
, and with this config, our logs will be rotated monthly, and 12 rotations will be kept. You could also choose to use weekly
or daily
to increase granularity.
That’s it… enjoy your self-hosted blog!