I am a tax accountant in Japan. I have been working in IT for over forty years — starting from an era when source code was compiled overnight.
Last year I sat down and added up what my small practice was paying for SaaS: cloud storage, document collaboration, AI assistants, calendar, email, remote desktop, monitoring. The number was $163 per user per month. I decided to see whether I could build a self-hosted replacement that I actually understood and controlled.
This is what I ended up with, running in production on real client work every day:
- VPS: Vultr, $24/month, Ubuntu 24.04 LTS
- Access: Cloudflare Zero Trust (free tier) — 2 open ports, no VPN, no exposed SSH
- Cloud + editing: Nextcloud + Collabora Online
- AI: Unified proxy for ChatGPT, Claude, Gemini, Perplexity (~100 lines of Node.js)
- Automation: OpenClaw (≥2026.1.29, patched for CVE-2026-25253)
- Remote desktop: Apache Guacamole through 5 authentication layers
- Monitoring: Prometheus + Grafana + Alertmanager
- Backups: Nightly DB to Supabase + weekly AES-256 encrypted config archive
Total for a 3–8 person team: approximately $35–50/month.
I wrote a five-part guide covering the entire build. Every command, every configuration file, every place where I made a mistake. It is free and will remain so.
A few things I learned that may be useful to others here:
- Cloudflare Tunnel eliminated the need for a VPN entirely. Two ports open, everything else invisible. This was the single biggest simplification.
- The hardest integration was not the AI proxy — it was getting Collabora’s
aliasgroupconfiguration to work correctly with Cloudflare’s TLS termination. - OpenClaw’s CVE-2026-25253 (CVSS 8.8) is a serious concern. The architectural defense — localhost-only binding plus tunnel authentication — neutralizes it structurally, but it should not be deployed without understanding the risk.
- The most underrated component is Supabase as a backup target. PostgreSQL-to-PostgreSQL with zero format conversion.
I would be grateful for any feedback from this community. If you see something I could improve, or a better approach to any part of this stack, I would genuinely like to hear it.



Why does this read as if you copied and pasted a LLM response?