Sin comentarios

Elige tu propio Vercel (o más bien Heroku)

Tiempo estimado de lectura: 9 minutos.

Segunda parte de la guía para subir webs a un VPS, esta vez armando Nube, un mini-PaaS que publica cada app con git push, HTTPS y base de datos incluidos.

En la guía para subir webs a hosting o VPS dejé las piezas sobre la mesa: un VPS, nginx, PHP-FPM, MySQL, DNS y certificados. La teoría está bien, pero en la práctica cada proyecto nuevo arranca con la misma ceremonia: crear el usuario, la carpeta, el virtual host, la base de datos, el certificado y el script que copia los archivos. Si tenés un proyecto, es un rato. Si tenés cinco, es una tarde y siempre te olvidás de algo.

Heroku resolvió eso hace años con una idea muy simple: hacés git push y la app queda publicada. Vercel y otros hacen un pull del repositorio. No es mucho más complicado, para mí el push es más simple para este caso donde no vas a escalar horizontalmente.

Más allá del plan inicial gratuito, Vercel es mucho más caro que una VPS. Ni hablar de Heroku. Por supuesto estás pagando su servicio de hacer de DevOps. Para mí en tiempos de IA no es tan difícil hacerlo uno mismo.

Lo vengo usando hace varios años internamente, y de hecho lo tenía público, pero lo tuve que quitar porque le agregué data muy concreta de algunos proyectos que estoy trabajando. Por eso publiqué la versión anterior en GitHub como VPS.

Usala como base para armar la tuya, toda la primera parte le podés pedir a la IA que lo deje todo configurado, que haga pruebas, y lo deje lo más armado posible. Luego te encargas de entrar por SSH y generar los proyectos con los comandos (ej add-domain.sh).

La idea

Nube tiene un solo usuario de deploy (nube) y un dominio base (nube.example.com). Cada app vive en un subdominio y se publica con un push:

git push server main   # aplica la configuración del servidor
git push prod main     # publica una app

Son dos flujos distintos a propósito. El repositorio del servidor no es una app: contiene nginx/, fail2ban/ y los scripts. Cuando le hacés push, el servidor copia esa configuración a /etc, valida con nginx -t y recarga. Si nginx -t falla, revierte el cambio y el push termina con error. O sea: el servidor se configura desde git, no entrando a editar archivos a mano.

El otro flujo es el de siempre, el de Heroku:

git push prod main
        │
        ▼
~/git/blog.git  ──►  hook post-update
                          │
                          ├─ checkout en /var/www/blog.example.com
                          ├─ arma el .env con los datos de la base
                          ├─ instala dependencias según el stack
                          ├─ corre migraciones y cachés si es Laravel
                          └─ ejecuta .nube/deploy si existe

Al final, nginx sirve el sitio, Node / Python o PHP-FPM ejecuta el código y MySQL guarda los datos. Nada nuevo: la diferencia es que está automatizado y versionado.

Lo que necesitás

nube.example.com       A   203.0.113.10
*.example.com     A   203.0.113.10

Por supuesto no hace falta que se llame Nube, ponele el nombre que quieras. A mí me gusta decir que mi proyecto lo tengo en la nube.

El wildcard es clave: con eso cualquier subdominio nuevo (blog.example.com, app.example.com) ya apunta al servidor sin crear un registro cada vez. También hay que emitir un certificado wildcard con acme.sh; está documentado en el repo y no lo voy a repetir acá.

Instalación

La idea es que cada servidor tenga su propio fork, así podés tocar nginx o fail2ban sin afectar a nadie. En el VPS:

sudo apt update && sudo apt install -y git
sudo git clone https://github.com/TU-USUARIO/vps.git /opt/nube
cd /opt/nube

sudo ./bootstrap.sh \
    --base-domain nube.example.com \
    --email [email protected] \
    --ssh-key-file ~/.ssh/id_ed25519.pub

bootstrap.sh es idempotente. Crea /etc/nube/nube.conf, instala los comandos, aplica la configuración de nginx y fail2ban, crea el usuario de deploy con git-shell, le instala tu clave SSH y deja el repositorio del servidor con su hook.

Después, desde tu máquina, apuntás tu fork al servidor y aplicás la configuración:

git remote add server [email protected]:git/nube
git push server main

Ese push no publica ninguna web: deja el servidor con la configuración que está en tu repo. Es raro la primera vez, después se agradece.

Publicar una app

Supongamos que querés publicar un blog. Primero preparás el subdominio:

sudo runuser -u nube -- nube-add-subdomain blog

Eso crea ~/www/blog.nube.example.com/public, el symlink en /var/www y una página provisoria. Después creás el repositorio y la base de datos:

sudo runuser -u nube -- nube-add-repository blog blog.nube.example.com | sudo mysql

nube-add-repository crea el repositorio bare en ~/git/blog.git, le pone el hook de deploy y escribe por stdout el SQL que crea la base y el usuario de MySQL. Por eso el pipe a sudo mysql: hacés las dos cosas en un comando.

Por último, en la carpeta de tu proyecto:

git remote add prod [email protected]:git/blog
git push prod main

Y listo: https://blog.nube.example.com. El hook imprime el progreso en la terminal y deja el detalle en ~/nube-deploy.log si algo falla.

La demo

Un deploy completo de una app PHP, desde el push hasta la URL:

Qué detecta el deploy

No hay que declarar el stack en ningún archivo. El hook mira lo que hay en el repositorio:

Para lo que no entra en ninguna receta está .nube/deploy, un script ejecutable que corre al final del deploy con variables como NUBE_PATH, NUBE_URL, NUBE_DOMAIN y las credenciales de la base. Ahí van los storage:link, los workers, los pasos de build propios o lo que necesite el proyecto.

El .env

El hook no pisa secretos. Si versionás un .env.example con placeholders, en cada deploy los reemplaza por los valores reales:

APP_NAME=Blog
APP_URL=#NUBE_URL#

DB_CONNECTION=#NUBE_DB_CONN#
DB_HOST=#NUBE_DB_HOST#
DB_DATABASE=#NUBE_DB_NAME#
DB_USERNAME=#NUBE_DB_USER#
DB_PASSWORD=#NUBE_DB_PASS#

Las variables que no son placeholders quedan como estén en el .env del servidor. Eso permite cargar a mano una MAIL_PASSWORD o una API key sin que el próximo push la borre.

Los límites

Primero que nada, el código de la VPS no es igual al que hay hoy en día productivo en mi servidor. Usalo como base, para crear el tuyo. Adaptalo y probalo.

Nube está pensado para un VPS, un dueño y un dominio base. No es un hosting multi-tenant: si necesitás alojar clientes que no confían entre sí, va un VPS por cliente. Tampoco tiene panel web, autoescalado ni deploy blue/green.

Hay otras decisiones que conviene tener claras:

Para cerrar

La guía anterior explicaba las piezas. Esta automatiza el armado. No es un reemplazo de Vercel ni pretende serlo: es la versión chica y transparente que puedo leer entera, adaptar y arreglar sin abrir un ticket.

El código, los ejemplos y la documentación están en github.com/4lb0/vps.

La Ilustración es de Katerina Limpitsouni publicada en unDraw.

Publicado por Albo el lunes 19 de octubre del 2026 en Tips.

Este blog respeta tu privacidad, no guarda analíticas ni cookies. Si te gusto este artículo puedes darle me gusta de manera anónima.