Com muntar un entorn SaaS en un VPS: stack, deploy i automatització
Guia pràctica per configurar un VPS per a projectes SaaS: Caddy, Cloudflare Tunnel, Next.js, Supabase i Resend. Tot automatitzat amb un Makefile. Cost total: 8€/mes.
Per què un VPS i no un PaaS?
Vercel, Railway, Fly.io — tots funcionen bé. Però quan valides varies idees en paral·lel, el cost s'escala ràpid i perds el control de la infraestructura. Un VPS a Hetzner CX22 costa 8€/mes i pots allotjar-hi tants projectes com vulguis. La diferència és que has de gestionar el servidor tu.
El truc és automatitzar-ho tot des del principi perquè la gestió manual no et costi més que el que estalvies.
L'stack escollit
Aquests són els criteris que em guien:
- Mínima superfície d'atac — res de ports oberts innecessaris
- Zero configuració TLS manual — vull HTTPS sense pensar-hi
- Tot al repo — si no és al git, no existeix
- Reproducible des de zero — poder esborrar el VPS i recrear-ho en 10 min
La taula de decisions:
| Capa | Tecnologia | Per qué |
|---|---|---|
| VPS | Hetzner CX22 | Millor relació preu/rendiment d'Europa |
| Web server | Caddy | HTTPS automàtic, config mínima |
| TLS / proxy | Cloudflare Tunnel | Cap port 80/443 obert al VPS |
| Frontend | Next.js (App Router) | SSG + API routes en un sol projecte |
| Auth | Supabase | Auth + DB + Storage gratuïts fins a cert punt |
| Resend | API neta, bona deliverability, free tier generós | |
| DNS | Cloudflare | API completa per automatitzar registres |
| Analytics | Plausible CE | Open source, selfhosted, GDPR compliant |
La clau: Cloudflare Tunnel
El canvi que més ha simplificat la configuració. En comptes d'obrir ports 80 i 443 al servidor i gestionar certificats, el VPS estableix un túnel sortint cap a Cloudflare. El tràfic arriba xifrat a Cloudflare i Cloudflare el passa al teu servidor per dins del túnel.
Avantatges reals:
- UFW bloqueja tots els ports web — només queda SSH (2222)
- TLS gestionat per Cloudflare — cap certificat a renovar
- El VPS no necessita IP pública accessible directament
# UFW: un sol port obert
ufw allow 2222/tcp comment 'SSH'
ufw default deny incoming
# Tot el web passa pel túnel, sense ports oberts
Estructura del repositori
La filosofia és simple: si no és al repo, no existeix. Cada fitxer de configuració, cada script de deploy, cada regla de firewall — tot al git.
repo/
├── infra/
│ ├── caddy/Caddyfile # Web server config
│ ├── cloudflare/ingress.yml # Tunnel routes
│ ├── ssh/99-hardening.conf # SSH hardening
│ └── ufw/rules.sh # Firewall rules
├── deploy/
│ ├── setup.sh # Bootstrap del VPS (una vegada)
│ ├── deploy.sh # Deploy de l'app
│ └── apply-infra.sh # Aplicar configs d'infra
├── apps/
│ └── tenza/ # Next.js app
├── scripts/
│ └── cloudflare.py # DNS via API
└── Makefile # Punt d'entrada
El Makefile com a interfície
Mai executes SSH manualment per desplegar. El Makefile és la interfície pública:
# Deploy complet en una comanda
make deploy
# Aplicar canvis d'infraestructura
make apply-infra
# Veure logs en temps real
make logs
# Gestionar el túnel
make tunnel-status
make tunnel-logs
Cada target és idempotent — pots executar-lo tantes vegades com vulguis sense por. Això és crític perquè no has de recordar quin estat té el servidor.
Deploy en 3 passes
El flux de deploy és:
- git push — el codi puja a GitHub
- git pull al VPS — el servidor baixa el codi
- deploy.sh — instala deps, builda i reinicia el servei
Tot automatitzat amb make deploy. El VPS mai necessita accés a GitHub amb credencials especials — simplement fa pull del repo públic (o privat via deploy key).
Email amb Resend i zero configuració DNS manual
Un dels punts de fricció clàssics al muntar un SaaS és l'email: SPF, DKIM, DMARC, configuració del sender... Resend ho simplifica molt, però encara cal configurar els registres DNS.
La solució: un script Python que configura tot via l'API de Cloudflare:
# Configura SPF, DKIM, DMARC i email routing en una comanda
uv run scripts/email_setup.py setup \
--domain tenza.io \
--forward-to [email protected] \
--addresses hola,support
Analytics amb Plausible selfhosted
Google Analytics 4 és massa complex per a validació. Plausible CE (Community Edition) és open source, s'autoposa en Docker al mateix VPS, i dóna les mètriques essencials sense complexitat ni problemes GDPR.
El dashboard en temps real et diu: quants visitors, d'on vénen, quines pàgines visiten i quins UTMs funcionen. Per a validació inicial, és tot el que necessites.
Cost total
| Servei | Cost/mes | Límit gratuït |
|---|---|---|
| Hetzner CX22 | 8€ | — |
| Cloudflare | 0€ | DNS + Tunnel gratuïts |
| Supabase | 0€ | 500 MB DB, 50K MAU |
| Resend | 0€ | 3.000 emails/mes |
| Plausible CE | 0€ | Selfhosted al VPS |
| Total | ~8€/mes | per a múltiples projectes |
Conclusions
Aquest setup no és per a producció a escala — és per a validació ràpida de SaaS. L'objectiu és passar de idea a landing page amb email capture en menys d'un dia, amb tots els fonaments ben posats: domini, email, analytics, deploy automatitzat.
Quan el producte arriba a escala, migres a Vercel/Railway/k8s. Però fins llavors, 8€/mes és prou per aprendre, validar i iterar ràpid.
Construint en públic
Apunta't per rebre les actualitzacions del projecte — stack, decisions, mètriques i aprenentatges.