From n00b to ZeroCool / Origen

Deploy o no existe: la primera vez que pones algo real en internet

Haz tu primer deploy sin humo: dominio, HTTPS, env vars, CI/CD, logs y rollback. Pasos reales y errores típicos que sí pegan.

Lo que vale la pena leer aquí

Le mandas el link a alguien y: boom. CORS. Variables de entorno en undefined. Build que no se generó. O el clásico 502 que se siente como “mejor dedícate a otra cosa”.

Cuando tu app “jala en mi compu” y en internet se muere

Son las 11:47 pm. Mañana hay demo. Tu laptop ya pidió jubilación, pero tu proyecto corre precioso en localhost. Te sientes listo.

Le mandas el link a alguien y: boom. CORS. Variables de entorno en undefined. Build que no se generó. O el clásico 502 que se siente como “mejor dedícate a otra cosa”.

Ahí aprendes la regla con la que muchos nos golpeamos la cara: deploy o no existe. Si nadie más lo puede abrir (sin que tú estés explicando “es que en mi máquina…”), tu app sigue en trámite.

Va una guía sin humo para subir algo real: con dominio, HTTPS, env vars, logs y un plan B para cuando (no si) se rompa.

Qué vas a sacar de aquí

  • Elegir una ruta de deploy sin convertirte en DevOps de golpe (pero sin ingenuidad).
  • Subir un frontend + backend sencillo con buenas prácticas mínimas.
  • Configurar dominio/DNS y HTTPS sin rezarle al módem.
  • Manejar variables de entorno, secretos y builds.
  • Ver logs, detectar errores y hacer rollback sin entrar en pánico.
  • Checklist final para que tu deploy no dependa de la suerte.

Contexto práctico: tres niveles de “subir algo”

Antes de tocar teclas, decide qué estás subiendo. Esto te ahorra horas de talacha por escoger la herramienta equivocada.

1) Frontend estático (HTML/CSS/JS, React/Vite, Next estático)

  • Ideal si tu app es UI + llamadas a APIs.
  • Deploy casi en corto: Vercel / Netlify / Cloudflare Pages.
  • Para proyectos personales, casi siempre sale gratis.

2) Fullstack con backend (API, auth, DB)

  • Ya necesitas runtime (Node/Python/etc.), variables y probablemente base de datos.
  • Rutas comunes:
    • Frontend en Vercel/Netlify + API en Render/Fly.io/Railway.
    • Todo junto en Render/Fly.io (más simple al inicio; menos “microservicios por moda”).

3) “Lo monté en mi compu” (puerto abierto + IP pública)

  • Sí se puede. También se puede cruzar Periférico en chanclas.
  • Para aprender está bien; para algo real, mejor usa un proveedor.

Dos realidades que pegan mucho por acá:

  • En LATAM, el internet de casa puede estar detrás de CGNAT. Traducción: aunque abras puertos, desde fuera no te ven. No es tu culpa.
  • En la chamba o la escuela a veces “deploy” es mandar un zip por WhatsApp. En cuanto haces un deploy de verdad, ya no hay vuelta.

Guía principal: tu primer deploy real (sin volverte mártir)

Ruta muy común y efectiva para empezar:

  • Repo en GitHub
  • Frontend en Vercel
  • Backend en Render (Fly.io también jala, pero Render suele ser más amable para primer setup)
  • Dominio opcional (pero recomendado)

Si tu proyecto es solo frontend, brinca la parte de backend.

Paso 0: deja tu repo listo para producción (modo adulto funcional)

Checklist rápida antes de subir nada:

  • Tu app corre con comandos claros:
    • Frontend: npm run dev (local) y npm run build (producción)
    • Backend: npm start o npm run start
  • Tu README mínimo dice:
    • cómo instalar (npm i)
    • cómo correr
    • qué variables de entorno necesita
  • No subas secretos al repo (ni “nomás tantito”).

Tip de guerra: si ya subiste un .env a GitHub una vez, aunque lo borres, puede quedar en el historial. Rota llaves. Sí, duele. Pero duele más un leak en production.

Paso 1: separa configuración (env vars) de tu código

En local sueles tener algo así:

# .env (NO se sube)
DATABASE_URL=...
JWT_SECRET=...
API_URL=http://localhost:3001

En producción:

  • Nunca uses localhost.
  • API_URL apunta al dominio real de tu backend.

