Skip to content

Latest commit

 

History

History
507 lines (344 loc) · 14.3 KB

File metadata and controls

507 lines (344 loc) · 14.3 KB

Deployment Guide

This guide gives the current production-style deployment path for this repository:

  • Deploy the API as a container on Amazon ECS with AWS Fargate.
  • Use Neon PostgreSQL for the database.
  • Store sensitive runtime values in AWS Secrets Manager.
  • Route traffic through an Application Load Balancer.

This repository is the PostgreSQL track of the Users & Posts API. If you continue running the MongoDB version separately, keep SQL-specific runtime resource names distinct with a suffix such as -sql.

Recommended Architecture

Use this architecture for the current project:

  • Neon PostgreSQL 18 for the database
  • Amazon ECR for the container image
  • Amazon ECS with AWS Fargate for compute
  • Application Load Balancer for inbound traffic
  • AWS Secrets Manager for DATABASE_URL and JWT_SECRET
  • CloudWatch Logs for container logs

Application traffic flow:

  1. A client calls the load balancer DNS name.
  2. The load balancer forwards traffic to the ECS target group.
  3. A Fargate task runs the API container on port 3111.
  4. The API connects to Neon PostgreSQL over TLS using DATABASE_URL.
  5. Neon stores the application data in PostgreSQL.

PostgreSQL 18 Requirement

This project requires PostgreSQL 18 because the schema uses native uuidv7() defaults.

Important notes:

  • Create the Neon project on PostgreSQL 18.
  • If the database is created on PostgreSQL 17 or lower, schema initialization fails.
  • Neon supports PostgreSQL 18 as of March 2026, but it is currently preview.

What Can Stay Shared With The MongoDB Deployment

If you still maintain the MongoDB version in AWS, these parts can remain shared if that already matches your setup:

  • VPC
  • Internet Gateway
  • Public subnets for the load balancer
  • Private subnets for ECS tasks
  • NAT gateway and route tables
  • ECS cluster
  • Task execution IAM role, if it already has the permissions you need
  • Application Load Balancer, if you use separate target groups and listener rules
  • General Secrets Manager structure

These items should be separate for the SQL deployment and should use a distinct -sql name:

  • Neon project and database credentials
  • ECR repository
  • ECS task definition family
  • ECS service
  • Container name
  • Target group
  • CloudWatch log group

Recommended SQL resource names:

  • ECR repository: users-posts-api-sql
  • ECS task definition family: users-posts-api-sql
  • ECS service: users-posts-api-sql
  • ECS container: users-posts-api-sql
  • Target group: users-posts-api-sql-tg
  • CloudWatch log group: /ecs/users-posts-api-sql
  • Neon project: users-posts-sql
  • Secret for database URL: users-posts/sql/prod/database-url

Quick Deployment Checklist

Prepare these values before you start:

AWS_REGION=<your-region>
AWS_ACCOUNT_ID=<your-account-id>
ECR_REPOSITORY_NAME=users-posts-api-sql
ECS_CLUSTER_NAME=<existing-or-new-ecs-cluster>
ECS_SERVICE_NAME=users-posts-api-sql
ECS_TASK_FAMILY=users-posts-api-sql
ECS_CONTAINER_NAME=users-posts-api-sql
TARGET_GROUP_NAME=users-posts-api-sql-tg
APP_PORT=3111
ALLOWED_ORIGINS=<comma-separated-frontend-origins>
JWT_SECRET=<long-random-secret>
NEON_PROJECT_NAME=users-posts-sql
NEON_POSTGRES_VERSION=18
NEON_DATABASE_NAME=users
NEON_DATABASE_ROLE=app_user
NEON_DATABASE_URL=<your-neon-connection-string>

High-level flow:

  1. Create the Neon PostgreSQL 18 project.
  2. Create the AWS secrets.
  3. Build and push the container image to ECR.
  4. Prepare the ECS networking and security groups.
  5. Create the task definition and ECS service.
  6. Run the database migrations as a one-off ECS task.
  7. Validate /health and /api-docs.

1. Application Runtime Requirements

This application expects these environment variables:

  • DATABASE_URL is required.
  • JWT_SECRET is required.
  • ALLOWED_ORIGINS is required.
  • PORT is optional and defaults to 3111.
  • DATABASE_SSL is optional and should be true for Neon.
  • DATABASE_SSL_REJECT_UNAUTHORIZED is optional and should usually stay true.

Useful endpoints after deployment:

  • GET /health
  • GET /api-docs
  • GET /users
  • GET /posts

2. Prerequisites

Before you start, make sure you have:

  • An AWS account
  • A Neon account
  • Docker installed on your local machine
  • Access to the AWS console
  • AWS CLI installed locally if you want to use CLI examples

Optional but helpful:

  • A GitHub account or another Git remote for the source
  • Existing shared AWS networking if you already run the MongoDB version

3. Create The Neon PostgreSQL Resources

