CushLabs Production Server
Self-hosted Docker infrastructure running 6 services on a single VPS for $10.59/mo
El Problema
Running multiple production services across PaaS free tiers creates cold start latency, per-service cost scaling, and zero infrastructure visibility. This project consolidates all CushLabs services onto a single hardened VPS with Docker orchestration, automatic HTTPS, and real user monitoring — eliminating cold starts and reducing hosting to a flat $10.59/mo.
Características Principales
- 6 Dockerized services running on a single VPS using ~386 MB of 3.7 GB RAM
- Zero cold start latency — always-on containers replace PaaS sleep cycles
- $10.59/mo flat vs. per-service PaaS pricing that scales with each new project
- Bare metal to full production in 1 day with complete documentation
- Automatic HTTPS via Caddy + Let's Encrypt across 5 subdomains
- Self-hosted Web Vitals RUM collector tracking Core Web Vitals across all frontends
Overview
This repository orchestrates all CushLabs production infrastructure on a single Hetzner CPX21 VPS. Six Docker containers — four client-facing services, a Redis cache, and a custom Web Vitals collector — run behind Caddy reverse proxy with automatic HTTPS, consuming just 10% of available RAM.
The entire stack was migrated from Render free tier in March 2026. The migration eliminated 30-60 second cold start latency, consolidated hosting costs to a flat $10.59/mo, and gave full SSH access for debugging, monitoring, and infrastructure control.
Every change to the server is documented in a phase-by-phase setup log. The repo contains everything needed to reproduce the environment from a fresh Ubuntu install — Docker Compose definitions, Caddy configuration, environment variable templates, and the vitals collector source code.
The Challenge
- Cold start latency: Render free tier sleeps services after 15 minutes of inactivity, causing 30-60 second wake-up times for the first request
- Cost scaling: Each new service on a PaaS adds another billing line item — unsustainable for a growing portfolio
- No infrastructure visibility: PaaS abstractions hide resource usage, networking, and debugging access behind dashboards
- Configuration drift risk: Multiple services deployed across different platforms with no centralized configuration management
The Solution
Docker Compose orchestration:
All services defined in a single docker-compose.yml with health checks, restart policies, named volumes, and an isolated bridge network. Service ports are bound to 127.0.0.1 — only Caddy talks to the internet.
Caddy reverse proxy with automatic HTTPS: Five subdomains route to their respective containers. Caddy provisions and renews Let's Encrypt certificates without configuration. SPA routing handles React frontends, and trailing-slash normalization prevents FastAPI 307 redirects from dropping auth headers.
Documentation-first operations:
Every server change is logged in docs/server-setup.md with exact commands, configuration snippets, and verification steps. The server can be rebuilt from documentation alone — no tribal knowledge, no undocumented SSH sessions.
Self-hosted Web Vitals (vitals.cushlabs.ai):
A custom FastAPI service collects Core Web Vitals (LCP, FCP, CLS, INP, TTFB) and pageview analytics from all frontends. A single <script> tag integrates any site. The dark-themed dashboard auto-refreshes and displays metrics by site, page, and time range.
Technical Highlights
- Phase-based hardening: Structured progression from bare metal through SSH hardening, UFW firewall, unattended upgrades, Docker, Caddy, and Netdata — each step documented and verified
- 6 containers in ~386 MB: Efficient resource usage leaves 3.3 GB RAM and 77 GB disk as headroom for new services
- Caddy SPA routing: Static React builds served with proper fallback to
index.html, asset 404 handling, and API proxying — all in a readable Caddyfile - Cloudflare DNS-only: A records point to the VPS with no proxy (gray cloud), letting Caddy handle TLS termination directly via ACME
- Environment variable isolation:
.env.example.*templates committed to git, actual.env.<service>files live only on the VPS - Custom RUM collector: Lightweight PerformanceObserver-based tracker (~2KB) with SQLite storage and no third-party analytics dependencies
Results
For CushLabs Operations:
- 4 production services migrated from Render to self-hosted Docker in a single day
- Hosting consolidated from per-service PaaS to $10.59/mo flat — cost stays fixed regardless of service count
- Zero cold start latency across all endpoints — services respond in milliseconds, not seconds
- Full infrastructure visibility via Netdata, Docker stats, and SSH access
Technical Demonstration:
- Linux server administration from bare metal to production
- Docker Compose orchestration for multi-service architectures
- Reverse proxy configuration with automatic TLS and SPA routing
- Infrastructure-as-code principles applied to VPS management
- Custom monitoring and observability tooling
¿Listo para discutir una solución similar?
Exploremos cómo la automatización con IA puede ayudar a tu negocio.
Agendar una Consulta