AWS RDS PostgreSQL
Managed PostgreSQL database with full AWS integration
Cost: RDS db.t3.micro is Free Tier eligible for 12 months (750 hours/month). After free tier, db.t3.small costs ~$25/month. Storage costs ~$0.115/GB/month. Multi-AZ doubles the instance price. Delete RDS instances via Console or CLI when not needed. See our Costs & Cleanup Guide.
What is Amazon RDS?
Amazon Relational Database Service (RDS) is a managed database service. AWS handles backups, patching, scaling, and replication. You get a PostgreSQL (or MySQL, MariaDB, etc.) database without managing servers.
RDS vs Self-Managed
Why Use RDS with Fargate?
- VPC Integration: Database stays private, not exposed to internet
- Automatic Backups: Point-in-time recovery up to 35 days
- Multi-AZ: Automatic failover for high availability
- Read Replicas: Scale read traffic horizontally
- Encryption: At-rest and in-transit encryption
- IAM Auth: Use IAM roles instead of passwords
Setup Guide
Plan VPC Configuration
RDS must be in the same VPC as your ECS tasks. Create private subnets for the database.
Create DB Subnet Group
A subnet group tells RDS which subnets can host your database instances.
Configure Security Group
Allow PostgreSQL traffic (port 5432) only from your ECS tasks security group.
Launch RDS Instance
Create the PostgreSQL instance with appropriate size and storage.
Store Credentials in Secrets Manager
Never hardcode database passwords. Use Secrets Manager for secure storage.
DB Subnet Group
resource "aws_db_subnet_group" "main" {
name = "my-app-db-subnet-group"
subnet_ids = [
aws_subnet.private_a.id,
aws_subnet.private_b.id
]
tags = {
Name = "My App DB Subnet Group"
}
}Security Group
resource "aws_security_group" "rds" {
name = "my-app-rds-sg"
description = "Security group for RDS PostgreSQL"
vpc_id = aws_vpc.main.id
ingress {
description = "PostgreSQL from ECS tasks"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.ecs_tasks.id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}RDS Instance
resource "aws_db_instance" "main" {
identifier = "my-app-postgres"
engine = "postgres"
engine_version = "15.4"
instance_class = "db.t3.micro" # Free tier eligible
allocated_storage = 20
max_allocated_storage = 100 # Auto-scaling
storage_type = "gp3"
storage_encrypted = true
db_name = "myapp"
username = "postgres"
password = random_password.db.result
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.rds.id]
publicly_accessible = false
skip_final_snapshot = true # Set to false for production
backup_retention_period = 7
backup_window = "03:00-04:00"
maintenance_window = "Mon:04:00-Mon:05:00"
# Enable Multi-AZ for production
multi_az = false
tags = {
Name = "My App PostgreSQL"
}
}
# Generate secure password
resource "random_password" "db" {
length = 32
special = false
}Store Credentials in Secrets Manager
resource "aws_secretsmanager_secret" "db_credentials" {
name = "my-app/production/database"
}
resource "aws_secretsmanager_secret_version" "db_credentials" {
secret_id = aws_secretsmanager_secret.db_credentials.id
secret_string = jsonencode({
username = aws_db_instance.main.username
password = random_password.db.result
host = aws_db_instance.main.endpoint
port = aws_db_instance.main.port
dbname = aws_db_instance.main.db_name
})
}RDS Instance Sizes
| Instance Class | vCPU | Memory | Use Case |
|---|---|---|---|
db.t3.micro | 2 | 1 GB | Development, free tier |
db.t3.small | 2 | 2 GB | Small production |
db.t3.medium | 2 | 4 GB | Medium workloads |
db.r6g.large | 2 | 16 GB | Memory-intensive |
RDS Pricing
| Component | Cost (ap-southeast-1) |
|---|---|
| db.t3.micro (Free Tier) | 750 hrs/month free for 12 months |
| db.t3.small | ~$0.034/hour (~$25/month) |
| Storage (gp3) | ~$0.115/GB/month |
| Multi-AZ | 2x instance price |