Ejemplo Node/Express:

const port = process.env.PORT || 3001;
app.listen(port, () => console.log(`Listening on ${port}`));

Esto evita el error típico estilo Heroku/Render: tu app ignora el puerto del proveedor, “corre”, pero nadie puede entrar.

Paso 2: deploy del backend (Render) con un Express básico

2.1 Requisitos mínimos

  • Un repo con tu backend.
  • package.json con scripts:
{
  "scripts": {
    "start": "node index.js",
    "dev": "nodemon index.js"
  }
}

2.2 Crear el servicio

  1. En Render: New + → Web Service.
  2. Conecta tu repo.
  3. Define:
    • Build command: npm install
    • Start command: npm start
  4. Agrega env vars en el panel (no en tu código).
  5. Deploy.

2.3 Prueba que vive

Crea un endpoint de salud:

app.get('/health', (req, res) => res.json({ ok: true }));

Abre https://tu-backend.onrender.com/health.
Si eso no responde, no te saltes al frontend. Primero deja el backend estable.

Paso 3: deploy del frontend (Vercel) sin drama

  1. En Vercel: Add New → Project.
  2. Importa repo.
  3. Que detecte el framework (Vite/Next/etc.).
  4. Configura env vars:
    • VITE_API_URL o NEXT_PUBLIC_API_URL según tu stack.

Ejemplo Vite:

VITE_API_URL=https://tu-backend.onrender.com

En tu código:

const apiUrl = import.meta.env.VITE_API_URL;
fetch(`${apiUrl}/health`);

Deploy.

Momento real: si jala en local pero en prod no, muchas veces es porque la env var en Vercel está mal escrita o la pusiste en Preview y no en Production. Pasa más de lo que nos gusta admitir.

Deploy o no existe: la primera vez que pones algo real en internet - visual explicativa 1
Visual de apoyo: Cuando tu app “jala en mi compu” y en internet se muere

Paso 4: conecta frontend y backend (CORS, rutas y headers)

El error más humillante del primer deploy: CORS.

En Express:

npm i cors
import cors from 'cors';

const allowed = [
  'http://localhost:5173',
  'https://tu-frontend.vercel.app'
];

app.use(cors({
  origin: function (origin, cb) {
    if (!origin) return cb(null, true); // Postman/health checks
    if (allowed.includes(origin)) return cb(null, true);
    return cb(new Error('Not allowed by CORS'));
  }
}));

Tradeoff real:

  • Permitir * te desbloquea… pero si hay auth/cookies, te abres puertas que no querías abrir.
  • Mejor whitelist de orígenes y actualízala cuando cambies dominio.

Paso 5: dominio + DNS (la parte que se siente como brujería)

No es obligatorio, pero cambia el juego: deja de verse “demo” y se empieza a sentir “producto”. Y si le estás chambeando para un cliente, un dominio es el mínimo para que no te regateen.

5.1 Conceptos que sí necesitas

  • A record: apunta un dominio a una IP.
  • CNAME: apunta un subdominio a otro dominio (común con Vercel).
  • TTL: cuánto tarda en propagarse. Si lo pones alto, cualquier cambio te persigue horas.

5.2 Setup típico

  • www.tudominio.com → CNAME a Vercel
  • api.tudominio.com → CNAME a Render (si te lo permite) o al hostname del backend

Realidad mexicana: si compraste dominio en un proveedor barato, su panel DNS puede ser un laberinto. Respira, toma screenshots, y revisa dos veces que no metiste espacios raros o puntos extra.

Paso 6: HTTPS sin llorar

La buena noticia: Vercel y Render te ponen HTTPS casi automático.
Lo que sí pasa:

  • El certificado no se emite hasta que DNS esté bien.
  • Puede tardar. Si traes deadline encima, no lo dejes para el último día.

Paso 7: logs, monitoreo mínimo y cómo no quedarte ciego

Cuando algo falla en production, ya no tienes tu consola feliz de local. Necesitas:

  • Logs del proveedor (Render: Logs).
  • Logs del frontend (Vercel: Build logs / Functions logs si aplica).

En backend, loguea errores con algo útil:

app.use((err, req, res, next) => {
  console.error('[ERROR]', err.message);
  res.status(500).json({ error: 'Internal error' });
});

