Mejores Prácticas de AWS — Backend Laravel + Aurora
Date: 2026-07-25 Status: ✅ Implementado en Terraform (infra/terraform/), revisado por los agentes devops y security — ver doc/architecture/infra-consensus.md para los hallazgos del review y qué se corrigió como consecuencia.
1. Dos caminos válidos para correr el backend en AWS
Opción A — ECS Fargate (contenedores, más control)
Es la continuación natural de lo que ya armamos en docker-compose.yml: la misma imagen Docker del backend (backend/Dockerfile, ya multi-stage y optimizada) se sube a Amazon ECR y corre en ECS Fargate (contenedores administrados, sin gestionar servidores EC2 a mano).
- Web: servicio ECS Fargate detrás de un Application Load Balancer (TLS con ACM).
- Queue worker: un segundo servicio ECS Fargate corriendo
php artisan queue:work(mismo patrón que elbackend-queuede docker-compose). - Scheduler: un tercer servicio (o una EventBridge Scheduled Rule que invoca una Lambda o una task de ECS puntual cada 30 min) ejecutando
php artisan schedule:run— evita correr un contenedor "siempre prendido" solo para el cron. - Ventaja: control total, mismo Docker que en dev, fácil de debuggear.
- Costo: pagás contenedores corriendo 24/7 (aunque Fargate Spot puede bajar el costo del queue worker, que tolera interrupciones).
Opción B — Laravel Vapor (serverless sobre AWS Lambda)
Vapor es la plataforma oficial de Laravel para desplegar sobre AWS Lambda — vos seguís siendo dueño de la cuenta de AWS (Vapor no es un hosting de terceros, es una capa de automatización sobre tu propia infraestructura AWS). Empaqueta el backend, workers de queue y el scheduler como funciones Lambda, con auto-scaling real (incluyendo "scale to zero" cuando no hay tráfico).
- Ventaja: cero servidores/contenedores que mantener corriendo; paga por uso real; abstrae VPC, API Gateway, y el empaquetado de Lambda.
- Contras: cold starts ocasionales (mitigables); menos control fino que ECS; conviene cuando el tráfico es variable/impredecible más que constante.
Recomendación inicial: empezar con ECS Fargate (Opción A) para el MVP1 — es más fácil de razonar 1:1 con el docker-compose.yml que ya tenemos, y no hay urgencia de auto-scaling extremo en esta etapa. Vapor queda como buena opción a evaluar si el tráfico real termina siendo muy variable entre países/horarios. Definir con devops/architect antes de provisionar Staging.
2. Base de datos: Amazon Aurora PostgreSQL-Compatible Edition
Ver doc/architecture/ADR-003-database.md para el razonamiento completo. Puntos operativos:
- Multi-AZ habilitado desde el día 1 en producción (failover automático).
- Backups automáticos con retención de al menos 7 días (14+ recomendado en producción).
- Conexión desde ECS/Lambda solo dentro de la VPC privada — la base nunca debe tener una IP pública ni un security group abierto a
0.0.0.0/0. - Considerar Aurora Serverless v2 en Staging (escala a casi cero cuando no se usa, ahorra costo) y una instancia provisionada de tamaño chico en Producción (más previsible en costo y latencia para un sistema que maneja dinero real).
3. Secretos: AWS Secrets Manager (nunca variables de entorno en texto plano en producción)
Nada de esto se pushea nunca a Git (ver .gitignore):
- Credenciales de la base de datos (Aurora).
FIREBASE_CREDENTIALS(JSON de la service account de Firebase Admin).SOTEREX_USERNAME/SOTEREX_PASSWORD.APP_KEYde Laravel.
Todos estos viven en AWS Secrets Manager, y ECS Fargate (o Vapor) los inyecta como variables de entorno del contenedor/función en runtime — nunca como archivo commiteado ni como GitHub Secret de texto plano si se puede evitar (los GitHub Secrets de los workflows de deploy son la excepción aceptable, porque GitHub los enmascara y no hay otra forma de pasarle credenciales de AWS al workflow que arranca el deploy).
4. IAM — mínimo privilegio
- Un rol de IAM específico por ambiente (Staging y Producción con roles separados, nunca compartidos) para que GitHub Actions asuma vía OIDC (
aws-actions/configure-aws-credentialsconrole-to-assume, sin Access Keys de larga duración guardadas en secrets — más seguro). - El rol de deploy de Staging no debe poder tocar recursos de Producción, y viceversa.
- La tarea de ECS (o la función Lambda de Vapor) tiene su propio rol de ejecución, separado del rol de deploy, con permisos acotados solo a lo que necesita en runtime (leer secrets puntuales, escribir logs a CloudWatch).
5. Observabilidad
- Logs del backend van a CloudWatch Logs (ya configurado en
config/logging.php— canalstderr, que en ECS/Lambda se captura automáticamente). - Alarmas de CloudWatch sobre: errores 5xx del ALB, fallas del job
RunSoterexSendRequest(métrica custom o parseo de logs), uso de CPU/memoria de Aurora. - Considerar AWS X-Ray o Laravel Telescope (solo en Staging, nunca expuesto en Producción) para tracing de requests lentos.
6. Networking
- VPC con subnets privadas para Aurora y las tasks de ECS; subnets públicas solo para el ALB.
- Security Groups específicos por servicio (ALB → ECS en el puerto de la app; ECS → Aurora en el puerto de Postgres; nada más abierto).
- Redis (ElastiCache en AWS, equivalente al Redis de docker-compose) también en subnet privada.
7. Costos — tagging desde el día 1
Todo recurso de AWS con tags Project=soterex, Environment=staging|production, para poder después separar el costo de este proyecto del resto de la infraestructura de CIS Latam.
Próximos pasos
Este documento es un punto de partida, no una arquitectura cerrada. Antes de provisionar Staging real, architect + devops deben:
- Confirmar Opción A (ECS Fargate) vs Opción B (Vapor) con el volumen esperado real.
- Definir el detalle de VPC/subnets/security groups como Terraform (o CDK) versionado en
infra/. - Provisionar Aurora de Staging y completar
doc/environments/staging.md.

