๐ก๏ธ How I Built a Full Production Backend on Hetzner VPS (As a Total Noob)
๐ Hi, I'm G โ I Had No Clue What I Was Doing
Before this adventure, I had zero background in DevOps. No fancy degree. No prior experience in systems administration. No clue what SSH even meant. Just a laptop, a burning curiosity, and a wild idea: could I actually host my own backend infrastructure for a series of micro SaaS projects without spending a fortune?
Turns out: yes. But it took plenty of Googling, a bunch of screwups, and lots of late-night terminal commands that made me question my life choices.
What began as a scary step into the tech unknown transformed into one of the most empowering wins of my digital life. I went from total noob to confidently running n8n, Supabase, Uptime Kuma, and more โ all on a single Hetzner VPS.
Hereโs my raw, unfiltered story โ filled with every win, mistake, and facepalm moment. No gatekeeping. Just an honest guide for others like me.
๐ง What I Wanted To Build
I needed a scalable, secure, and budget-conscious backend to support various AI workflows and automation tools. I wanted it to be stable enough for real client use and flexible enough to handle different tools.
My initial vision:
- Deploy n8n for automations (my digital Swiss Army knife)
- Self-host Supabase for database, auth, and storage
- Set up Uptime Kuma to monitor my apps and get downtime alerts
- Use Caddy as a reverse proxy that auto-manages HTTPS certs
- Run everything inside Docker with Compose to keep things isolated and portable
- Set up daily backups of everything and store them in GitHub or encrypted in Google Drive
- Make it easy to manage with VS Code, cron, and shell scripts
I didnโt want to pay $30โ60/month for SaaS tools I could self-host. And I didnโt want to rely on 3rd party platforms that could change pricing or shut down.
๐ ๏ธ What I Used
Tool | What it Did |
---|---|
Hetzner VPS | My production-grade cloud server (cheap + powerful) |
Ubuntu 24.04 | Operating system of choice |
Docker + Compose | Containerized everything I run |
n8n | No-code/low-code backend automation engine |
Supabase | PostgreSQL + REST API + Auth backend |
Caddy | Reverse proxy + HTTPS with zero config TLS |
Fail2Ban | Actively bans malicious IPs hitting SSH |
UFW | Lightweight firewall for basic traffic rules |
Uptime Kuma | Beautiful, beginner-friendly monitoring UI |
Git + GitHub | Version control + safe remote backups |
Google Drive + Rclone + Crypt | Cloud backups with encryption |
Bonus: I used cron, bash scripting, and VS Code Remote SSH for convenience.
๐ฎ The Beginner's Questline (With Real Mistakes I Made)
โ Quest 1: Provision a Hetzner VPS
A VPS (Virtual Private Server) is like having your own mini-computer running in the cloud. You get full control of an isolated machine with its own RAM, disk space, and operating system โ perfect for hosting apps, APIs, databases, or even websites. Itโs not quite a full physical server, but way more powerful and flexible than shared hosting.