Use Neon first because the app cannot boot without a valid PostgreSQL connection string.

Neon steps

  1. Create or open your Neon account.
  2. Create a new Neon project.
  3. Choose PostgreSQL version 18.
  4. Choose an AWS region close to your ECS deployment.
  5. Set the project name to something distinct such as users-posts-sql.
  6. Create or confirm the database name is users.
  7. Create a dedicated application role such as app_user.
  8. Copy the server-side connection string.

Example format:

postgresql://app_user:<password>@ep-example-123456.us-east-2.aws.neon.tech/users?sslmode=require

Use the application database name users unless you intentionally want a different database.

Neon network access

If you want IP restriction in Neon:

  1. Decide how ECS tasks will reach the internet.
  2. If using private ECS subnets, send outbound traffic through a NAT gateway with an Elastic IP.
  3. Add that Elastic IP to the Neon IP allow rules.

If you do not want to manage IP restrictions immediately, you can start without an allowlist and tighten it later when your network path is stable.

4. Create The AWS Secrets

Store runtime secrets before creating the ECS task definition.

Recommended secrets:

  • One secret for DATABASE_URL
  • One secret for JWT_SECRET

Recommended names:

  • users-posts/sql/prod/database-url
  • users-posts/shared/prod/jwt-secret or a SQL-specific JWT secret if you prefer

Example AWS CLI commands:

aws secretsmanager create-secret \
    --name users-posts/sql/prod/database-url \
    --secret-string 'postgresql://app_user:<password>@ep-example-123456.us-east-2.aws.neon.tech/users?sslmode=require' \
    --region <your-region>

aws secretsmanager create-secret \
    --name users-posts/shared/prod/jwt-secret \
    --secret-string '<long-random-secret>' \
    --region <your-region>

Keep these non-secret values ready for the task definition:

  • PORT=3111
  • DATABASE_SSL=true
  • DATABASE_SSL_REJECT_UNAUTHORIZED=true
  • ALLOWED_ORIGINS=<comma-separated-origins>

5. Create The Amazon ECR Repository

Create the image repository for the SQL deployment.

Example repository name:

  • users-posts-api-sql

Create it:

aws ecr create-repository --repository-name users-posts-api-sql --region <your-region>

6. Build And Push The Container Image

From the repository root:

docker build -t users-posts-api-sql:latest .
aws ecr get-login-password --region <your-region> | docker login --username AWS --password-stdin <aws-account-id>.dkr.ecr.<your-region>.amazonaws.com
docker tag users-posts-api-sql:latest <aws-account-id>.dkr.ecr.<your-region>.amazonaws.com/users-posts-api-sql:latest
docker push <aws-account-id>.dkr.ecr.<your-region>.amazonaws.com/users-posts-api-sql:latest

This repository's container listens on port 3111 and exposes /health for health checks.

7. Prepare The AWS Networking

Use the normal ECS with ALB layout:

  • Two public subnets for the Application Load Balancer
  • Two private subnets for the ECS tasks
  • NAT gateway for outbound internet access from the private subnets

Recommended security groups:

Load balancer security group

Inbound:

  • 80 from the internet
  • 443 from the internet if you add TLS

Outbound:

  • Allow traffic to the ECS task security group on port 3111

ECS task security group

Inbound:

  • 3111 from the load balancer security group only

Outbound:

  • Allow outbound internet access so the tasks can reach Neon and other required endpoints

If you already have a shared VPC and ALB for the MongoDB deployment, you can reuse them and add a new SQL target group plus a new listener rule.

8. Create The IAM Roles

You need a task execution role at minimum.

Recommended permissions for the task execution role:

  • Pull images from Amazon ECR
  • Write logs to CloudWatch Logs
  • Read the referenced secrets from Secrets Manager

If you already use a shared execution role for the MongoDB deployment, confirm that it allows access to:

  • the users-posts-api-sql ECR repository
  • the SQL CloudWatch log group
  • the SQL DATABASE_URL secret

9. Create The ECS Cluster

You can either:

  • Reuse an existing ECS cluster
  • Create a new one for the SQL deployment

Example CLI:

aws ecs create-cluster --cluster-name <your-cluster-name> --region <your-region>

If you already use a shared cluster with the MongoDB deployment, keep the SQL service name distinct.

10. Create The CloudWatch Log Group

Create the log group before you register the task definition.

Example:

aws logs create-log-group --log-group-name /ecs/users-posts-api-sql --region <your-region>

11. Create The Target Group

Create a target group for the SQL API service.

Recommended settings:

  • Target type: ip
  • Protocol: HTTP
  • Port: 3111
  • Health check path: /health

Recommended name:

  • users-posts-api-sql-tg

12. Create The Load Balancer Listener Rule

If you already have an ALB, add a SQL-specific rule.