No metas datos sensibles al log (tokens, passwords). Luego alguien pide “mándame un screenshot del log” y se te arma el problema gratis.

Paso 8: rollback (porque la vida pega)

Subes un cambio, se rompe todo y tu jefe te escribe “¿qué moviste?” mientras tú sigues en pijama.

  • Vercel: puedes promover un deploy anterior.
  • Render: revisa el historial de deploys y redeploy del commit previo.

Plan simple:

  1. Identifica el último commit “bueno”.
  2. Re-deploy ese commit.
  3. Con el servicio arriba, debuggeas con calma.

Tradeoff real: CI/CD rápido te da velocidad, pero también te deja romper producción más rápido. La solución no es “no deployes”, es tener rollback y pruebas mínimas.

Screenshots sugeridos

  • Panel de Vercel mostrando:
    • Deploy exitoso
    • Variables de entorno configuradas
    • Dominio conectado
  • Panel de Render mostrando:
    • Build logs
    • Env vars
    • URL pública del servicio
  • Configuración DNS (A/CNAME) en tu registrador
  • Error CORS en consola del navegador y la corrección
  • Endpoint /health respondiendo en el navegador

Errores comunes y cómo salir vivo

1) “Funciona local, en producción 404/500”

Causa: rutas distintas, build que no corre, o start command incorrecto.

  • Revisa build logs.
  • Asegúrate que existe npm run build si tu framework lo necesita.
  • Verifica Start Command.

2) Variables de entorno undefined

Causa: nombre mal escrito o no reiniciaste el deploy.

  • Revisa mayúsculas y prefijos (VITE_, NEXT_PUBLIC_).
  • En muchos proveedores, cambiar env vars requiere redeploy.

3) CORS bloqueando todo

Causa: origin no permitido.

  • Agrega tu dominio real a la whitelist.
  • No uses * si hay cookies/sesión.

4) Base de datos “se cae” o no conecta

Causa: IP allowlist, URL mal, SSL requerido.

  • Copia DATABASE_URL directo del proveedor.
  • Revisa si necesita ?sslmode=require (común en Postgres administrado).

5) Tu backend se duerme (free tier) y la primera petición tarda años

Causa: planes gratis con cold start.

  • Solución real: plan de pago.
  • Solución de supervivencia: endpoint ping (no ideal, pero pasa mucho en proyectos personales).
Deploy o no existe: la primera vez que pones algo real en internet - visual explicativa 2
Visual de apoyo: Qué vas a sacar de aquí

Checklist final (deploy o no existe)

  • Tengo un repo con build y start claros.
  • Mis secretos NO están en Git.
  • Backend responde /health en internet.
  • Frontend consume API_URL desde env vars (no hardcodeado).
  • CORS permite mi dominio real.
  • Tengo HTTPS activo.
  • Dominio y DNS apuntan bien (y entendí qué es CNAME/A).
  • Sé dónde ver logs.
  • Sé hacer rollback al último deploy estable.
  • Tengo un “README para mi yo del futuro”.

FAQ

1) ¿Cuál es el deploy más fácil para empezar?

Si es solo frontend: Vercel o Netlify. Si hay backend: frontend en Vercel + backend en Render suele ser la ruta menos dolorosa.

2) ¿Necesito comprar dominio desde el día 1?

No, pero ayuda. Para portfolio y demos rápidas, el subdominio del proveedor está bien. Si ya lo van a usar clientes/usuarios, dominio propio se siente más serio.

3) ¿Qué pasa si mi app usa .env y lo subo por error?

Asume compromiso: rota keys (API keys, DB passwords), invalida tokens si aplica y limpia historial si es necesario. Borrarlo del repo no basta.

4) ¿Cómo sé si mi problema es DNS o mi servidor?

Si el dominio no resuelve o apunta a otro lado, es DNS. Si resuelve pero da 500/502, es tu app o el servicio. Prueba primero con la URL directa del proveedor (sin dominio).

5) ¿CI/CD es obligatorio desde el inicio?

No, pero tener deploy automático por push te ahorra un buen de workflow manual. El mínimo: que el deploy sea reproducible y que puedas regresar a una versión estable.

Siguiente episodio

Ya que tu app vive en internet, toca lo que separa “demo” de “producto”: logs de verdad, métricas y alertas.
Porque el bug que no ves igual te cobra la factura… nomás que a las 3 am.