I chose Hetzner over options like DigitalOcean or AWS because:
- Their pricing is ridiculously good for the amount of CPU and RAM you get.
- They offer fast European data centers (perfect for my app latency needs).
- No complicated billing surprises like AWS.
Win: Got SSH access working and connected from my Mac. Mistake: Didn't know about disabling root login or why SSH keys were safer than passwords. That came later. Spun up a VPS on Hetzner with Ubuntu 24.04. Super affordable for the specs.
โ Quest 2: Install Docker + Docker Compose
Docker is a tool that lets you run applications inside isolated containers. Think of containers as mini-computers inside your server โ each one runs only what it needs, and nothing more. Docker Compose is a helper tool that lets you run multiple containers together using a single YAML file. For example, one file can define your n8n app, Supabase stack, and Kuma monitor.
Why it's helpful for beginners: It keeps things modular and easy to reset. If I broke something, I could just stop the container, delete it, and run it again clean โ no need to reinstall everything manually.
Win: docker --version
and docker compose version
returned properly. Mistake: Mixed up docker-compose
(deprecated) vs docker compose
(correct now). Debugged that for 30 mins. Win: docker --version
and docker compose version
returned properly. Mistake: Mixed up docker-compose
(deprecated) vs docker compose
(correct now). Debugged that for 30 mins.
โ Quest 3: Set Up n8n with HTTPS
Exposed via Caddy with a custom domain. Forgot to set N8N_HOST
and WEBHOOK_URL
initially. Fixed it later.
What is HTTPS? HTTPS (Hypertext Transfer Protocol Secure) encrypts the data sent between your browser and server. It ensures that login credentials, form inputs, API keys, and anything sensitive is protected from being intercepted by third parties (like hackers or public Wi-Fi sniffers).
What is a reverse proxy? A reverse proxy like Caddy sits in front of your apps. It routes traffic from your domain (like agents.truelytics.solutions
) to the correct service (like n8n running on port 5678). Bonus: Caddy handles SSL certificates from Let's Encrypt automatically, so you donโt need to manage certs manually.
Win: n8n became accessible at a real domain with HTTPS. Mistake: Missed environment variables early on, so OAuth and webhooks failed until fixed. Didnโt understand how Caddy was handling SSL at first. Exposed via Caddy with a custom domain. Forgot to set N8N_HOST
and WEBHOOK_URL
initially. Fixed it later.
โ Quest 4: Harden the VPS (Security Time!)
- Enabled UFW, SSH Keys, Fail2Ban
- Created non-root user, disabled password login
What went wrong: I accidentally locked myself out of my own server by misconfiguring the /etc/ssh/sshd_config
file. I had disabled password login before ensuring my SSH keys were fully working and recognized by the server. The moment I restarted the SSH service, I lost access.
Recovery: I panicked. But Hetzner has a lifesaving feature โ the web-based console from the Hetzner Cloud Panel. I accessed the VPS directly from my browser, edited sshd_config
, re-enabled password login temporarily, restarted the SSH service, and regained control. Then I fixed the SSH key setup properly and re-hardened the config.
Lesson: Always test SSH key access in a new session before disabling password login. And always keep a recovery path like Hetzner's web console in mind.
- Enabled UFW, SSH Keys, Fail2Ban
- Created non-root user, disabled password login
- Locked myself out once due to misconfiguring
sshd_config
. Recovered through Hetzner console.

โ Quest 5: Structure Project Folders
Created clean /home/my/projects/
structure:
/projects/
โโโ n8n/
โโโ supabase/
โโโ uptime-kuma/
โโโ auto_git_backup.sh
โโโ backup_n8n.sh
โโโ backup_to_gdrive.sh
โ Quest 6: Set Up Daily GitHub Backups
Created cron jobs and scripts to push key config files nightly to GitHub.
Win: This gave me version control over everything: Docker files, backup scripts, even my Markdown setup guides.
Mistake (Almost!): At one point I almost committed a .env
file containing secrets. I caught it just in time because of a Git warning โ and because ChatGPT had previously warned me to always include .env
in .gitignore
. That reminder saved me.
Fix: I immediately added .env
to .gitignore
, renamed my real secret file to .env
, and committed a .env.example
instead. This example file now shows the correct format but no sensitive values.
Lesson: Donโt ever push credentials โ and always double-check whatโs in your staging area before running git add .
.
โ Quest 7: GitHub Repo + Version Control
Everything inside /projects/
is now versioned in a private GitHub repo. We created the repo manually, connected my server via SSH key authentication, and configured a clean .gitignore
to make sure sensitive files like .env
were excluded. I remember thinking I had accidentally pushed secrets at one point, but thanks to the safety reminders from ChatGPT and a careful git status
check, I avoided disaster. Every push now happens automatically from cron and includes a timestamped commit for traceability.
โ Quest 8: Install Uptime Kuma
Running at status.truelytics.solutions
, Uptime Kuma is my personal backend health command center. It monitors:
- Sites (n8n, Supabase, and future apps)
- VPS Public IP with continuous Ping checks
- Disk space levels via a custom
kuma_disk_space_push.sh
script (runs every minute via cron) - SSH port 22 (to check if remote access is alive)
- HTTP responses and container uptime
- And it sends real-time Telegram alerts directly to my phone whenever something goes down or recovers โ
Setup Details:
- I installed it in its own
/projects/uptime-kuma/
folder - Exposed via Caddy with SSL at
status.truelytics.solutions
- Integrated a simple push-based health script for non-HTTP services (like disk)
Why it matters: I now get instant notifications if anything critical fails. No more blind spots. It helps me sleep better at night knowing Iโll know right away if my infrastructure breaks.

