SincroDev Logo SincroDev

Deploy de una app Astro + API Python en un VPS con Docker


Publicar una app en un VPS no debería convertirse en una colección de comandos sueltos, cambios manuales y reinicios nerviosos.

Si tienes:

  • un frontend en Astro
  • una API en Python
  • un VPS con Docker

puedes montar un flujo bastante razonable sin meterte todavía en Kubernetes, pipelines enormes ni complejidad innecesaria.

En este tutorial voy a mostrar una forma práctica de desplegar una app Astro + API Python usando la estructura real de este proyecto:

  • frontend estático compilado y servido con Nginx
  • backend Python con FastAPI y Uvicorn
  • docker compose para producción
  • Makefile con comandos de despliegue y actualización

Qué vas a construir

La arquitectura final es esta:

Internet

Nginx del VPS / reverse proxy

127.0.0.1:5100 -> frontend Astro servido por Nginx
127.0.0.1:5200 -> API Python con FastAPI

La idea clave es que los contenedores no se exponen públicamente a todo Internet, sino solo a 127.0.0.1, y el acceso externo lo controla tu reverse proxy del VPS.

Cuándo conviene este enfoque

Tiene sentido cuando:

  • estás desplegando una app pequeña o mediana
  • quieres un flujo mantenible sin montar una plataforma compleja
  • necesitas separar frontend y backend
  • quieres dejar un deploy reproducible en el repositorio

No es la mejor solución cuando:

  • necesitas alta disponibilidad real con múltiples nodos
  • operas múltiples entornos complejos con fuerte automatización
  • requieres escalado horizontal serio desde el día uno

Stack usado en este proyecto

Este repo ya está preparado con:

  • docker-compose.yml para desarrollo
  • docker-compose.prod.yml para producción
  • docker/frontend/Dockerfile.prod para compilar Astro y servirlo con Nginx
  • docker/backend/Dockerfile.prod para correr FastAPI en producción
  • Makefile con comandos de deploy

Archivos clave:

Requisitos previos

Antes de empezar, necesitas:

  • un VPS Linux
  • Docker y Docker Compose instalados
  • acceso por SSH
  • un dominio apuntando al VPS
  • un reverse proxy o Nginx en el host
  • el proyecto versionado en Git

Paso 1: Entender la separación entre desarrollo y producción

En desarrollo, este proyecto monta código fuente como volumen y expone puertos para trabajar localmente.

En producción, cambia la estrategia:

  • no se montan volúmenes de código del frontend
  • Astro se compila durante el build
  • el frontend se sirve desde Nginx dentro del contenedor
  • el backend corre con configuración productiva
  • los puertos se bindean a 127.0.0.1

Ese cambio está en docker-compose.prod.yml.

Ejemplo importante del frontend:

ports:
  - "127.0.0.1:${FRONTEND_PORT:-5100}:80"

Y del backend:

ports:
  - "127.0.0.1:${BACKEND_PORT:-5200}:8000"

Eso evita dejar los servicios expuestos directamente hacia afuera.

Paso 2: Cómo se construye el frontend

El frontend usa una imagen multi-stage en docker/frontend/Dockerfile.prod.

La lógica es:

  1. instalar dependencias
  2. ejecutar npm run build
  3. copiar dist/ a una imagen ligera de Nginx

La ventaja es clara:

  • la imagen final es más liviana
  • no necesitas Node.js en runtime
  • el frontend queda servido como sitio estático

Paso 3: Cómo se construye el backend

El backend en docker/backend/Dockerfile.prod hace algo más simple:

  1. parte de python:3.11-slim
  2. instala requirements.txt
  3. copia el código
  4. crea /app/data
  5. arranca Uvicorn

Comando de producción:

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "1"]

En este proyecto además se monta un volumen para persistir contactos:

volumes:
  - ./backend/data:/app/data

Eso evita perder datos al recrear el contenedor.

Paso 4: Estructura mínima en el VPS

Una estructura razonable en servidor sería:

/var/www/sincrodev.com/
  ├── docker-compose.yml
  ├── docker-compose.prod.yml
  ├── Makefile
  ├── frontend/
  ├── backend/
  └── docker/

En este proyecto, esa ruta ya está reflejada en el Makefile:

VPS_HOST = root@72.60.13.147
VPS_PATH = /var/www/sincrodev.com/

