This document describes the AWS infrastructure architecture for the Hasura Blog application deployed using Terraform.
┌─────────────────┐
│ Internet │
└────────┬────────┘
│
│ HTTPS/HTTP
│
┌────────▼────────┐
│ Application │
│ Load Balancer │
│ (Public) │
└────────┬────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
│ Port 80 │ Port 8080 │
│ (Next.js) │ (Hasura) │
│ │ │
┌───────────▼────────┐ ┌────────▼───────────┐ │
│ Target Group │ │ Target Group │ │
│ (Next.js) │ │ (Hasura) │ │
└───────────┬────────┘ └────────┬───────────┘ │
│ │ │
┌───────────────┴────────────────────┴───────────────────┴───────┐
│ VPC (10.0.0.0/16) │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ Public Subnets │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ 10.0.0.0/24 │ │ 10.0.1.0/24 │ │ │
│ │ │ us-east-1a │ │ us-east-1b │ │ │
│ │ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │
│ │ │ │ NAT Gateway│ │ │ │ NAT Gateway│ │ │ │
│ │ │ └────────────┘ │ │ └────────────┘ │ │ │
│ │ └──────────────────┘ └──────────────────┘ │ │
│ └────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┴──────────────────────────┐ │
│ │ Private Subnets │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ 10.0.10.0/24 │ │ 10.0.11.0/24 │ │ │
│ │ │ us-east-1a │ │ us-east-1b │ │ │
│ │ │ │ │ │ │ │
│ │ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │
│ │ │ │ECS Fargate │ │ │ │ECS Fargate │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ ┌────────┐ │ │ │ │ ┌────────┐ │ │ │ │
│ │ │ │ │Next.js │ │ │ │ │ │Next.js │ │ │ │ │
│ │ │ │ └────────┘ │ │ │ │ └────────┘ │ │ │ │
│ │ │ │ │ │ │ │ │ │ │ │
│ │ │ │ ┌────────┐ │ │ │ │ ┌────────┐ │ │ │ │
│ │ │ │ │ Hasura │ │ │ │ │ │ Hasura │ │ │ │ │
│ │ │ │ └────────┘ │ │ │ │ └────────┘ │ │ │ │
│ │ │ └────────────┘ │ │ └────────────┘ │ │ │
│ │ │ │ │ │ │ │
│ │ │ ┌────────────┐ │ │ ┌────────────┐ │ │ │
│ │ │ │RDS Postgres│ │ │ │RDS Postgres│ │ │ │
│ │ │ │ (Primary) │ │ │ │ (Standby) │ │ │ │
│ │ │ └────────────┘ │ │ └────────────┘ │ │ │
│ │ └──────────────────┘ └──────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
┌──────────────────────────────┐
│ CloudWatch Log Groups │
│ - /ecs/hasura-blog/hasura │
│ - /ecs/hasura-blog/nextjs │
└──────────────────────────────┘
- CIDR Block: 10.0.0.0/16
- DNS Hostnames: Enabled
- DNS Support: Enabled
- Availability Zones: 2 (us-east-1a, us-east-1b)
Public Subnets (Internet-facing):
10.0.0.0/24in us-east-1a10.0.1.0/24in us-east-1b- Connected to Internet Gateway
- Hosts NAT Gateways and ALB
Private Subnets (Internal):
10.0.10.0/24in us-east-1a10.0.11.0/24in us-east-1b- Connected to NAT Gateways for outbound traffic
- Hosts ECS tasks and RDS instances
- Enables communication between VPC and internet
- Attached to VPC
- Count: 2 (one per AZ for high availability)
- Purpose: Allow private subnet resources to access internet
- Elastic IPs: 2 (one per NAT Gateway)
- Public Route Table: Routes internet traffic to Internet Gateway
- Private Route Tables: Route internet traffic to NAT Gateways (one per AZ)
Inbound Rules:
- Port 80 (HTTP) from 0.0.0.0/0
- Port 443 (HTTPS) from 0.0.0.0/0
- Port 8080 (Hasura Console) from 0.0.0.0/0
Outbound Rules:
- All traffic allowed
Inbound Rules:
- Port 3000 (Next.js) from ALB Security Group
- Port 8080 (Hasura) from ALB Security Group
Outbound Rules:
- All traffic allowed
Inbound Rules:
- Port 5432 (PostgreSQL) from ECS Security Group
Outbound Rules:
- All traffic allowed
- Type: Application Load Balancer
- Scheme: Internet-facing
- Subnets: Public subnets in both AZs
- Deletion Protection: Enabled for production
HTTP Listener (Port 80):
- Default action: Forward to Next.js target group
- Rule: Forward
/v1/*,/v2/*,/healthzto Hasura target group
Hasura Console Listener (Port 8080):
- Default action: Forward to Hasura target group
Next.js Target Group:
- Port: 3000
- Protocol: HTTP
- Target Type: IP
- Health Check:
/endpoint - Deregistration Delay: 30 seconds
Hasura Target Group:
- Port: 8080
- Protocol: HTTP
- Target Type: IP
- Health Check:
/healthzendpoint - Deregistration Delay: 30 seconds
- Launch Type: Fargate (serverless)
- Container Insights: Enabled
- Services: 2 (Hasura and Next.js)
- Task Count: 2 (configurable)
- CPU: 512 units (0.5 vCPU)
- Memory: 1024 MB (1 GB)
- Network Mode: awsvpc
- Container Port: 8080
- Health Check:
/healthzendpoint
Environment Variables:
HASURA_GRAPHQL_DATABASE_URL: RDS connection stringHASURA_GRAPHQL_ADMIN_SECRET: Admin secretHASURA_GRAPHQL_JWT_SECRET: JWT configurationHASURA_GRAPHQL_ENABLE_CONSOLE: trueHASURA_GRAPHQL_DEV_MODE: false
- Task Count: 2 (configurable)
- CPU: 512 units (0.5 vCPU)
- Memory: 1024 MB (1 GB)
- Network Mode: awsvpc
- Container Port: 3000
- Health Check:
/endpoint
Environment Variables:
NEXT_PUBLIC_HASURA_GRAPHQL_URL: Hasura GraphQL endpointHASURA_GRAPHQL_ADMIN_SECRET: Admin secretNEXTAUTH_SECRET: NextAuth secretNEXTAUTH_URL: Application URLJWT_SECRET: JWT secret
- Engine: PostgreSQL 15.4
- Instance Class: db.t3.micro (configurable)
- Storage: 20 GB GP3 with auto-scaling to 40 GB
- Multi-AZ: Single-AZ deployment (can be upgraded to Multi-AZ)
- Storage Encryption: Enabled
- Automated Backups: Enabled (7 days retention)
- Backup Window: 03:00-04:00 UTC
- Maintenance Window: Monday 04:00-05:00 UTC
CloudWatch Logs:
- PostgreSQL logs
- Upgrade logs
- Purpose: Allows ECS to pull images and write logs
- Managed Policy: AmazonECSTaskExecutionRolePolicy
- Permissions:
- ECR image pull
- CloudWatch Logs write
- Secrets Manager access (if needed)
- Purpose: Allows running tasks to access AWS services
- Use Case: Currently minimal, can be extended for S3, DynamoDB, etc.
/ecs/hasura-blog-prod/hasura: Hasura container logs/ecs/hasura-blog-prod/nextjs: Next.js container logs
Configuration:
- Retention: 7 days (configurable)
- Log Driver: awslogs
- Stream Prefix: ecs
- Client sends HTTP request to ALB DNS name
- ALB receives request and performs health check on targets
- ALB routes request based on path:
/→ Next.js target group/v1/graphql→ Hasura target group/console(port 8080) → Hasura target group
- Target Group forwards request to healthy ECS task
- ECS Task (Next.js or Hasura) processes request
- Hasura queries RDS PostgreSQL if needed
- Response flows back through the same path
- Hasura ECS Task initiates connection to RDS
- ECS Security Group allows outbound connection to RDS
- RDS Security Group allows inbound connection from ECS
- RDS authenticates and processes query
- Response returns to Hasura task
- ECS Task in private subnet needs internet access
- Route Table directs traffic to NAT Gateway
- NAT Gateway translates private IP to public Elastic IP
- Internet Gateway routes traffic to internet
- Response flows back through NAT Gateway to ECS task
- Multi-AZ Deployment: Resources distributed across 2 availability zones
- Multiple Tasks: 2 tasks per service for redundancy
- NAT Gateways: One per AZ for HA
- RDS: Can be upgraded to Multi-AZ for automatic failover
- ALB Health Checks: Monitor container health
- ECS Health Checks: Container-level health monitoring
- RDS: Automated monitoring and recovery
- ECS Service: Automatically replaces unhealthy tasks
- ALB: Automatically routes traffic to healthy targets
- RDS: Automated backup and point-in-time recovery
ECS Services:
hasura_desired_count = 2 # Increase to 3, 4, etc.
nextjs_desired_count = 2 # Increase to 3, 4, etc.Auto Scaling (not implemented, can be added):
- Target Tracking Scaling: Based on CPU/Memory utilization
- Step Scaling: Based on CloudWatch alarms
- Scheduled Scaling: Based on time patterns
ECS Tasks:
hasura_cpu = 512 # Increase to 1024, 2048
hasura_memory = 1024 # Increase to 2048, 4096RDS:
db_instance_class = "db.t3.micro" # Upgrade to db.t3.small, db.t3.medium
allocated_storage = 20 # Increase storage- Private subnets for application and database
- Security groups with least privilege
- No direct internet access for ECS tasks
- RDS encryption at rest
- Secrets stored as environment variables (can be moved to Secrets Manager)
- VPC isolation
- IAM roles with least privilege
- No public database access
- Admin console access controlled
- ECS Fargate: ~$30-40/month (4 tasks, 0.5 vCPU, 1 GB each)
- RDS db.t3.micro: ~$15-20/month
- ALB: ~$20/month
- NAT Gateway: ~$60-70/month (2 gateways)
- Data Transfer: Variable
- Total: ~$125-150/month
- Use Single NAT Gateway: Save ~$32/month
- Trade-off: Reduced availability if NAT Gateway fails
- Reduce Task Count: Save ~$15/month per task
- Trade-off: Reduced redundancy
- Use Savings Plans: 20-30% discount on ECS and RDS
- Reserved Instances: For RDS if long-term commitment possible
- ECS: CPU, Memory, Network utilization
- ALB: Request count, latency, HTTP codes
- RDS: CPU, connections, storage, IOPS
- Application logs from containers
- RDS logs (PostgreSQL, upgrades)
- High CPU usage
- High memory usage
- Elevated error rates
- RDS storage threshold
- RDS Automated Backups: 7 days retention
- RDS Snapshots: Manual snapshots before major changes
- Terraform State: Store in S3 with versioning
Database Recovery:
# Restore from automated backup
aws rds restore-db-instance-to-point-in-time \
--source-db-instance-identifier hasura-blog-prod-postgres \
--target-db-instance-identifier hasura-blog-restored \
--restore-time 2024-01-01T12:00:00ZInfrastructure Recovery:
# Re-apply Terraform configuration
terraform apply- RTO (Recovery Time Objective): ~15 minutes
- RPO (Recovery Point Objective): Up to 5 minutes (RDS automated backups)
- Auto Scaling: Implement ECS auto-scaling based on metrics
- HTTPS/SSL: Add ACM certificate and HTTPS listener
- Custom Domain: Add Route53 DNS configuration
- WAF: Add Web Application Firewall for security
- Secrets Manager: Move secrets from environment variables
- Multi-Region: Add replica in another region for DR
- CDN: Add CloudFront for static content
- Monitoring: Add X-Ray tracing and detailed monitoring
- CI/CD: Add pipeline for automated deployments
- Cost Management: Add budget alerts and cost optimization