โ Quest 9: Deploy Supabase (Cloud Hybrid)
- Initially self-hosted Supabase using Docker on the same VPS โ but hit memory limits fast.
- My Hetzner VPS only had 2GB RAM, and the full Supabase container stack consumed most of it.
- Apps like PostgreSQL, Kong, Realtime, and Studio quickly choked the server, making n8n and Kuma unstable.
Mistake: I underestimated how resource-heavy Supabase's Docker setup really is โ even with "light" mode. How I Realized It: Uptime Kuma started showing frequent crashes. htop
revealed Supabase was eating all available memory. Caddy started timing out.
Fix: Migrated to the Supabase Cloud Free Tier and kept only essential apps running on the VPS. This restored full performance stability.
- Supabase Cloud connected successfully to n8n โ
- Now running a hybrid setup: automation logic (n8n) self-hosted, database (Supabase) cloud-hosted
- Initially self-hosted (used too much RAM)
- Moved to Supabase Cloud (free tier)
- Connected to n8n successfully โ

โ Quest 10: Central Logging & Monitoring
Monitoring is fully operational via status.truelytics.solutions
, where Uptime Kuma tracks all key services and subdomains โ including n8n, Supabase, and the VPS itself. Alerts are pushed directly to my Telegram app, which has been incredibly helpful. Iโve received real-time notifications whenever something went down or if a disk issue occurred. It saved me multiple times from silent failures I wouldnโt have caught without it. While I had originally planned to integrate Slack or ClickUp, Telegram proved more than enough for now, especially for mobile alerts.
โ Quest 11: Setup .env and Credential Hygiene
All Docker projects now use .env
files. .gitignore
enforces no secrets committed.
โ Quest 12: Setup VS Code SSH + Docker Extension
I can now edit and manage my server like a local machine.
โ Quest 13: Setup n8n Update Flow
Keeping n8n up to date is critical โ both for security patches and new feature releases. The update process sounded scary at first, especially since I didnโt want to break a running production automation tool. But it turned out to be clean and straightforward thanks to Docker.
How I did it:
- I stopped the running container using
docker compose down
- Pulled the latest image with
docker pull n8nio/n8n
- Then restarted it using
docker compose up -d
Since my workflows and credentials were mounted as Docker volumes, none of the app data was lost. I was also protected by my daily backups (cron scripts + GitHub + encrypted Google Drive) in case anything failed โ but it didnโt.
Verification: I accessed my n8n domain and tested workflows, credentials, and webhooks. Everything was alive and working.
Lesson: Docker makes updates stress-free if your volumes are mounted properly and you have backups in place. Now Iโm confident to update anytime. Simple docker pull
+ restart, tested and verified โ
โ Quest 14: Setup SSH Shortcut (truelytics-prod)
I can SSH in with ssh truelytics-prod
. .ssh/config
secured. No more IP memorization.
โ Quest 15: SSH Security Audit + Fail2Ban + Recovery Plan
SSH keys only, root login disabled, recovery instructions written and saved offline.
Why this matters: Password-based login is one of the most common entry points for brute-force attacks. Disabling it and using SSH keys drastically reduces the attack surface. During setup, I noticed an overwhelming number of login attempts being blocked โ many of them coming from unfamiliar IPs, particularly from China and other international IP ranges. This is where Fail2Ban saved me โ automatically banning IPs that repeatedly tried (and failed) to log in.

