๐Ÿ›ก๏ธ How I Built a Full Production Backend on Hetzner VPS (As a Total Noob)

๐Ÿ›ก๏ธ 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

ToolWhat it Did
Hetzner VPSMy production-grade cloud server (cheap + powerful)
Ubuntu 24.04Operating system of choice
Docker + ComposeContainerized everything I run
n8nNo-code/low-code backend automation engine
SupabasePostgreSQL + REST API + Auth backend
CaddyReverse proxy + HTTPS with zero config TLS
Fail2BanActively bans malicious IPs hitting SSH
UFWLightweight firewall for basic traffic rules
Uptime KumaBeautiful, beginner-friendly monitoring UI
Git + GitHubVersion control + safe remote backups
Google Drive + Rclone + CryptCloud 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 layered gdrive-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.