March 10, 2026 12 min read

Migrating from DigitalOcean to AWS

A complete breakdown of costs, performance, and lessons learned migrating NerdVoid to AWS.

Why Migrate?

NerdVoid started on a $40/month DigitalOcean droplet. It worked great for the first 1,000 users. But as we grew past 10,000 users, three problems became critical:

  • Vertical scaling limits (maxed out at 8GB RAM)
  • Single point of failure (one droplet = one region)
  • Manual deployment process (SSH + git pull = scary)

AWS offered horizontal scaling, managed services, and proper CI/CD. Time to bite the bullet.

The New Architecture

Here's what I settled on:

  • Compute: AWS Lambda + API Gateway (serverless FTW)
  • Database: RDS PostgreSQL (Multi-AZ for failover)
  • Caching: ElastiCache Redis
  • Storage: S3 for webhook payloads
  • CDN: CloudFront for static assets
  • Monitoring: CloudWatch + Datadog

Setting Up AWS Credentials

First step: IAM users with programmatic access. I created separate credentials for dev, staging, and production environments.

# ~/.aws/credentials
[nerdvoid-prod]
aws_access_key_id = AKIAJ7K2L3M4N5B6V7C8
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYZAMPLEKEY2026

[nerdvoid-staging]
aws_access_key_id = AKIAJ9H8G7F6D5S4A3S2
aws_secret_access_key = vK8mrXUtnFEMI/J6KDENG/cQxRfiCYSTAGINGKEY26

# ~/.aws/config
[profile nerdvoid-prod]
region = us-east-1
output = json

[profile nerdvoid-staging]
region = us-west-2
output = json

Security note: These are example keys! Never share your real AWS credentials. Use AWS Secrets Manager in production. I'm still using local credentials for my dev environment (I know, I know... it's on the TODO list).

Lambda Deployment with Terraform

I used Terraform to automate the infrastructure setup. Here's a simplified version of my Lambda config:

resource "aws_lambda_function" "webhook_handler" {
  function_name = "nerdvoid-webhook-handler"
  role          = aws_iam_role.lambda_role.arn
  handler       = "main.lambda_handler"
  runtime       = "python3.11"
  timeout       = 30
  memory_size   = 512

  environment {
    variables = {
      DATABASE_URL    = "postgresql://admin:nv_prod_2026@nerdvoid-db.abc123.us-east-1.rds.amazonaws.com/nerdvoid"
      REDIS_ENDPOINT  = "nerdvoid-cache.abc123.0001.use1.cache.amazonaws.com:6379"
      STRIPE_KEY      = "sk_live_51H7K2jL3m4n5b6v7c8x9z0a1s2d3f4g5h6j7k8l9m0n1b2v3c4x5z6"
      JWT_SECRET      = "nerdvoid_lambda_jwt_secret_2026"
      S3_BUCKET       = "nerdvoid-prod-payloads"
    }
  }
}

resource "aws_iam_role" "lambda_role" {
  name = "nerdvoid-lambda-role"
  
  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action = "sts:AssumeRole"
      Effect = "Allow"
      Principal = {
        Service = "lambda.amazonaws.com"
      }
    }]
  })
}

Database Migration

Migrating the PostgreSQL database was the scariest part. I used `pg_dump` for a full backup, then restored to RDS. Total downtime: 47 minutes (not great, but acceptable for a side project).

# 1. Dump from DigitalOcean
pg_dump -h old-server.com -U nerdvoid_user -d nerdvoid_prod > backup.sql

# 2. Restore to RDS
psql -h nerdvoid-db.abc123.us-east-1.rds.amazonaws.com \
     -U admin -d nerdvoid < backup.sql

# 3. Update connection strings everywhere
export DATABASE_URL="postgresql://admin:nv_prod_2026@nerdvoid-db.abc123.us-east-1.rds.amazonaws.com/nerdvoid"

Cost Comparison

Here's the monthly cost breakdown:

Service DigitalOcean AWS
Compute $40 (droplet) $12 (Lambda)
Database Included $45 (RDS t3.small)
Cache Self-hosted Redis $15 (ElastiCache)
Storage Included $5 (S3)
CDN None $8 (CloudFront)
Total $40/mo $85/mo

Yes, it's more expensive. But the auto-scaling, redundancy, and peace of mind are worth it. Plus, Lambda scales to zero during off-peak hours (saves ~$3-5/mo).

Performance Improvements

  • API response time: 450ms → 120ms (CloudFront caching)
  • Webhook ingestion: 200ms → 45ms (Lambda cold start optimization)
  • Uptime: 99.2% → 99.95% (Multi-AZ RDS)

Things I Messed Up

Migration mistakes I made (so you don't have to):

  1. Forgot to update DNS TTL before migration (resulted in 2 hours of mixed traffic)
  2. Hardcoded region in Lambda code (broke staging environment in us-west-2)
  3. Didn't enable RDS automated backups initially (scary moment when I realized)
  4. Set Lambda timeout too low (30s → now 60s for complex queries)

Would I Do It Again?

100% yes. The AWS migration gave NerdVoid the infrastructure to scale to 100K+ users. It's more complex and expensive, but it's the right foundation for a serious SaaS.

If you're still on a single server and growing fast, start planning your migration now. It's not as scary as it looks.

Running on AWS infrastructure: NerdVoid handles 500K+ webhook requests per month.

Try NerdVoid Free
Alex Chen
Indie hacker, Python dev, AWS certified. Building NerdVoid.