Paso 5: Levantar producción manualmente

Si quieres hacer un primer deploy manual, dentro del VPS puedes ejecutar:

docker compose -f docker-compose.yml -f docker-compose.prod.yml build
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d

O, usando el Makefile del proyecto:

make prod-build
make prod-start

Eso construye y levanta:

  • sincrodev-frontend
  • sincrodev-backend

Paso 6: Verificar que los servicios estén vivos

El archivo de producción ya incluye healthchecks.

Frontend:

healthcheck:
  test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost/"]

Backend:

healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:8000/api/health"]

Puedes revisar estado con:

make prod-status

Y logs con:

make prod-logs

Paso 7: Añadir un reverse proxy delante

Como los contenedores escuchan en 127.0.0.1, necesitas un reverse proxy en el host del VPS.

La idea sería algo como:

sincrodev.com        -> 127.0.0.1:5100
sincrodev.com/api    -> 127.0.0.1:5200

Eso te permite:

  • manejar SSL en un solo lugar
  • separar acceso público de puertos internos
  • mantener más limpio el despliegue

No estoy incluyendo la configuración completa de Nginx del host en este tutorial, pero ese sería el siguiente paso natural si aún no lo tienes montado.

Paso 8: Automatizar el deploy con Make

Uno de los puntos más útiles del proyecto es que ya tiene un comando de deploy remoto en Makefile.

Target:

deploy-vps:
	@echo ">>> Pusheando cambios a origin..."
	git push origin master
	@echo ">>> Conectando al VPS y desplegando..."
	ssh $(VPS_HOST) 'cd $(VPS_PATH) && git pull origin master && make prod-update'

Eso te permite lanzar desde local:

make deploy-vps

Y ejecutar el flujo:

  1. push a origin
  2. SSH al VPS
  3. git pull
  4. rebuild
  5. recreación de contenedores

Es simple, entendible y suficiente para muchos proyectos chicos y medianos.

Paso 9: Cómo funciona prod-update

El target prod-update hace algo importante:

  • construye imágenes de producción
  • detiene contenedores viejos
  • los elimina
  • garantiza la red Docker
  • levanta de nuevo frontend y backend

Eso concentra el procedimiento operativo en un solo punto del proyecto.

Es mejor que depender de una secuencia manual recordada “de memoria”.

Errores comunes

1) Exponer puertos al público sin necesidad

Si publicas 0.0.0.0:5100 o 0.0.0.0:5200 sin un motivo claro, estás abriendo más superficie de ataque de la necesaria.

2) No persistir datos importantes

Si el backend escribe archivos o datos locales y no montas volumen, perderás información al recrear contenedores.

3) Mezclar desarrollo con producción

Montar el código como volumen en producción suele ser mala señal. En producción quieres imágenes construidas, no un entorno mutable.

4) No tener healthchecks

Sin healthchecks, un contenedor “arriba” puede estar roto y no darte ninguna pista rápida.

5) No dejar el deploy en el repositorio

Si el procedimiento de deploy vive en la cabeza de una persona, el sistema no es mantenible.

Qué mejoraría después de este punto

Una vez que esto funcione bien, los siguientes pasos razonables son:

  • separar entornos (staging, production)
  • agregar backups automatizados
  • rotación y centralización de logs
  • pipeline CI/CD
  • monitoreo básico
  • estrategia de rollback más explícita

No necesitas todo eso el primer día. Pero sí conviene saber hacia dónde evolucionar.

Resumen del flujo

Con esta arquitectura:

  1. construyes frontend y backend en imágenes separadas
  2. levantas producción con docker compose y override productivo
  3. publicas solo puertos locales
  4. dejas el acceso público al reverse proxy
  5. centralizas actualización con make deploy-vps

No es una plataforma “enterprise”, pero sí una base muy digna para desplegar software real sin convertir la operación en un caos.

Cierre

Un buen deploy no es solo “que funcione ahora”. Es que otro yo de dentro de tres meses pueda entender cómo está montado, actualizarlo sin miedo y detectar rápido si algo se rompió.

Ese estándar ya te pone por encima de muchos despliegues improvisados.

Si necesitas adaptar este esquema a tu proyecto, dejar un VPS operativo o diseñar una arquitectura un poco más sólida para producción, puedes escribirme desde Sobre Mí.