Why I Self-Host Everything
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 |
|---|---|---|
| n8n | Zapier / Make | Workflow automation, AI agents |
| Vaultwarden | LastPass / 1Password | Bitwarden-compatible password manager |
| Nextcloud | Google Drive / Dropbox | Files, calendar, contacts |
| Gitea | GitHub (private repos) | Lightweight Git hosting |
| Uptime Kuma | Better Uptime / Pingdom | Service monitoring with alerts |
| OpenClaw | Custom AI agent setup | AI 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.