Setting up Hetzner Server for Website Hosting

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

1adduser <my_user_name>
2usermod -aG sudo <my_user_name>
4sudo apt update
5sudo apt install apt-transport-https ca-certificates curl \
6  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:

1sudo cp /root/.ssh/authorized_keys /home/<my_user_name>/.ssh/authorized_keys
2cd ~/.ssh
3sudo chown <my_user_name> authorized_keys
4sudo chgrp <my_user_name> authorized_keys

Some SSH Setup

Create a private/public key pair:

1ssh-keygen -t rsa

Update /etc/ssh/sshd_config with the following:

1PermitRootLogin no
2PasswordAuthentication no
3PubkeyAuthentication yes

Install Docker:

Get Docker repositories into apt sources, then install:

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

Install Gitlab Runner:

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

1curl -L \
2 <url>/ \
3 | sudo bash
4sudo apt update
5sudo apt install gitlab-runner

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

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

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

1sudo usermod -aG docker gitlab-runner

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

1sudo gitlab-runner register # I chose shell as exectutor

Install Go

Get binary and install:

2sudo 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:

1mkdir $HOME/src
2cd $HOME/src
3git clone
4cd hugo
5go 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:

1go clean -modcache

Install Caddy

Get binary and install:

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

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

1# Add gzip compression to requests
2(webconf) {
3  encode gzip
4} {
6  reverse_proxy
7  tls # For automatic Let's Encrypt SSL certificates
8  import webconf

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

1cd /etc/caddy
2sudo mv Caddyfile Caddyfile_bak
3sudo 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.