Set Up a $4/mo Hetzner VM to Skip the Serverless Tax
- Updated on
In the world of cloud computing, the costs can quickly add up, especially when using serverless architectures. However, with a little effort, you can set up a virtual machine (VM) on Hetzner for just $4 a month, allowing you to bypass the "serverless tax." and have full control over your server. In this tutorial, we'll walk through setting up a VM on Hetzner, installing Caddy for SSL, configuring Cloudflare for DNS, and deploying a web app using Github.
This tutorial is made for beginners ― you only need to be somewhat comfortable with the command line.
It is made as short as possible and avoids using e.g. Docker to keep things simple. Once you feel comfortable with this setup, you should consider using Docker for easier management or automatically deploying from Github with a webhook.
Let's do this.
Pre-requisites
Before diving in, make sure you have the following:
- Buy a domain: This is where every good idea starts.
- Generate an SSH key:
- copy the .pub part somewhere handy.
- remember the password you set during the key generation.
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519_hetzner
This will allow secure access to your VM.
You need a domain to host your application and set up SSL. I like to use Cloudflare, but you can use any domain registrar you like. We'll use Cloudflare for it's security features later, so this'll make things easier.
Initial Setup
- Register on Hetzner Cloud and buy a server:
- You can register quickly with a PayPal pre-purchase.
- Use a company email rather than a personal one.
- After creating the server, copy the IP address for later use.
- Set up on Cloudflare: If you don't have an account, create one.
- Add a new site using the domain you purchased.
- Add an A record with the name "@" and the IP address you copied from Hetzner.
- Under SSL/TLS settings, ensure the encryption mode is set to "Full."
Why is this good? Cloudflare will cache your site and protect it from DDoS attacks and much more, free.
It must sound like they pay me. I wish. It's just a good service.
Configure your domain and add SSL with Caddy
SSL (https) is a must-have for any website. Caddy is a web server that automatically manages SSL certificates for you. It's easy to set up and use. Let's take a look.
SSH into your server (login to your server)
ssh -i ~/.ssh/id_ed25519_hetzner root@<server-ip-address>
Install Caddy
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy
Enable on boot
sudo systemctl start caddy sudo systemctl enable caddy
Add domain; Open the Caddy config file
nano /etc/caddy/Caddyfile
And replace the contents with the below (note: port is set to 3000, you might want to change that):
your_domain.com, www.your_domain.com { reverse_proxy localhost:3000 }
Replace
your_domain.com
with your domain.Restart to apply changes
sudo systemctl reload caddy
Caddy automatically obtains and renews SSL certificates for your domain using Let's Encrypt. No extra steps are needed for HTTPS.
"Integrate" a Github Repo
We'll set up a simple "deployment" method that requires you to pull changes manually from GitHub. It's not the most efficient, but it does the job.
Generate another SSH key, but this time on the Hetzner server. You should already be logged in otherwise, SSH into your server again.
ssh-keygen -t ed25519 -C "your_email@example.com" -f ~/.ssh/id_ed25519_github
Get .pub part of the SSH key & copy it to clipboard. Look at you go you're basically a pro now.
cat ~/.ssh/id_ed25519_github.pub
Add SSH key to Github
- Go to Settings -> SSH and GPG keys
- Press New SSH Key
- Type a title e.g. "Hetzner" and paste the contents of
- Press Add SSH key
Now let's "tell" the server to use this key when pulling from Github. Open the SSH config file
nano ~/.ssh/config
And add the following:
Host github.com HostName github.com User git IdentityFile ~/.ssh/id_ed25519_github
Clone your repo
git clone git@github.com:<username>/<repo-name>.git
That's it! Now you can cd <repo-name>
and git pull
to get the latest changes from your repo to "deploy" your app again.
[Bonus] Get an app running with automatic restart (Node.js)
You've made it this far, but what if you don't have an app to deploy? Let's set up a simple Node.js app that restarts automatically when it crashes.
Say we have this simple express app in app.js
:
const express = require('express');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
res.send('Hello World!');
});
A bit low on energy?
Deploy a beautiful web app, landing page and blog with a click (serverless 🙈).No? Okay. Let's get back to self-hosting. Had to try.
Install node & npm (if not already installed)
sudo apt update curl -fsSL https://deb.nodesource.com/setup_lts.x | sudo -E bash - sudo apt install nodejs
(Verify by running
node -v
)Install pm2 (process manager)
sudo npm install -g pm2
Run app
pm2 start app.js --name "my-node-app"
Save & set up to run at startup
pm2 save pm2 startup
Now open
your_domain.com
in your browser and you should see "Hello World!"Check status and logs via:
pm2 status pm2 logs
If the server crashes for any reason, pm2 will restart it automatically. Pretty neat, huh?
Remember: this should be running on port 3000, as per the Caddy config we set up earlier.
Wrap-up
You've set up a $4/mo Hetzner VM with SSL, DNS, a domain, and a web app. You've also learned how to deploy changes from Github and set up a simple Node.js app that restarts automatically.
This is not rocket science and it's a great starting point for hosting your own web apps. Once you get comfortable with this setup, you can add Docker so you can replicate the environment easily or set up a webhook to automatically deploy changes from Github.
Is there something specific you'd like to learn more about? Did we miss a tool?
How about setting up multiple servers? What about a SSR app like Next.js?
Reach out on Twitter/X or reach out on this website with your feedback!
Tools
You might also want to check out:
- Coolify - nice way to deploy Next.js apps. Also see this Coolify tutorial.
- Cloudflare Tunnels - for exposing your local server to the internet.