All posts
Self-hosting DevOps

Why I Self-Host Everything

Home server rack with Docker containers

n8n, Nextcloud, Vaultwarden, Gitea — my whole stack runs on a single VPS for under $20/month. The cost is low. The control is priceless. Here's how I set it all up.

A few years ago I was paying for Notion, LastPass, GitHub Pro, a Zapier subscription, and three other SaaS tools I barely used. One day I sat down and added it up. It was over $120/month — and I didn't even fully control my own data.

I replaced all of it with a single €12/month VPS. Here's how.

The stack

Service Replaces Notes
n8nZapier / MakeWorkflow automation, AI agents
VaultwardenLastPass / 1PasswordBitwarden-compatible password manager
NextcloudGoogle Drive / DropboxFiles, calendar, contacts
GiteaGitHub (private repos)Lightweight Git hosting
Uptime KumaBetter Uptime / PingdomService monitoring with alerts
OpenClawCustom AI agent setupAI assistant with full access to my stack

Everything runs in Docker. The whole setup is defined in a single docker-compose.yml that I can redeploy from scratch in under 10 minutes.

The architecture

The key piece is Cloudflare Tunnel. I don't expose any ports publicly. Instead, each service is accessible via a subdomain, routed through an encrypted tunnel to Cloudflare's edge:

n8n.yourdomain.com      → localhost:5678
vault.yourdomain.com    → localhost:8080
cloud.yourdomain.com    → localhost:8888
git.yourdomain.com      → localhost:3000

This means:

  • No open ports on my VPS
  • Automatic HTTPS everywhere
  • DDoS protection baked in
  • I can run the server behind NAT or even at home

The Docker Compose setup

Here's a simplified version of how n8n and the Cloudflare tunnel coexist:

services:
  n8n:
    image: n8nio/n8n
    environment:
      - N8N_HOST=n8n.yourdomain.com
      - WEBHOOK_URL=https://n8n.yourdomain.com
    volumes:
      - n8n_data:/home/node/.n8n
    networks:
      - internal

  cloudflared:
    image: cloudflare/cloudflared:latest
    command: tunnel --no-autoupdate run
    environment:
      - TUNNEL_TOKEN=${CLOUDFLARE_TUNNEL_TOKEN}
    networks:
      - internal

networks:
  internal:
    driver: bridge

volumes:
  n8n_data:

The tunnel token is the only secret that matters. Everything else is configuration.

Backups

A self-hosted setup without backups is just a delayed disaster.

I use a nightly cron job that tars up the Docker volumes and uploads them to Cloudflare R2. Total backup size is around 2GB. At R2's pricing that's essentially free.

#!/bin/bash
DATE=$(date +%Y-%m-%d)
tar -czf /tmp/backup-$DATE.tar.gz /var/lib/docker/volumes/
rclone copy /tmp/backup-$DATE.tar.gz r2:my-backups/
rm /tmp/backup-$DATE.tar.gz

I test restores quarterly. If you don't test restores, you don't have backups.

Is it worth it?

Honestly? Yes, but with caveats.

It's worth it if you're a developer who enjoys this stuff and wants to actually understand your infrastructure. It's not worth it if you just want things to work without thinking — in that case, pay for the SaaS and move on.

The real value isn't the $100/month I save. It's that I understand every layer of what I'm running. When something breaks at 2am, I know exactly where to look. That's worth a lot.

Previous