Examples:

  • Route a dedicated hostname such as sql-api.example.com
  • Route a dedicated path prefix such as /sql/*

If this is your first deployment on the ALB, you can forward the default listener rule to the SQL target group for now.

13. Register The ECS Task Definition

Create a Fargate task definition with these baseline settings:

  • Family: users-posts-api-sql
  • Container name: users-posts-api-sql
  • Image: <aws-account-id>.dkr.ecr.<your-region>.amazonaws.com/users-posts-api-sql:latest
  • Port mapping: 3111
  • Launch type compatibility: FARGATE
  • Network mode: awsvpc
  • Log driver: awslogs
  • Log group: /ecs/users-posts-api-sql

Environment values:

  • PORT=3111
  • DATABASE_SSL=true
  • DATABASE_SSL_REJECT_UNAUTHORIZED=true
  • ALLOWED_ORIGINS=<comma-separated-origins>

Secrets:

  • DATABASE_URL from Secrets Manager
  • JWT_SECRET from Secrets Manager

Health check:

  • Container health check should hit http://127.0.0.1:3111/health

14. Create The ECS Service

Create the ECS service using the SQL task definition.

Recommended settings:

  • Service name: users-posts-api-sql
  • Launch type: FARGATE
  • Desired count: 1 to start
  • Deployment controller: ECS rolling update
  • Attach the target group users-posts-api-sql-tg
  • Place tasks in the private subnets
  • Assign the task security group created earlier
  • Do not assign a public IP if the tasks already have NAT egress

15. Run The Database Migrations

This project expects the PostgreSQL schema to exist before normal traffic starts.

For AWS, use a one-off ECS task that runs the compiled migration entrypoint against the Neon database.

Migration command:

node dist/db/init.js

Recommended flow:

  1. Build and push the application image.
  2. Register the task definition.
  3. Run a one-off task using the same image, same secrets, and same network settings.
  4. Override the container command so it runs node dist/db/init.js.
  5. Wait for the task to finish successfully.
  6. Only then create or scale the long-running service.

The migrations create these tables:

  • users
  • posts
  • user_favorite_foods
  • user_hobbies

16. Validate The Deployment

Use the load balancer DNS name or your own hostname.

Test these URLs:

  • http://<alb-dns>/health
  • http://<alb-dns>/api-docs
  • http://<alb-dns>/users
  • http://<alb-dns>/posts

If /health fails:

  • Check the ECS service events.
  • Check the CloudWatch log group /ecs/users-posts-api-sql.
  • Confirm the ECS task can reach the Neon endpoint.
  • Confirm DATABASE_URL points to the Neon PostgreSQL 18 project.
  • Confirm the migrations completed successfully.
  • Confirm the target group health check uses /health.

17. Updating The App Later

For each new release:

docker build -t users-posts-api-sql:latest .
aws ecr get-login-password --region <your-region> | docker login --username AWS --password-stdin <aws-account-id>.dkr.ecr.<your-region>.amazonaws.com
docker tag users-posts-api-sql:latest <aws-account-id>.dkr.ecr.<your-region>.amazonaws.com/users-posts-api-sql:latest
docker push <aws-account-id>.dkr.ecr.<your-region>.amazonaws.com/users-posts-api-sql:latest

Then:

  1. Register a new task definition revision.
  2. Update the ECS service to the new revision.
  3. Wait for the rolling deployment to complete.
  4. Re-test /health and /api-docs.

18. Optional AWS Services To Add Later

Add these only if you need them.

Route 53 And TLS

Useful if you want a custom domain and HTTPS.

Recommended additions:

  • Route 53 hosted zone
  • ACM certificate
  • HTTPS listener on the ALB

Systems Manager

Useful if you want operational access and AWS-native troubleshooting workflows.

CloudWatch Alarms

Useful if you want alerts for:

  • unhealthy target count
  • high response latency
  • task restarts

WAF

Useful if you want basic public-edge protection in front of the ALB.

19. Security Recommendations

Keep these controls in place:

  • Use a long random JWT_SECRET
  • Use a dedicated Neon database role for this app
  • Keep DATABASE_SSL=true
  • Restrict ECS task inbound traffic to the load balancer security group only
  • Keep Secrets Manager values out of the repository
  • If you use Neon IP allow rules, only allow the stable NAT egress IP

20. Cleanup

When you no longer need the deployment:

  1. Scale down or delete the ECS service.
  2. Deregister old task definition revisions if you want to tidy up.
  3. Delete the target group and listener rule if they are dedicated to the SQL service.
  4. Delete the SQL ECR repository if you no longer need the image.
  5. Delete the SQL secrets from Secrets Manager if they are dedicated to this deployment.
  6. Delete the Neon project or database role if you no longer need it.

21. Suggested Upgrade Path Later

When this deployment is no longer enough, upgrade in this order:

  1. Add HTTPS with ACM and Route 53.
  2. Add alarms and dashboards.
  3. Increase ECS desired count above 1.
  4. Add stricter Neon network controls when your outbound IP path is stable.
  5. Split shared AWS resources from the MongoDB deployment if you want full isolation.