DEV Community

Cover image for AWS Terraform infrastructure for a FastAPI+PostgreSQL backend
Shoban Chiddarth
Shoban Chiddarth

Posted on

AWS Terraform infrastructure for a FastAPI+PostgreSQL backend

Introduction

This blog post showcases the AWS infrastructure written in Terraform for the backend of alumni-connect, a MVP of a college project written in FastAPI with a PostgreSQL database.

The terraform repo: https://github.com/ShobanChiddarth/alumni-connect-terraform
The backend repo: https://github.com/ShobanChiddarth/alumni-connect-backend

Architecture

architecture

VPC Design

Since this is an MVP, I went with the absolute minimal for everything. 1 VPC exists on ap-south-1. It has an internet gateway. Frontend is hosted in netlify, so API requests as well as management traffic (SSH) will enter through the internet gateway.

Subnet Design

There are 4 subnets in total.

  • A public subnet to handle management traffic (ap-south-1a)
  • 2 private subnets for backend and database EC2 instances (ap-south-1a)
  • Another public subnet to satisfy AWS's hard requirement of multi AZ for load balancers (ap-south-1b)

The management subnet:

  • Contains the bastion EC2
  • Contains a NAT gateway for EC2 instances in the private subnet to reach the internet

Load Balancer

The backend EC2 has no public IP and sits in a private subnet. Its security group only accepts port 8000 from the ALB security group - there is no direct path from the internet to the backend. The ALB is the only entry point.

  • listens on port 80 for HTTP traffic from the public internet
  • spans across ap-south-1a (management subnet) and ap-south-1b (empty subnet) - AWS requires an internet-facing ALB to span at least 2 AZs
  • forwards the traffic from the internet to port 8000 in the backend EC2

Security Groups Design

  • SSH traffic from the internet is allowed only to the bastion EC2
  • SSH traffic to the backend and database EC2s are allowed only from the bastion EC2
  • HTTP traffic from the internet is allowed only to the load balancer
  • HTTP traffic to the backend is allowed only from the load balancer
  • Database traffic (port 5432) to the database EC2 is allowed only from the backend EC2

SSH Keys

  • Bastion EC2's SSH private key stays on the local computer of the person deploying this
  • Other EC2s SSH private key stays in the bastion

EC2 instances

  • Backend EC2 is set to pull and run docker image shobanchiddarth/alumni-connect-backend:0.0.2
  • Database EC2 is set to pull and run docker image postgres:16

NAT Gateway Cost Problem

I wrote a LinkedIn post about this. Click here to view it.

If you are not able to see it, here are the contents of the post:

I recently faced a problem with making EC2 instances communicate with the internet while deploying a FastAPI+Postgres backend architecture on AWS using Terraform. NAT Gateways exist to solve this - a NAT gateway can be placed in a public subnet and traffic can be routed through it.

But NAT Gateways are costly. ~$0.045/hr just to exist, plus data transfer charges.

The solution I used: keep the NAT gateway in the Terraform code, but destroy it immediately after deployment. Private instances lose internet access after packages are updated, Docker images are pulled, and containers are running.

terraform destroy -target=aws_nat_gateway.alumni-nat-gw -target=aws_eip.nat-gateway-elastic-ip

I also tried a NAT instance - an EC2 that acts as a router - but ran into configuration issues getting it to actually forward traffic. Ended up not going down that path for this project.

This temporary NAT gateway approach is good enough for a college project MVP with almost no users that gets destroyed in a few hours anyway.

Has anyone dealt with this in production? Is there a cleaner pattern for private subnet internet access beyond NAT gateway or NAT instance?

#Terraform #AWS #VPC #CloudComputing #IaC #CloudCost
Enter fullscreen mode Exit fullscreen mode

Steps to Deploy

  1. Clone the repo

    git clone https://github.com/ShobanChiddarth/alumni-connect-terraform
    cd alumni-connect-terraform/infrastructure
    
  2. Set AWS credentials

    export AWS_ACCESS_KEY_ID="..."
    export AWS_SECRET_ACCESS_KEY="..."
    
  3. Set the database password

    export TF_VAR_db_password="..."
    
  4. Deploy

    terraform init
    terraform apply
    
  5. Destroy the NAT gateway after apply

    terraform destroy \
     -target=aws_nat_gateway.alumni-nat-gw \
     -target=aws_eip.nat-gateway-elastic-ip
    

To tear down everything:

terraform destroy
Enter fullscreen mode Exit fullscreen mode

Proof of Deployment

These are screenshots I took when it was live. I then destroyed the whole infrastructure.

working-001

working-002

working-003

working-004

I archived the API landing URL (first image) in Wayback Machine. Here is the link: https://web.archive.org/web/20260322130840/http://alumni-alb-backend-83642402.ap-south-1.elb.amazonaws.com/

Conclusion

This is the full Terraform infrastructure for the alumni-connect backend.

Top comments (0)