En este artículo, vamos a explorar el proceso completo de despliegue de una aplicación de chat moderna utilizando una variante del stack MERN. En lugar del tradicional Node.js, implementaremos Bun como entorno de ejecución tanto para el frontend como para el backend, aprovechando su velocidad y eficiencia. Todo esto será orquestado mediante Docker y Docker Compose en un VPS para garantizar un entorno consistente y fácil de mantener.
Visión General del Proyecto
Nuestra aplicación de chat consta de tres componentes principales:
- Frontend: Desarrollado con React y Vite
- Backend: Implementado con Express.js
- Base de datos: MongoDB
Lo que hace único este proyecto es el uso de Bun como entorno de ejecución, reemplazando a Node.js en el tradicional stack MERN, y el despliegue completo utilizando Docker en un VPS.
[Imagen: Diagrama de arquitectura mostrando los componentes de la aplicación y cómo interactúan entre sí]
Configuración de Dominio y DNS
Nuestro proyecto utilizará subdominios específicos para el frontend y el backend, basados en el dominio principal eliasablan.com. Comenzamos configurando estos subdominios en el panel de administración de Hostinger.
Paso 1: Crear Registros DNS
Necesitamos configurar:
chat.eliasablan.compara el frontendapi.chat.eliasablan.compara el backend
Para cada subdominio, creamos dos registros en nuestro DNS:
- Registro A que apunta a la dirección IPv4 de nuestro VPS
- Registro AAAA que apunta a la dirección IPv6 de nuestro VPS
[Imagen: Capturas de pantalla del panel de DNS de Hostinger mostrando la configuración de los registros A y AAAA]
Estructura del Proyecto
Nuestro proyecto está organizado en dos directorios principales:
frontend/: Contiene la aplicación de Reactbackend/: Contiene la API de Express.js
[Imagen: Árbol de directorios mostrando la estructura de archivos del proyecto]
Configuración de Scripts
Scripts del Backend
En el archivo package.json del backend, configuramos dos scripts:
"scripts": {
"dev": "bun --watch src/index.js",
"start": "bun src/index.js"
}El script dev incluye la bandera --watch para reiniciar automáticamente el servidor durante el desarrollo cuando se detectan cambios en los archivos. El script start se utiliza para el entorno de producción.
Scripts del Frontend
En el archivo package.json del frontend, configuramos tres scripts:
"scripts": {
"dev": "vite",
"build": "bunx --bun vite build",
"start": "vite --port 3000 --host 0.0.0.0"
}dev: Para desarrollo localbuild: Para generar los archivos optimizados para producciónstart: Para servir la aplicación en producción, exponiendo el puerto 3000 a todas las interfaces de red
Configuración de Docker y Base de Datos
Para nuestra base de datos MongoDB, utilizaremos Docker para crear un entorno aislado y seguro. Además, implementaremos Mongo Express para tener una interfaz visual de administración.
Configuración Inicial del Docker Compose
Creamos un archivo docker-compose.yml en la raíz del proyecto con los servicios para MongoDB y Mongo Express:
services:
mongo:
image: mongo
container_name: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
volumes:
- mongo_data:/data/db
mongo-express:
image: mongo-express
container_name: mongo-express
ports:
- 8081:8081
environment:
ME_CONFIG_MONGODB_ADMINUSERNAME: ${ME_CONFIG_MONGODB_ADMINUSERNAME}
ME_CONFIG_MONGODB_ADMINPASSWORD: ${ME_CONFIG_MONGODB_ADMINPASSWORD}
ME_CONFIG_MONGODB_SERVER: ${ME_CONFIG_MONGODB_SERVER}
ME_CONFIG_BASICAUTH_USERNAME: ${ME_CONFIG_BASICAUTH_USERNAME}
ME_CONFIG_BASICAUTH_PASSWORD: ${ME_CONFIG_BASICAUTH_PASSWORD}
depends_on:
- mongo
volumes:
mongo_data: null
networks: {}Este archivo define:
- Un servicio
mongoque utiliza la imagen oficial de MongoDB - Un servicio
mongo-expresspara la interfaz web de administración - Un volumen
mongo_datapara persistir los datos de la base de datos entre reinicios
[Imagen: Interfaz de Mongo Express después de la configuración inicial]
Dockerización del Backend y Frontend
Dockerfile para el Backend
Creamos un archivo Dockerfile en el directorio backend/:
FROM oven/bun:1
WORKDIR /app
COPY . .
RUN bun install
EXPOSE 5051
CMD ["bun", "run", "start"]Este Dockerfile:
- Utiliza la imagen oficial de Bun
- Establece el directorio de trabajo
- Copia los archivos del proyecto
- Instala las dependencias
- Expone el puerto 5051
- Define el comando para iniciar la aplicación
Dockerfile para el Frontend
Creamos un archivo Dockerfile en el directorio frontend/:
FROM oven/bun:1
WORKDIR /app
COPY . .
RUN bun install
ARG PORT
EXPOSE 3000
CMD ["bun", "run", "start"]Este Dockerfile sigue una estructura similar a la del backend, pero está configurado para servir la aplicación React.
Configuración del Docker Compose
Ahora actualizamos nuestro archivo docker-compose.yml para incluir los servicios de backend y frontend:
services:
mongo:
# ... (configuración anterior)
mongo-express:
# ... (configuración anterior)
backend:
image: ghcr.io/eliasablan/mern-chat-backend:latest
container_name: mern-chat-backend
ports:
- 5010:5000
environment:
MONGODB_URI: ${MONGODB_URI}
ORIGIN: ${ORIGIN}
PORT: ${PORT}
JWT_SECRET: ${JWT_SECRET}
CLOUDINARY_CLOUD_NAME: ${CLOUDINARY_CLOUD_NAME}
CLOUDINARY_API_KEY: ${CLOUDINARY_API_KEY}
CLOUDINARY_API_SECRET: ${CLOUDINARY_API_SECRET}
NODE_ENV: ${NODE_ENV}
depends_on:
- mongo
frontend:
image: ghcr.io/eliasablan/mern-chat-frontend:latest
container_name: mern-chat-frontend
ports:
- 5007:3000
environment:
VITE_API_BASE_URL: ${VITE_API_BASE_URL}
depends_on:
- backendLos nuevos servicios:
backend: Utiliza la imagen del backend desde GitHub Container Registryfrontend: Utiliza la imagen del frontend desde GitHub Container Registry
Ambos servicios exponen puertos y definen las variables de entorno necesarias.
[Imagen: Estructura completa del Docker Compose en Dockge o una herramienta similar]
Configuración de Variables de Entorno
Para gestionar las credenciales y configuraciones de forma segura, creamos un archivo .env en la raíz del proyecto:
# MONGO
MONGO_INITDB_ROOT_USERNAME=user
MONGO_INITDB_ROOT_PASSWORD=password
# MONGO-EXPRESS
ME_CONFIG_MONGODB_ADMINUSERNAME=user
ME_CONFIG_MONGODB_ADMINPASSWORD=password
ME_CONFIG_MONGODB_SERVER=mongo
ME_CONFIG_BASICAUTH_USERNAME=admin-ui
ME_CONFIG_BASICAUTH_PASSWORD=securepass123
# BACKEND
MONGODB_URI=mongodb://user:password@mongo:27017
ORIGIN=https://chat.eliasablan.com
PORT=5000
JWT_SECRET=
CLOUDINARY_CLOUD_NAME=
CLOUDINARY_API_KEY=
CLOUDINARY_API_SECRET=
NODE_ENV=production
# FRONTEND
VITE_API_BASE_URL=https://api.chat.eliasablan.com/api⚠️ Nota importante: En un entorno de producción real, deberías usar credenciales más seguras y almacenarlas de forma segura, por ejemplo mediante secretos de Docker o herramientas especializadas.
[Imagen: Panel de configuración de variables de entorno en Dockge]
Construcción y Publicación de Imágenes
Antes de poder desplegar nuestra aplicación en el VPS, necesitamos construir las imágenes de Docker y publicarlas en un registro de contenedores accesible. En este caso, utilizaremos GitHub Container Registry (ghcr.io).
Construcción de Imágenes en el Entorno Local
En la raíz de nuestro proyecto, donde se encuentra el archivo docker-compose.yml, ejecutamos:
docker compose buildEste comando construirá las imágenes de Docker para el frontend y el backend según las especificaciones de los Dockerfiles correspondientes.
[Imagen: Terminal mostrando el proceso de construcción de las imágenes]
Publicación de Imágenes en GitHub Container Registry
Una vez construidas las imágenes, las subimos al registro:
docker compose pushEste comando enviará las imágenes al GitHub Container Registry usando las rutas especificadas en el docker-compose.yml (ghcr.io/eliasablan/mern-chat-backend:latest y ghcr.io/eliasablan/mern-chat-frontend:latest).
📝 Nota: Para poder publicar en GitHub Container Registry, necesitas estar autenticado previamente con docker login ghcr.io utilizando tu token de GitHub.[Imagen: Terminal mostrando el proceso de publicación al registro de GitHub]
Configuración del Reverse Proxy con Nginx
Para que nuestros subdominios apunten a los servicios correctos, necesitamos configurar Nginx como reverse proxy. En este caso, utilizamos CloudPanel para facilitar esta configuración.
Pasos para configurar el Reverse Proxy en CloudPanel:
- Acceder al panel de administración de CloudPanel
- Crear un nuevo sitio para
chat.eliasablan.com - Configurar el proxy para apuntar al puerto
5007donde se ejecuta el frontend - Crear un nuevo sitio para
api.chat.eliasablan.com - Configurar el proxy para apuntar al puerto
5010donde se ejecuta el backend - Generar y configurar certificados SSL para ambos subdominios
[Imagen: Configuración de los sitios en CloudPanel]
[Imagen: Configuración del reverse proxy para el frontend]
[Imagen: Configuración del reverse proxy para el backend]
[Imagen: Certificados SSL configurados para ambos subdominios]
Despliegue Final y Pruebas
Con toda la configuración completada, procedemos al despliegue final en nuestro VPS.
Descarga de Imágenes en el VPS
Primero, necesitamos descargar las imágenes publicadas desde GitHub Container Registry:
docker pull ghcr.io/eliasablan/mern-chat-frontend:latest
docker pull ghcr.io/eliasablan/mern-chat-backend:latest[Imagen: Terminal del VPS mostrando el proceso de descarga de las imágenes]
Inicio de los Servicios
Una vez descargadas las imágenes, iniciamos todos los servicios con:
docker-compose up -dEste comando inicia todos los servicios definidos en nuestro archivo docker-compose.yml en modo "detached" (en segundo plano).
[Imagen: Terminal mostrando los servicios iniciándose correctamente]
Verificación del Despliegue:
- Acceder a
https://chat.eliasablan.compara verificar que el frontend está funcionando correctamente - Probar la API accediendo a
https://api.chat.eliasablan.com/api/statuso un endpoint similar - Verificar que la comunicación entre frontend y backend funciona correctamente
- Comprobar que los datos se almacenan correctamente en MongoDB
[Imagen: Aplicación de chat funcionando en el navegador]
[Imagen: Respuesta exitosa de la API]
[Imagen: Datos almacenados correctamente en Mongo Express]
Conclusión
Hemos completado con éxito el despliegue de una aplicación de chat moderna utilizando una variante del stack MERN con Bun, todo orquestado a través de Docker en un VPS. Este enfoque nos proporciona:
- Un entorno consistente y reproducible
- Aislamiento entre componentes
- Facilidad para realizar actualizaciones
- Persistencia de datos
- Seguridad mediante HTTPS
El flujo de trabajo completo, desde el desarrollo hasta el despliegue, puede resumirse en:
- Desarrollo de los componentes frontend y backend
- Configuración de Docker y Docker Compose
- Construcción y publicación de imágenes
- Configuración del dominio y DNS
- Configuración del reverse proxy
- Despliegue en el VPS
Si tienes dudas sobre algún paso en el proceso, no dudes en contactarme por cualquier medio. Intentaré responder sin tardar.
Este artículo forma parte de una serie sobre despliegue de aplicaciones web modernas. ¡Mantente atento para más contenido técnico!