Skip Navigation

Scott Spence

Setting up my VPS on Hetzner

6 min read

Aight! So, I’ve gone off of Fly.io, great service, I’ll probably come back to it in the future, but, now I’m going to set up my own VPS on Hetzner.

There’s threads from Puru on him doing it but he expertly didn’t document what he did, so, I’m going through that now as I set up my own VPS on Hetzner.

Puru mentions his journey on Twitter:

I’m going to fill in the gaps.

VPS essentially means I’m now managing my own server instead of using a service like, Vercel, Netlify, or Fly.io and so on. So, there’s overhead in keeping my Ubuntu box (box being VPS server) up to date but I do that sort of the thing on the regular being a WSL (Ubuntu) user.

Why am I moving away from Fly.io? Well, reasons!

Setting up a Hetzner account

So, to use Hetzner I first need an account and a credit card (yes you have to pay up front!). Then there was the ID process where I had to scan in my ID for approval. All pretty straightforward.

Then I get access to the Hetzner dashboard and I can create a new server. The Create a Server page walks you through all the options, there’s a few options to pick from!

  • Location, pick from five locations, eu-central, eu-west, us-east,
  • Image, I went with Ubuntu 24.04
  • Type, I followed Puru’s lead and went with CAX11 shared CPU Arm64
  • Networking, defaults
  • SSH keys, created an SSH key and added the public key to the server
  • Volumes, empty
  • Firewalls, not configured, default
  • Backups, default
  • Placement groups, empty
  • Labels, empty
  • Cloud config, empty
  • Name, generated for me

To gen my SSH key I used the following command on my local machine:

ssh-keygen -t rsa -b 4096 -C [email protected]

That generates the public and private SSH keys, I copy pasted the public key to the Hetzner dashboard option, saved it and it’s ready to go.

Click the ‘Create & Buy now’ button and it’s up and running!

Now it’s a case of updating the server and securing it.

Logging in

So the first attempt to log into the box was straightforward enough I copied the IP address from the Hetzner dashboard and used the following command:

# ip-address is copied from the Hetzner dashboard
ssh root@ip-address

So, totally guessed that the username was root and because I’m using SSH I was signed straight in.

I’ll go ahead and update, upgrade and auto remove all the packages on the server with:

# autoremove removes packages that are no longer needed
apt update -y && apt upgrade -y && apt autoremove -y

Now I’m up to date I’ll start getting the box ready for use!

Ok, so it’s an IP address that anyone can access and yeah, there’s already bots trying to access the box! Using the following command:

tail -n 10 -f /var/log/auth.log

I start to see all the automated login attempts from bots trying to compromise the server.

So, I guess I’m pretty secure as it’s an SSH key to access the server, but I’ll check to see if there’s a password for the root user with:

passwd -S root

In the output it shows an L which (from what I can tell) means that the password is locked, so disabled password access. This will keep the box relatively secure.

Non root user

So I’m not logging into the box as the root user all the time I’m going to create a new user called me.

adduser me

This adds a new user called me and prompts me to assign it a password. I’ll set up another SSH key for this user as well.

First up, I’ll add the user to the sudoers group:

usermod -aG sudo me

Check the user is in the group:

groups me

It should show sudo in the output.

me : me sudo

I can now SSH into the box as the me user and I’m prompted to enter the password I assigned the account when I created the me account.

ssh me@ip-address

What I want to do now though is generate a new SSH key for the me user so that I can use it to access the server. Same as before to generate the keys.

ssh-keygen -t rsa -b 4096 -C [email protected]

This time specifying a different file path and name for the generated files.

Generating public/private rsa key pair.
Enter file in which to save the key (/home/me/.ssh/id_rsa): /home/me/.ssh/non_root_user

I’ll not be using the Hetzner dashboard to add the public key to the box, I’ll be using the authorized_keys file on the server this time.

Over on the server as the me user I’ll create the .ssh directory and then add the public key to the authorized_keys file.

mkdir .ssh
nano .ssh/authorized_keys

Nano will create the authorized_keys file for me, I’ll paste in the public key, write out the changes with Ctrl+o then Ctrl+x to exit.

I can then exit out of the server again and log in as the me user pointing to the non_root_user key.

ssh -i /home/me/.ssh/non_root_user me@ip-address

Disable password login

Aight, now I have my SSH login working I’ll disable password login on the non root user account.

There’s a sshd_config file with a couple of options I’ll be configuring, so, open the file:

sudo nano /etc/ssh/sshd_config

The option for password authentication I’ll change to no.

PasswordAuthentication no

Then I can exit out again, try logging in as the me user without the SSH key:

ssh me@ip-address

I get the following message:

Permission denied (publickey).

Meaning that I can only authenticate with the SSH key.

Disable login as root

Now to completely disable root login, I’ll need to edit the /etc/ssh/sshd_config file again as my me user.

# change from PermitRootLogin prohibit-password
PermitRootLogin no
# also add in the option to disconnect after a period of inactivity
ClientAliveInterval 300
ClientAliveCountMax 1

Validate the configuration with:

sudo sshd -t

If there are any errors then I’ll need to fix them.

As an example I didn’t leave a space in the permit root login option, here’s the validation message:

/etc/ssh/sshd_config line 33: no argument after keyword "PermitRootLoginno"
/etc/ssh/sshd_config: terminating, 1 bad configuration options

Then exit and try to log in as root and:

Permission denied (publickey).

Success!

Now it’s just my me user that I can log in as.

Conclusion

So, I’ve set up and secured my own VPS on Hetzner, this is just a starting point and there’s still a lot to do and configure. I’ll be playing around with this now to get things configured the way I want, still no node or any DNS set up just yet, but the intention is to do that using something like nvm and Caddy to handle that.

Then there’s the whole managing projects with GitHub and adding deploy keys so only that the server can access only that repo on GitHub.

So, possibly another two three posts on this! 😅

I’ll leave it at that for now though!

Further configuration

There’s a really comprehensive guide on the Hetzner community forum that covers a lot of additional options for Securing the SSH service that I’ve linked in the resources section.

For me, for now, I’m going to leave it where it is, for now.

Resources

Written content over on the Hetzner community forum:

There’s very comprehensive guides in video format from the Syntax team, I’m going to be checking out the Caddy one next:

There's a reactions leaderboard you can check out too.

Copyright © 2017 - 2024 - All rights reserved Scott Spence