MUJICA.DEV Escritos EN Patagonia · CL
← Escritos

Infraestructura

Un solo servidor.

Cinco proyectos paralelos, un droplet de $12 en Santiago, detrás de Cloudflare. Sin Vercel, sin Supabase, sin Redis.

Tengo varios proyectos paralelos dando vueltas. Un agendador de citas por WhatsApp, una app de mensajería que entrega con retraso, un backoffice para una agencia de viajes, un juego de apuestas del Mundial para mis amigos, y un par más a medio cocinar. Por un tiempo cada uno vivía en un free tier distinto: Vercel por acá, Supabase por allá, MongoDB Atlas, una instancia olvidada en Oracle Cloud, Resend para los correos. Funcionaba, en el mismo sentido en que funciona un castillo de naipes: hasta que alguien estornuda.

El problema de los free tiers no es el precio. Es que cada uno es otro panel, otro modo de falla, y otra cuenta regresiva hacia el correo donde te suben el plan. Supabase te pausa la base de datos a los siete días sin uso. Vercel se pone quisquilloso apenas hueles a que vas a cobrar por algo. Yo quería un solo lugar, que entendiera de punta a punta, que pudiera tener claro en la cabeza a las 2 de la mañana, y que costara más o menos lo mismo que dos cafés.

Así que metí todo en un solo servidor. Este es el mapa completo.

Toda la infraestructura de producción.

El borde: Cloudflare

Todo lo público entra por Cloudflare: DNS, CDN, WAF y TLS. La dirección real del droplet está detrás de un firewall, así que solo contesta el tráfico que pasó por Cloudflare; desde la internet abierta el origin no se ve. La misma cuenta me da R2 para guardar archivos (compatible con S3 y sin cobro por salida de datos) y un servicio de correo transaccional. Un proveedor reemplazó a cuatro sin hacer ruido.

Cómputo: un droplet de Vultr, manejado por Dokploy

Todo corre sobre una instancia Vultr High Performance en Santiago: 1 vCPU, 2 GB de RAM, 50 GB de NVMe. Santiago porque es la única región de una nube grande que está de verdad en Chile, lo que significa unos 5ms para la gente que usa estas apps, en vez de un viaje de ida y vuelta hasta Virginia.

Encima va Dokploy, que es la parte que hace que esto sea llevadero y no una tortura. Es una capa open-source y self-hosted sobre Traefik y Docker que te da deploys al estilo Railway: le apuntas a un repo de GitHub y él solo construye el Dockerfile, arma el ruteo y saca los certificados de Let's Encrypt. Listo. La misma comodidad que las plataformas que dejé, pero ahora es mía y no cuesta nada extra. Cada app es apenas un contenedor en una red Docker compartida, así que se encuentran entre sí, y a la base de datos, por su nombre.

Un solo Postgres, muchas bases de datos

Hay un solo contenedor de Postgres 16, y cada proyecto tiene su base de datos y su rol adentro. atendi, postamis, patagonica, fubol: bases separadas, sin tablas compartidas, sin que una app lea la de otra. Es aburrido, es portable, y para respaldar me basta con un pg_dump. Le sumé pgvector para las apps que quieren embeddings y pg_cron para los temporizadores dentro de la base; los dos son apenas extensiones, no un servicio más que andar cuidando.

La autenticación vive dentro de cada app (Better Auth o NextAuth, según el proyecto), no en el proveedor de la base de datos. Fue una decisión a propósito para alejarme del row-level-security para todo de Supabase. Menos magia, menos amarre, menos sorpresas cuando quiero hacer algo que el framework no tenía previsto.

Tareas en segundo plano, sin Redis

Dos de estas apps son, en el fondo, relojes. Atendi manda recordatorios de citas; Postamis es una app de mensajería cuya gracia entera es entregar las cosas tarde, a propósito. Las dos necesitan tareas programadas que no se pierdan.

El reflejo acá es tirar mano de Redis y una cola de trabajos. No lo hice. Hay un solo worker compartido corriendo pg-boss, que usa de cola el mismo Postgres que ya tengo. Despierta según un horario y le hace ping a cada app por HTTP; nunca lee la base de datos de nadie más. Así la cola es persistente, las tareas sobreviven a los reinicios, y no sumé ni una sola pieza móvil nueva. Lo que no levantas no te puede despertar a medianoche.

El correo, separado a propósito

El correo es el único lugar donde, a propósito, no consolido, porque las formas de fallar son distintas. Las casillas humanas (las direcciones que de verdad leo) pasan por un proveedor de correo dedicado. El correo que generan las apps (códigos para entrar, recordatorios) sale por el servicio de correo de Cloudflare, que se hace cargo solo del SPF, el DKIM y el DMARC porque Cloudflare ya maneja mi DNS. Si algún envío transaccional me ensucia la reputación, no se lleva de paso mi bandeja personal. Acá la separación es por seguridad, no por plata.

Respaldos y la puerta de atrás

Cada noche un script corre pg_dump sobre cada base de datos y manda el resultado a R2 con rclone. Fuera del servidor, versionado, dentro del free tier, y tengo un script que prueba la restauración para que los respaldos no sean solo respaldos de Schrödinger. La administración (el panel de Dokploy, el SSH) pasa por una red privada de Tailscale, nunca por la internet pública. Al plano de control sencillamente no se llega si no estás ya en mi tailnet.

La cuenta

La razón por la que vale la pena escribir todo esto:

ÍtemProveedor/mes
Droplet · 1 vCPU / 2 GB · SantiagoVultr$12
DNS · CDN · WAF · R2Cloudflare$0
Correo transaccionalCloudflare~$5
Casillas humanasMXroute~$5
Respaldos fuera del servidorR2 (free tier)$0
Total~$22

Unos $22 al mes por toda la infraestructura, contra un techo que yo mismo me puse en $40. Ese margen no lo he tocado porque ningún proyecto se lo ha ganado todavía; cuando a alguno le quede chica la máquina, le subo specs al droplet y sigo. Un servidor ha aguantado cómodo cinco apps hasta ahora, y lo que más se aprieta es una máquina de 2 GB construyendo imágenes de Docker, no sirviendo el tráfico.

¿Lo recomendaría?

Si tienes clientes que pagan y un turno de on-call: no, quédate con todo administrado. Pero si programas solo, con un puñado de proyectos y sin clientes en producción, el peaje de las plataformas es real y mantener un servidor bien cuidado cuesta menos de lo que parece. El trato fue este: más configuración al principio a cambio de un sistema que entiendo entero y una cuenta que no me da sustos. Hasta ahora, fue el correcto.

El stack aburrido gana más seguido de lo que la gente cree.

Lo armé, lo rompí y lo escribí. Preguntas → rene@mujica.dev.