Happy Path

Hetzner setup new VPS

My existing VPS has been running CentOS Linux 8.2, which has reached end-of-life, discontinued even, on . Not having an in-place distro upgrade available presented a nice opportunity to try a different distribution. Since this might occur again a few years from now, keeping notes for future reference.

SSH key

Create SSH key using ssh-keygen on Windows.

> ssh-keygen -f key
Your identification has been saved in key.
Your public key has been saved in key.pub.

Note that this will generate OpenSSH keys, not PuTTy format. We will see later that WinSCP needs to convert the key to PuTTy format.

Create server

Add server in Hetzner Cloud Console.

  • Location Nuremberg eu-central
  • Image Ubuntu 22.04
  • Shared vCPU x86 CX11, € 3.98/mo
  • Uncheck Public IPv4 (save € 0.61/mo)
  • Add the public SSH key

Click Create & Buy now. Allow a minute for the minute to complete booting. In this example, assume the assigned IPv6 address to be 2001:db8:3333:4444:5555:6666:7777:8888.

Login to server

Use the private SSH key to connect.

> ssh root@2001:db8:3333:4444:5555:6666:7777:8888 -i key

Update packages

$ sudo apt update
$ sudo apt upgrade
$ sudo reboot

Install nginx

$ sudo apt install nginx

$ nginx -v
nginx version: nginx/1.18.0 (Ubuntu)

$ sudo ufw app list
Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS

$ sudo ufw allow 'Nginx Full'
Rules updated
Rules updated (v6)

By now, the server is hosting webpages, and can be accessed via client browser by visiting http://[2001:db8:3333:4444:5555:6666:7777:8888]/.

The contents for the default website are stored under /var/www/html, and nginx config can be found under /etc/nginx/.

Setup nginx

Let's setup virtual hosts, to allow hosting multiple websites from the same server.

$ vi /etc/nginx/sites-enabled/website2
server {
    listen 80;
    listen [::]:80;

    server_name website2.com www.website2.com;

    root /var/www/website2;
    index index.html;

    location / {
       try_files $uri $uri/ =404;

$ sudo service nginx restart

There are now two websites accessible on port 80. Based on the incoming HTTP Request Header field, nginx decides which server processes the request. This requires DNS configuration.

Setup DNS

Type Host Value
AAAA Record @ 2001:db8:3333:4444:5555:6666:7777:8888
AAAA Record www 2001:db8:3333:4444:5555:6666:7777:8888

Allow some time for the DNS changes to propagate. Around 10-20 minutes typically worked, although worldwide may take longer.

Setup Let's Encrypt

There is an outstanding bug that prevents installing certbot using snapd on IPv6-only machines. Another option is to install certbot using pip.

$ sudo apt install python3 python3-venv libaugeas0
$ sudo python3 -m venv /opt/certbot/
$ sudo /opt/certbot/bin/pip install --upgrade pip
$ sudo /opt/certbot/bin/pip install certbot certbot-nginx
$ sudo ln -s /opt/certbot/bin/certbot /usr/bin/certbot
$ sudo certbot --nginx

SFTP access

Download WinSCP for Windows. Specify the generated private SSH key under Advanced -> SSH -> Authentication -> Private key file. WinSCP will prompt to convert the OpenSSH private key to PuTTy format. Save it as key.ppk in the same folder.