// cloud · aws

AWS: the everything store.

The most control, the most services, the most footguns. Here's the opinionated path that keeps a Ruby app boring and stable.

AWS has ~200 services. You need six: ECS on Fargate, Elastic Beanstalk, Aurora Postgres, Application Load Balancer, S3, CloudFront, and Secrets Manager. That's the whole stack for 90% of Ruby apps.
39
regions supported
6
services you'll actually touch
~2 min
typical deploy time (Fargate rolling)
01 / 06

ECS on Fargate, not EC2

Fargate removes the entire 'who patches the box' question. You give it a container image and a task definition; it gives you a running process behind an ALB. Use EC2-backed ECS only when you need GPUs or specialized instance families.
hcl
# main.tf (excerpt) resource "aws_ecs_task_definition" "web" { family = "app-web" network_mode = "awsvpc" requires_compatibilities = ["FARGATE"] cpu = "1024" memory = "2048" execution_role_arn = aws_iam_role.exec.arn container_definitions = jsonencode([{ name = "web" image = "${aws_ecr_repository.app.repository_url}:latest" portMappings = [{ containerPort = 3000 }] environment = [{ name = "RAILS_ENV", value = "production" }] secrets = [{ name = "RAILS_MASTER_KEY", valueFrom = aws_secretsmanager_secret.master_key.arn }] healthCheck = { command = ["CMD-SHELL", "curl -f localhost:3000/up || exit 1"] } }]) }
02 / 06

Elastic Beanstalk for velocity

When you want managed infrastructure without writing Terraform, Elastic Beanstalk is the hidden gem. It handles capacity provisioning, load balancing, scaling, and health monitoring for you — just upload your code or container image and it wires up EC2, ALB, and CloudWatch automatically. Great for Rails teams that need to ship today and optimize tomorrow.
bash
# Deploy a Rails app to Elastic Beanstalk # 1. Install the EB CLI and initialize your app eb init -p ruby my-rails-app # 2. Create an environment and deploy eb create prod-env --single # 3. Deploy updates with a single command eb deploy prod-env
03 / 06

Aurora Postgres > RDS Postgres

For Ruby apps, Aurora Serverless v2 is the sweet spot: scales to zero-ish, handles bursts, and gives you read replicas without babysitting. Use plain RDS only if you need a specific Postgres extension Aurora doesn't ship.
04 / 06

Secrets: never in the task definition

Use Secrets Manager and reference by ARN in the task def (`secrets` block). Rotate the master key by rotating the secret — no redeploy needed for env-var-loaded secrets on task restart.
05 / 06

S3 + CloudFront for assets

Precompile assets into the image, then push them to S3 during deploy (`aws s3 sync`). Point config.asset_host at your CloudFront distribution. Cache-Control: `public, max-age=31536000, immutable` on hashed files.
06 / 06

Logs: FireLens > default awslogs

The default awslogs driver is fine to start. When you outgrow it — usually around the third microservice — switch to FireLens and pipe to your log tool of choice.

Gotchas we learned the hard way

  • !ALB target group health check timeouts default to 5s / 30s intervals. That's too aggressive for Rails cold boot. Bump to 10s / 60s and use a 2-minute grace period.
  • !Fargate ephemeral storage defaults to 20 GB. If you write big files in tmp/, raise it in the task definition or you'll hit ENOSPC at 3 AM.
  • !NAT Gateway egress is a sneaky operational drag. Add VPC endpoints for S3, ECR and Secrets Manager so container pulls and secret fetches never leave the VPC.
  • !Aurora minor version auto-upgrades are Sunday mornings by default. Set the maintenance window somewhere sane.

Related guides

Ready?
Full AWS + Rails stack in Terraform

Grab the reference Terraform, adjust three values, `terraform apply`. Production-grade in under an hour.