Setting up Hetzner Server for Website Hosting

Published: Sep 2, 2020

This post feature image

Some scratch notes on setting up a Hetzner VPS to run docker-based Flask projects, static websites, and more using Caddy as a reverse proxy.

Purchase Cheapest Cloud VPS from Hetzner

Their Falkenstein, Germany location gave me the best ping times, so I chose that one. At €2.49/month for a KVM-based VPS with 2GB RAM, 1 vCPU, and 20GB SSD, this was cheaper than my previous preferred European provide, Time4VPS.

I chose a Debian 10 Buster image. It was deployed within seconds (no account verification needed… and didn’t even have to pay yet). They didn’t provide a root password, but luckily they have a section in their web panel that allows adding an SSH key. Put in my public key and logged in as root via SSH.

Initial Setup…

Let’s setup a sudo user, aliases, and initial installs

adduser <my_user_name>
usermod -aG sudo <my_user_name>

sudo apt update
sudo apt install apt-transport-https ca-certificates curl \
software-properties-common mc htop tmux gcc g++ libc6-dev

Update .bashrc to enable my favorite alias with this line: alias ll='ls -alF'

Also, since the Hetzner SSH key web interface puts the authorized key into the root space, I had to copy it to my user space and change owner:

sudo cp /root/.ssh/authorized_keys /home/<my_user_name>/.ssh/authorized_keys
cd ~/.ssh
sudo chown <my_user_name> authorized_keys
sudo chgrp <my_user_name> authorized_keys

Some SSH Setup

Create a private/public key pair:

ssh-keygen -t rsa

Update /etc/ssh/sshd_config with the following:

PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes

Install Docker:

Get Docker repositories into apt sources, then install:

curl -fsSL | sudo apt-key add -
sudo add-apt-repository \
"deb [arch=amd64] buster stable"
sudo apt update
sudo apt install docker-ce docker-ce-cli

Install Gitlab Runner:

Get Gitlab repositories into apt sources, then install. Replace the url with

curl -L \
<url>/ \
| sudo bash
sudo apt update
sudo apt install gitlab-runner

Delete or rename .bash_logout under the gitlab-runner userspace:

cd /home/gitlab-runner
mv .bash_logout .bash_logout_rename

Add gitlab-runner to the docker group so it can run build and deploy jobs:

sudo usermod -aG docker gitlab-runner

If you are ready to register this VPS with a Gitlab project, then do this:

sudo gitlab-runner register # I chose shell as exectutor

Install Go

Get binary and install:

sudo tar -C /usr/local -xzf go1.14.3.linux-amd64.tar.gz

Add Go path to path in .profile:


Install Hugo

The best static site generator is Hugo. The best way to install the latest version is from source:

mkdir $HOME/src
cd $HOME/src
git clone
cd hugo
go install --tags extended

It will put the hugo binary in ~/go/bin, although I like to move it to /usr/local/go/bin. It will also leave a bunch of files in a download cache in ~/go/pkg. Clean it up with:

go clean -modcache

Install Caddy

Get binary and install:

echo "deb [trusted=yes] /" \
| sudo tee -a /etc/apt/sources.list.d/caddy-fury.list
sudo apt update
sudo apt install caddy

I like creating a ~/caddy directory and putting Caddyfile inside. An example of using it for a reverse proxy:

# Add gzip compression to requests
(webconf) {
  encode gzip
} {
  tls [email protected] # For automatic Let's Encrypt SSL certificates
  import webconf

It’s nice having a hard-linked file in my user space while still having it in Caddy’s system startup space:

cd /etc/caddy
sudo mv Caddyfile Caddyfile_bak
sudo ln ~/caddy/Caddyfile /etc/caddy/Caddyfile

Caddy will automatically start when the system is started and will load the Caddyfile that is hard-linked to my user space Caddyfile.

How is this VPS Used?

Basically, gitlab-runner is registered to a project (i.e. Flask application) that is designed to run out of a Docker. And build and deploy scripts are called in the .gitlab-ci.yml file of the respective repository. This server will take care of the rest.

Previous Post

Netlify's Awesome Build Process

Well I went and moved all of my static websites from AWS S3/Cloudfront to Netlify.