This article contains affiliate links. We may earn a commission if you purchase through them, at no extra cost to you.
You read the comparison article, ran the numbers, and decided Hetzner Cloud is your answer. Smart move. A CX22 instance (2 vCPU, 4GB RAM) costs roughly €4.35/month — that’s the same spec that’ll run you $24/month on DigitalOcean. The savings are real and the performance holds up. But Hetzner’s UI and onboarding experience is noticeably more barebones than what you get from managed platforms, and if you’re coming from Heroku, Railway, or Render, there’s a learning curve that nobody warns you about.
This guide closes that gap. By the end, you’ll have a production-ready Hetzner Cloud server: hardened SSH, a non-root user, UFW firewall, Nginx reverse proxy, and a deployment pipeline that doesn’t make you want to quit programming. I’m writing this from actual experience running six side projects on Hetzner across two years — including the painful migration story you can read about in how I mass-migrated 14 projects off Heroku.
Quick Picks: What You’ll Need
- Account: Hetzner Cloud (cloud.hetzner.com) — verification takes 10–30 minutes
- Local tools: SSH client,
hcloudCLI (optional but recommended) - Server type: CX22 for most side projects, CCX13 if you need dedicated vCPUs
- OS: Ubuntu 22.04 LTS — widest support, most Stack Overflow answers
- Time to complete: ~45 minutes for a clean, production-hardened setup
If you’re still evaluating whether Hetzner is the right call, check out the full DigitalOcean vs Hetzner vs Vultr comparison first — it’ll save you from choosing the wrong tier.
Step 1: Create Your Hetzner Cloud Account and Project
Go to cloud.hetzner.com and sign up. Hetzner requires identity verification before you can spin up servers — this is the one friction point that trips people up. Upload your ID, wait. It’s usually under 30 minutes during business hours (they’re a German company, so factor in CET timezone). Don’t start this at 11pm on a Friday expecting to deploy by midnight.
Once verified, create a Project. Projects are Hetzner’s way of grouping resources — think of them like workspaces. I keep one project per client and one for personal stuff. This matters later for API tokens and SSH key scoping.
Inside your project, go to Security → SSH Keys and add your public key before you create any server. This is the move. If you add it here first, Hetzner will inject it into every new server automatically. To get your public key:
cat ~/.ssh/id_ed25519.pub
If that file doesn’t exist, generate a key pair first:
ssh-keygen -t ed25519 -C "your@email.com"
Use Ed25519, not RSA. It’s faster, shorter, and more secure. Copy the output of the cat command and paste it into the Hetzner SSH key form.
Step 2: Spin Up Your First Server
Click Add Server. Here’s exactly what to pick:
- Location: Falkenstein (FSN1) or Nuremberg (NBG1) for Europe; Helsinki (HEL1) for slightly better latency to Eastern Europe/Asia. Ashburn (ASH) and Hillsboro (HIO) are the US options — latency from the US East Coast to FSN1 is around 100ms, which is fine for most apps but not great for latency-sensitive APIs. If your users are primarily in the US, use ASH.
- Image: Ubuntu 22.04 — don’t overthink this. Debian 12 is also solid if you prefer it.
- Type: Shared vCPU (Intel or AMD) for dev/side projects. CX22 (€4.35/mo) is the sweet spot. If you’re running something with consistent CPU load — a Node.js API with heavy processing, a Python ML endpoint — go CCX13 (dedicated vCPU, €12.49/mo).
- SSH Keys: Select the key you just added.
- Firewalls: Skip for now — we’ll set this up manually with UFW for more control.
- Volumes/Networks/Backups: Enable Backups (+20% of server cost). It’s cheap insurance. Skip Volumes unless you need persistent block storage separate from the server.
Hit Create & Buy Now. Your server will be ready in about 15 seconds — Hetzner’s provisioning speed is genuinely impressive.
Get the dev tool stack guide
A weekly breakdown of the tools worth your time — and the ones that aren’t. Join 500+ developers.
No spam. Unsubscribe anytime.
Step 3: Initial Server Hardening
You’ll get an IP address in the Hetzner dashboard. SSH in as root:
ssh root@YOUR_SERVER_IP
The first thing you do on any new server is stop using root. Create a deploy user:
adduser deploy
usermod -aG sudo deploy
Copy your SSH key to the new user:
mkdir -p /home/deploy/.ssh
cp ~/.ssh/authorized_keys /home/deploy/.ssh/
chown -R deploy:deploy /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys
Open a second terminal and verify you can SSH in as deploy before you lock anything down:
ssh deploy@YOUR_SERVER_IP
Good? Now harden SSH. Edit /etc/ssh/sshd_config:
sudo nano /etc/ssh/sshd_config
Change or add these lines:
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
Port 22
I leave SSH on port 22. The “security through obscurity” argument for changing ports is weak, and it adds operational friction. Use fail2ban instead (covered below). Restart SSH:
sudo systemctl restart sshd
Verify your deploy SSH session still works. If it does, you’re good. If not, you still have the root session open — fix the config before closing it.
Step 4: Firewall with UFW
Hetzner has a cloud firewall you can configure in the UI, but I prefer UFW on the server itself — it travels with the server if you snapshot it, and it’s easier to script.
sudo apt update && sudo apt install ufw -y
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
Check the status:
sudo ufw status verbose
If you’re running a database that needs external access (you probably shouldn’t, but if you are), add the specific IP rather than opening the port to the world:
sudo ufw allow from YOUR_OFFICE_IP to any port 5432
Step 5: Install fail2ban
This is non-negotiable. Within minutes of a new server being live, bots will start hammering SSH with credential stuffing attacks. fail2ban watches the logs and bans IPs that fail too many times:
sudo apt install fail2ban -y
sudo systemctl enable fail2ban
sudo systemctl start fail2ban
The defaults are fine for most use cases — it bans IPs after 5 failed SSH attempts for 10 minutes. If you want to be more aggressive, create /etc/fail2ban/jail.local:
[sshd]
enabled = true
bantime = 1h
findtime = 10m
maxretry = 3
Restart fail2ban: sudo systemctl restart fail2ban
Step 6: Install Nginx as a Reverse Proxy
Most apps shouldn’t be exposed directly on port 80/443. Run Nginx in front of them:
sudo apt install nginx -y
sudo systemctl enable nginx
Create a site config. Replace yourdomain.com and the upstream port with your actual values:
sudo nano /etc/nginx/sites-available/myapp
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
}
}
Enable it:
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 7: SSL with Certbot
Free SSL, no excuses:
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Follow the prompts. Certbot will automatically modify your Nginx config to handle HTTPS and set up auto-renewal. Verify the renewal timer is active:
sudo systemctl status certbot.timer
Step 8: Deploy Your Application
This varies by stack, but here’s the pattern I use for Node.js apps with PM2:
sudo apt install nodejs npm -y
sudo npm install -g pm2 n
sudo n lts # installs latest LTS Node.js
Clone your repo, install dependencies, build:
cd /home/deploy
git clone https://github.com/youruser/yourapp.git
cd yourapp
npm install
npm run build # if applicable
Start with PM2:
pm2 start npm --name "myapp" -- start
pm2 startup
pm2 save
PM2 will now restart your app on server reboots. For Python apps, use gunicorn + systemd service instead — the pattern is similar but PM2 doesn’t handle Python as cleanly.
Step 9: Set Up the hcloud CLI (Optional but Powerful)
The Hetzner CLI lets you manage everything from your terminal. Install it:
# macOS
brew install hcloud
# Linux
wget https://github.com/hetznercloud/cli/releases/latest/download/hcloud-linux-amd64.tar.gz
tar -xzf hcloud-linux-amd64.tar.gz
sudo mv hcloud /usr/local/bin/
Create an API token in the Hetzner Cloud Console (Security → API Tokens → Generate API Token, read/write). Then:
hcloud context create myproject
# paste your API token when prompted
Now you can do things like:
hcloud server list
hcloud server reboot my-server
hcloud snapshot create --server my-server --description "pre-deploy-$(date +%Y%m%d)"
That last command — snapshotting before a deploy — is the kind of thing that saves you at 2am. I have it as a pre-deploy hook in my CI pipeline.
Hetzner Cloud Pricing Breakdown (2026)
| Instance | vCPU | RAM | Storage | Price/mo | Best For |
|---|---|---|---|---|---|
| CX11 | 1 (shared) | 2GB | 20GB SSD | ~€3.29 | Static sites, tiny APIs |
| CX22 | 2 (shared) | 4GB | 40GB SSD | ~€4.35 | Most side projects, staging |
| CX32 | 4 (shared) | 8GB | 80GB SSD | ~€7.52 | Production apps, small DBs |
| CCX13 | 2 (dedicated) | 8GB | 80GB SSD | ~€12.49 | CPU-consistent workloads |
| CCX23 | 4 (dedicated) | 16GB | 160GB SSD | ~€23.99 | High-traffic production |
Backups add 20% to server cost. Snapshots are €0.01/GB/month. Outbound traffic is free up to 20TB/month on most instances — this is where Hetzner absolutely murders the competition. DigitalOcean gives you 1–4TB before charging; Hetzner gives you 20TB. For bandwidth-heavy apps, this difference is massive.
Common Gotchas and How to Avoid Them
Gotcha 1: IPv6-only by default on some configs. Hetzner assigns both IPv4 and IPv6 by default, but if you’re setting up private networks, make sure your app binds to the right interface. Run ip addr show to see what’s assigned.
Gotcha 2: The cloud firewall vs UFW confusion. If you enable both Hetzner’s cloud firewall AND UFW, you can end up with confusing double-filtering. Pick one. I use UFW and leave the cloud firewall disabled for single-server setups. For multi-server architectures, use the cloud firewall for inter-server rules and UFW for the OS-level stuff.
Gotcha 3: Shared vCPU throttling. The CX-series uses shared vCPUs. Under sustained CPU load, you’ll get throttled. This is fine for most web apps (which are I/O-bound, not CPU-bound), but if you’re running anything CPU-intensive in a loop, go CCX. I learned this the hard way running a PDF generation service on a CX22 — it was fine under normal load and fell apart under concurrency.
Gotcha 4: Hetzner’s abuse team is aggressive. They’ll suspend servers that generate unusual traffic patterns — even legitimate ones like email sending or port scanning your own IPs. If you’re running anything that looks like abuse, open a support ticket proactively. Their support is responsive but the automated suspension system is hair-trigger.
Use Hetzner Cloud If…
- You’re running side projects or indie apps where cost matters significantly
- Your users are primarily in Europe
- You’re comfortable with Linux server management (or willing to learn)
- You need high bandwidth without paying per-GB fees
- You want bare metal performance at VPS prices for specific workloads
Consider an Alternative If…
- You need a managed Kubernetes experience (Hetzner’s K8s is functional but rough around the edges compared to GKE/EKS)
- Your users are primarily in Asia-Pacific (Hetzner has no APAC presence)
- You want a polished managed database service — Hetzner’s managed DBs exist but are limited compared to DigitalOcean’s managed databases, which support more engines and have better tooling
- You’re on a team that needs enterprise SLAs and support contracts
For a broader look at your options, the best cloud hosting for side projects guide covers the full landscape including managed platforms.
Automating Your Hetzner Setup
Once you’ve done this manually once, automate it. I maintain a bash script that runs all the steps above — hardening, UFW, fail2ban, Nginx, Certbot — on a fresh Ubuntu server. You can also use cloud-init via Hetzner’s “User data” field when creating a server, which runs scripts at first boot.
Here’s a minimal cloud-init example that creates the deploy user and sets up UFW automatically:
#cloud-config
users:
- name: deploy
groups: sudo
shell: /bin/bash
sudo: ['ALL=(ALL) NOPASSWD:ALL']
ssh_authorized_keys:
- ssh-ed25519 YOURPUBLICKEY your@email.com
packages:
- ufw
- fail2ban
- nginx
runcmd:
- ufw default deny incoming
- ufw default allow outgoing
- ufw allow ssh
- ufw allow 80/tcp
- ufw allow 443/tcp
- ufw --force enable
Paste this into the “User data” field when creating a server. Your server will come up pre-hardened. This is the move when you’re spinning up multiple servers or want reproducible infrastructure.
If you’re using AI tools to help write your infrastructure scripts or documentation, I’ve found the tools covered in our best AI tools for developers roundup genuinely useful for generating boilerplate config and explaining unfamiliar Linux commands.
Final Recommendation
The Hetzner Cloud setup process isn’t magic, but it’s not complicated either. The 45 minutes you spend on initial hardening pays dividends for years. The cost savings over AWS, GCP, or even DigitalOcean are real enough to matter — especially if you’re running multiple projects or a bootstrapped product where every dollar counts.
The honest caveat: Hetzner rewards developers who are comfortable in the terminal and don’t need hand-holding. If you’re used to Heroku-style deploys and the idea of managing Nginx makes you nervous, consider starting with a managed platform and migrating once you’ve built the muscle memory. The full comparison between Hetzner, DigitalOcean, and Vultr covers where each one actually wins.
But if you’re ready to own your infrastructure and stop paying managed-platform tax? Hetzner is the best value in cloud hosting in 2026. This guide gives you everything you need to go from zero to production-ready in under an hour. The rest is just shipping.
Get the dev tool stack guide
A weekly breakdown of the tools worth your time — and the ones that aren’t. Join 500+ developers.
No spam. Unsubscribe anytime.