The scary part? I checked my logs once and saw over 300+ failed SSH login attempts in a single day. These werenโt just random โ they were real bots scanning the internet for weak servers. Thankfully, my setup was secure, and every attempt was blocked.
The good: Knowing Iโm protected. The bad: Realizing how many bots are actively probing the web. It was a wake-up call.
Thatโs why this quest is more than a checkbox โ itโs the frontline of my server's defense.
โ Quest 16: Install rclone + Google Drive Backup
Using rclone
, I set up a secure bridge between my VPS and Google Drive. But instead of just syncing files directly, I created an encrypted remote called gdrive-crypt
. This means even if someone accessed my Drive, they couldn't read or decrypt any of my server files without the private key.
What it protects: All my critical backups โ n8n workflows, Docker configs, environment samples, Markdown docs โ are encrypted and uploaded automatically every day at 3AM via a cronjob.
Setup details:
- Installed
rclone
and authenticated it with my Google account - Created a regular remote called
gdrive
, then layeredgdrive-crypt
on top of it using a password and salt key - Wrote a bash script (
backup_to_gdrive.sh
) that compresses important folders and syncs them to the encrypted remote - Cron runs this every night at 3AM and logs the output for reference
Why itโs cool: I literally get end-to-end encrypted backups uploaded silently to the cloud. If my VPS exploded tomorrow, I could restore everything from Drive. Even better? Nobody can spy on my files.
Lesson: Encryption isnโt just for paranoid nerds โ itโs smart disaster insurance.
โ Quest 17: Uptime Kuma Alert System

Telegram alerts working โ Disk push script works โ Auto-monitoring confirmed โ
โ Quest 18: Setup Auto GitHub Cron Backup
Pushes GitHub backup every 2AM โ
How it works: A simple bash script (auto_git_backup.sh
) runs a git add .
, git commit
, and git push
with a timestamp every morning. This ensures my entire /projects/
folder โ including all config files, scripts, and Markdown docs โ is backed up remotely in my private GitHub repo.
Why it matters: Even if I accidentally delete something or mess up a config file, I can always go back to a previous version. It's my codebase safety net.
โ Quest 19: Setup Cron-Based Encrypted GDrive Sync
backup_to_gdrive.sh
runs daily at 3AM โ- Keeps infra & config safe even if VPS dies
Details: This script compresses folders like /projects/
, /backups/
, and custom .env.example
files, then syncs them to my encrypted gdrive-crypt
remote using rclone.
Why this is important: If Hetzner suddenly went offline or I broke my VPS beyond repair, I could spin up a new one and restore everything from my Drive โ with all secrets protected via encryption.
โ Quest 20: Final Backup Folder Cleanup
Organized /backups/n8n/
, /backups/kuma/
, logs, and cron logs
โ Quest 21: Uptime Kuma Disk Space Push Script
Pushes disk stats every minute to Kuma โ
๐ Quest 22: Setup Pinecone or Weaviate (Vector DB)
Pending setup. Will power AI apps like chatbots or semantic search.
๐ Quest 23: Setup DNS Email Auth (SPF, DKIM, DMARC)
Required so apps can send verified emails (e.g. from n8n or Supabase).
โ Quest 24: Wildcard Subdomain Automation (Blocked)
GoDaddy doesnโt support API needed for Caddy DNS plugin. Currently managing subdomains manually.
๐ Final Result
- โ 23 Quests Completed
- โ Backend Infra is Production-Ready
- โ Telegram alerts, encrypted backups, GitHub sync, server hardened
- โ Supabase + n8n now integrated
- โ Project folder structure organized
- โ Real SaaS backend officially unlocked
๐ Final Thought
If you're a noob like I was, trust this: you can do it. It takes curiosity, persistence, and a little help from good documentation and AI tools.
One terminal command at a time.
From clueless beginner to backend builder โ that's the Wonder With G journey.