Self-host con Bun: qué vale la pena correr en tu propio servidor
Cada vez que abro el resumen de la tarjeta aparece otra suscripción de 5 dólares que ni recordaba que existía. Por eso me atrapó el post What I self-host, de viceconsole.fyi. El autor muestra lo que corre en su propia infraestructura y explica el porqué de cada elección. Lo leí y fui directo a revisar mi lista. Este artículo es mi versión del tema, con un recorte específico: self-host con Bun. Hoy es el camino más corto que conozco para pasar del "voy a levantar un serviciecito" al "ya está corriendo".
Por qué el self-host volvió a ser tema
Durante unos diez años la respuesta estándar fue "mándalo a un SaaS". Tenía sentido. Un servidor daba trabajo, y el tiempo del dev cuesta caro.
Cambiaron tres cosas:
- Las VPS se abarataron. Con unos 5 dólares al mes tienes 2 vCPUs y 4 GB de RAM. Alcanza para una docena de servicios pequeños.
- Los SaaS se encarecieron. Muchas herramientas que eran gratis pasaron a "free tier con 1 proyecto" y el resto se volvió de pago.
- El runtime se simplificó. Este es el punto que me interesa. Antes, correr JavaScript en el servidor exigía Node, un gestor de paquetes, un bundler, a veces un transpiler y un process manager. Con Bun buena parte de eso viene en un solo ejecutable.
El post original va por un camino más amplio. Habla de servicios listos para usar, de hardware, del placer de ser dueño de tus propios datos. Comparto el espíritu. Pero como dev, lo que más tengo para alojar no es software ajeno. Son mis propios cachivaches: bots, webhooks, dashboards internos, scripts que tienen que correr cada hora.
Qué tiene sentido alojar tú mismo
Antes de hablar de código, conviene separar. No todo merece ir a tu servidor.
Lo que alojo sin miedo:
- Herramientas internas. Panel de métricas del blog, acortador de links, un formulario que manda una notificación a Telegram.
- Webhooks y automatizaciones. Algo que recibe un POST de GitHub o de Stripe y hace alguna tarea.
- Jobs programados. Backup, scraping liviano, reporte semanal por e-mail.
- Prototipos. Esa idea que puede volverse proyecto o morir en dos semanas.
Lo que no alojo:
- E-mail. La entregabilidad es un pozo sin fondo. Déjaselo a quien vive de eso.
- Autenticación de producto con usuarios que pagan. Se puede hacer, pero el costo de equivocarse es demasiado alto.
- Base de datos de clientes sin backup probado. Si nunca restauraste un backup, no tienes backup. Tienes un archivo.
El self-host es genial hasta el momento en que te vuelves tu propia guardia.
Esa frase resume la regla que uso: si se cae a las 3 de la mañana y me entero recién al mediodía, ¿está bien? Entonces puede ir a casa. Si no, paga el SaaS y duerme.
Qué tan liviano queda un servidor con Bun
Me gusta tanto Bun para esto porque ya trae casi todo lo que necesita un servicio pequeño. Servidor HTTP, SQLite, hash de contraseñas, lectura de archivos, cliente S3 y cliente Postgres vienen incluidos.
Un acortador de links completo, con persistencia, entra en esto:
import { Database } from "bun:sqlite";
const db = new Database("links.db", { create: true });
db.run("CREATE TABLE IF NOT EXISTS links (slug TEXT PRIMARY KEY, url TEXT NOT NULL)");
const find = db.query<{ url: string }, [string]>("SELECT url FROM links WHERE slug = ?");
Bun.serve({
port: 3000,
routes: {
"/:slug": (req) => {
const row = find.get(req.params.slug);
return row ? Response.redirect(row.url, 302) : new Response("No lo encontré", { status: 404 });
},
},
});
Cero dependencias. Sin express, sin better-sqlite3 compilando bindings nativos en la VPS, sin dotenv (Bun lee el .env solo). El package.json de este proyecto prácticamente solo tiene el nombre.
Parece un detalle, pero no lo es. Cada dependencia es algo que puede romperse en un npm install dentro de ocho meses, cuando ya ni recuerdas cómo funciona el proyecto. En self-host, el enemigo no es el rendimiento. Es el olvido.
Binario único: el truco que cambia el deploy
Lo que de verdad cambió mi flujo es bun build --compile. Empaqueta tu código y el runtime en un solo ejecutable.
bun build ./src/index.ts --compile --minify --target=bun-linux-x64 --outfile encurtador
scp encurtador vps:/opt/encurtador/
Listo. En la VPS no hace falta tener Bun, ni Node, ni nada instalado. El archivo pesa algunas decenas de megabytes porque lleva el runtime adentro. A cambio, ganas un deploy que es literalmente copiar un archivo.
Para mantenerlo corriendo, uso lo que Linux ya trae. Nada de PM2:
# /etc/systemd/system/encurtador.service
[Service]
ExecStart=/opt/encurtador/encurtador
WorkingDirectory=/opt/encurtador
Restart=always
User=apps
[Install]
WantedBy=multi-user.target
Un systemctl enable --now encurtador y el servicio arranca con el sistema y se reinicia si se cae. Delante pongo un Caddy, que resuelve HTTPS solo con dos líneas de config por dominio.
¿Docker? Lo uso cuando el servicio es software de terceros, como un Postgres o una herramienta open source que ya viene con imagen lista. Para código mío, en Bun, binario + systemd es más liviano y tiene menos piezas móviles. Opinión fuerte de la casa: un contenedor para un script de 40 líneas es fantasía de infraestructura. Si tu docker-compose es más grande que tu código, algo salió mal.
¿Y la base de datos?
Para casi todo lo personal, SQLite alcanza. En serio. Un archivo, sin proceso aparte, sin contraseña, sin puerto abierto. bun:sqlite es lo bastante rápido para un volumen que un proyecto personal nunca va a alcanzar.
Cuando necesito Postgres (porque el proyecto puede crecer, o porque quiero usar jsonb y full text search como corresponde), Bun también tiene cliente nativo:
import { sql } from "bun";
const posts = await sql`SELECT slug, title FROM posts WHERE published = true LIMIT 10`;
Lee la DATABASE_URL del entorno y usa template literals con parámetros escapados. En muchos proyectos puedes reemplazar el driver pg casi sin tocar nada.
El backup es la parte que a nadie le gusta y que todos deberían hacer. El mío es un job en Bun que corre de madrugada. Genera el dump y lo manda a un bucket compatible con S3 usando el Bun.s3 que ya viene incluido. Una vez al mes bajo uno de esos archivos y lo restauro en una máquina local. Toma diez minutos y ya me salvó una vez.
Cuánto cuesta y cuánto trabajo da
Números de mi realidad, para que tengas una referencia:
- VPS: unos 5 dólares al mes, corriendo 9 servicios.
- Uso de RAM: cada servicio Bun en reposo anda entre 30 y 50 MB. Postgres es el que más consume.
- Tiempo de mantenimiento: unos 30 minutos al mes, casi todo actualizando el sistema y revisando backups.
Comparado con lo que pagaría en SaaS equivalentes (acortador, analytics simple, cron gestionado, una base pequeña), la cuenta pasa fácil de 40 dólares. Pero el ahorro no es el argumento principal. El argumento es que entiendo cada pieza. Cuando algo se rompe, sé dónde mirar.
El lado malo existe y hay que decirlo. Las actualizaciones de seguridad son tu responsabilidad. Si hackean la VPS porque dejaste SSH con contraseña, la culpa es tuya y de nadie más. Configura llave SSH, desactiva el login por contraseña, activa el firewall y habilita las actualizaciones automáticas de seguridad. La primera vez toma veinte minutos y evita muchos dolores de cabeza.
¿Vale la pena para ti?
Si eres dev y tienes media docena de proyectos pequeños repartidos en free tiers que cambian de reglas todo el tiempo, vale la pena. Empieza de a poco. Toma un solo servicio, reescríbelo en Bun sin dependencias, compílalo y súbelo a una VPS con systemd y Caddy. Si después de un mes no te dio trabajo, mueve el siguiente.
El post de viceconsole.fyi me recordó que ser dueño de tu propia infraestructura es más cuestión de hábito que de talento. Bun solo hizo que ese hábito sea mucho más barato de mantener. Hoy buena parte de lo que corro en producción personal es un archivo ejecutable y un .service. Si quieres ver algunos de los proyectos que nacieron así, están aquí en el portafolio.
Resumen para LinkedIn
Cada resumen de la tarjeta trae otra suscripción de 5 dólares que ni recordaba que existía. Hoy una VPS de 5 dólares corre 9 servicios míos, y el mantenimiento no pasa de 30 minutos al mes. El secreto es Bun: servidor HTTP, SQLite y cliente S3 ya vienen incluidos, sin ninguna dependencia. Un `bun build --compile` genera un binario único. El deploy se volvió copiar un archivo, con systemd y Caddy delante. Mi regla: si se cae a las 3 de la mañana y me entero recién al mediodía, puede ir a mi servidor. Si no, pago el SaaS y duermo. Escribí en el blog qué vale la pena alojar uno mismo y qué dejo afuera. El link está en los comentarios. #Bun #SelfHosting #DevOps #JavaScript #Programación