Skip to content

Recommended AWS Deployment Architecture

Decision summary

Anuva should keep the existing Cloudflare Tunnel workflow for local Development and use AWS only for the three hosted environment profiles:

  1. Pilot/Preview for demos, validation, and invited preview users.
  2. Early Users for the first persistent customer-facing environment.
  3. Production for a resilient service with render capacity in the United States and India.

The recommended AWS foundation is:

  • Amazon ECS on Fargate for the Web application and non-GPU background workers;
  • Amazon RDS for PostgreSQL, not Aurora;
  • Amazon SQS for render-job coordination, with S3 object references in messages;
  • EC2 Auto Scaling groups of g6f.large or g6f.2xlarge GPU workers running the Python server and Unity executable;
  • Amazon S3 for assets and rendered media, delivered through CloudFront;
  • public subnets with an internet gateway and tightly scoped security groups;
  • no NAT Gateway and no private-subnet tier in the initial architecture; and
  • infrastructure as code behind narrow, allowlisted Anuva CLI operations.

us-east-1 is the primary Region. Production adds ap-south-1 for regional GPU render capacity. These are two AWS Regions, not two Availability Zones.

Architecture

flowchart LR
    User["Browser or client"]
    DNS["Route 53"]
    CDN["CloudFront"]
    Media["S3 media bucket\nprivate origin"]

    subgraph USE1["us-east-1 - primary control plane"]
        ALB["Application Load Balancer"]
        ECS["ECS Fargate\nWeb + background workers"]
        DB["RDS PostgreSQL"]
        QueueUS["SQS render queue + DLQ"]
        GPUUS["EC2 Auto Scaling group\ng6f GPU workers"]
    end

    subgraph APS1["ap-south-1 - Production render plane"]
        QueueIN["SQS render queue + DLQ"]
        GPUIN["EC2 Auto Scaling group\ng6f GPU workers"]
        StageIN["Optional regional S3\nstaging bucket"]
    end

    User --> DNS --> ALB --> ECS
    User --> CDN --> Media
    ECS --> DB
    ECS --> Media
    ECS --> QueueUS --> GPUUS
    ECS -. "Production region routing" .-> QueueIN --> GPUIN
    GPUUS --> Media
    GPUIN --> Media
    GPUIN -. "add when transfer warrants it" .-> StageIN

The Web application remains the control plane. It creates render records in PostgreSQL, places small job envelopes on SQS, and exposes status to users. GPU workers claim jobs, download source assets from S3, run the Python and Unity render process, upload the MP4 to S3, and report the outcome through an idempotent API or status message.

For Production, keep the Web application and writable PostgreSQL database in us-east-1 initially. Add only the latency- and capacity-sensitive GPU render plane in Mumbai. A fully active-active Web and relational-database deployment would introduce cross-region consistency, failover, and operations work that is not justified for a bootstrapped solo developer.

Environment profiles

Concern Pilot/Preview Early Users Production
Purpose Demos and invited validation First persistent customer workload Resilient paid-user service
Regions us-east-1 us-east-1 Control plane in us-east-1; GPU render planes in us-east-1 and ap-south-1
Web One Fargate task while active; may scale to zero during shutdown One continuously running task; add a second if availability requires it At least two tasks spread across US East Availability Zones
Background workers One task per required worker type while active, or combine low-volume workers initially Separate independently scalable worker services Separate services with CPU/memory and queue-depth scaling
PostgreSQL Small Single-AZ RDS instance Single-AZ RDS with automated backups Multi-AZ RDS in us-east-1; no Aurora
GPU workers US East ASG, minimum/desired 0, maximum 1 One US East GPU worker while accepting jobs; maximum 1 initially Two workers in US East and two in Mumbai; spread each regional fleet across available AZs where G6f capacity permits
GPU purchase model Spot by default; manual On-Demand fallback Spot with automated or operator-controlled On-Demand fallback Mixed Instances policy, Capacity Rebalancing, and On-Demand fallback/base capacity if render SLA requires it
Media One private S3 bucket and CloudFront Same, with lifecycle rules Primary media bucket and CloudFront; add a Mumbai staging bucket only when measured transfer latency/cost warrants it
Availability target Recoverable, not highly available Modest availability with simple operations Multi-AZ control plane and two regional render fleets

Although Pilot/Preview and Early Users run their application workload in one primary Availability Zone, the VPC still needs public subnets in at least two Availability Zones. An Application Load Balancer requires two AZ subnets, and an RDS DB subnet group must also cover at least two AZs. This network layout does not require the ECS tasks, Single-AZ database, or early GPU fleet to run in both AZs.

Component recommendations

Web application and background workers

Build the Web application and its background workers as Docker images stored in Amazon ECR. Use one ECS task definition per independently deployable process and one ECS service per process that needs continuous execution.

The containers must be stateless:

  • store durable application state in PostgreSQL;
  • store input and output files in S3;
  • put only identifiers, S3 keys, versions, and retry metadata on queues;
  • write logs to stdout/stderr for CloudWatch Logs; and
  • support graceful shutdown and idempotent retries.

Only the public Web service is registered with the ALB. Queue consumers and other background workers do not need inbound listeners.

PostgreSQL

Use ordinary Amazon RDS for PostgreSQL. Aurora is intentionally excluded because its additional capabilities and operational choices do not justify its cost for the initial workload.

  • Pilot/Preview and Early Users use the smallest tested Single-AZ instance.
  • Production upgrades the same engine to Multi-AZ in us-east-1.
  • Set PubliclyAccessible=false even though the DB subnet group uses the shared public subnets. The database then has only private VPC reachability.
  • Allow TCP 5432 only from the ECS task security group. GPU workers should update state through an application API or result queue rather than connect directly to PostgreSQL.
  • Enable encryption, automated backups, deletion protection in Production, and tested snapshot restore procedures.

RDS is retained by default when an environment is shut down. Temporary RDS stop is not a permanent scale-to-zero mechanism: AWS automatically restarts a stopped instance after seven days, and storage and backup charges continue.

Render queue

Use an SQS Standard queue plus a dead-letter queue for each render Region. The approximately 20 MB of initial voice-over audio and assets must be uploaded to S3; the SQS message carries references because a native SQS message is limited to 1 MiB.

For the current approximately five-minute Unity render:

  • set the initial visibility timeout above the expected cold-start plus render and upload duration;
  • extend visibility with heartbeats while the job is making progress;
  • delete the message only after the MP4 and final status are durably recorded;
  • make job claims and completion idempotent; and
  • route repeatedly failing jobs to the DLQ with an alarm.

Keep one queue in US East until Production. Production can route jobs to a US or Mumbai queue based on user location, requested capacity, and queue depth.

GPU render workers

Use a launch template and one Auto Scaling group per Region. The image contains the tested NVIDIA driver, Python runtime, Unity executable, SSM agent, monitoring agent, and a small worker supervisor. Prefer a baked AMI so instance boot time is predictable.

Both g6f.large and g6f.2xlarge remain candidates. Benchmark the same project on each before choosing the default: g6f.large exposes 1/8 of a GPU with 3 GB GPU memory, while g6f.2xlarge exposes 1/4 of a GPU with 6 GB GPU memory. The larger instance is justified only if it materially reduces total job time, prevents Unity memory failures, or improves concurrent throughput enough to offset its higher hourly rate.

Use Spot capacity first, with these safeguards:

  • the price-capacity-optimized allocation strategy;
  • Capacity Rebalancing;
  • multiple allowed AZs where the chosen G6f size is available;
  • an interruption handler that stops claiming work and records the active job as retryable; and
  • an On-Demand override or mixed-capacity fallback when Spot is unavailable.

A five-minute render cannot rely on completing during the two-minute Spot interruption window. Correctness must come from idempotent retry, not graceful completion on the interrupted instance.

Media storage and delivery

Use private S3 buckets with blocked public access. CloudFront accesses the media origin through Origin Access Control. Deliver completed videos with signed URLs or signed cookies, depending on the application authorization model.

Store the source asset set, render manifest, output MP4, and useful diagnostic artifacts under a job-specific prefix. Apply lifecycle rules separately to temporary render inputs, diagnostics, and customer-owned final outputs. The approximately 100 MB output should be uploaded directly from the GPU worker to S3 rather than routed through the Web container.

Start with one primary bucket in US East. If Mumbai transfer measurements become material, add a short-lived regional staging bucket and controlled replication or copying instead of making the entire application multi-region.

Networking without NAT or private subnets

Create one VPC in each active Region with an internet gateway and at least two public subnets in different AZs. Do not create a NAT Gateway or a separate private-subnet tier initially.

Security group Inbound Outbound
ALB HTTPS 443 from the internet; optional HTTP 80 redirect Web ECS task security group on the application port
ECS tasks Application port only from the ALB security group; none for worker-only services HTTPS to AWS/public dependencies and PostgreSQL 5432 to the DB security group
GPU workers None HTTPS to SQS, S3, SSM, logs, and the application result endpoint
RDS PostgreSQL 5432 only from the ECS task security group Default database response traffic

Assign public IPs to Fargate task ENIs and GPU EC2 instances so they can reach ECR, SQS, S3, Secrets Manager, SSM, and external APIs through the internet gateway. A public IP does not require an inbound rule. Do not open SSH or RDP; use Systems Manager Session Manager for audited operator access without inbound ports.

This is a deliberate cost/complexity tradeoff. Revisit private subnets and VPC endpoints when compliance requirements, threat modelling, or sustained traffic justify the additional infrastructure. A free S3 gateway endpoint may be added without introducing NAT if measurement shows a useful benefit.

Scaling and automation

Provision the AWS resources from one infrastructure-as-code implementation, preferably AWS CDK with TypeScript to minimize the number of languages a solo developer must maintain. Because Product Main owns coordination and only the slim Anuva CLI as implementation code, place the CDK application in a dedicated infrastructure repository or approve a new repository ownership decision before implementation.

Expose only fixed, reviewed operations through the Anuva CLI. A proposed command surface is:

anuva aws plan --profile <pilot-preview|early-users|production>
anuva aws up --profile <pilot-preview|early-users|production>
anuva aws down --profile <pilot-preview|early-users> --retain-data
anuva aws status --profile <pilot-preview|early-users|production>

down --retain-data should be the safe default:

  • set ECS service desired counts to zero;
  • set GPU Auto Scaling group minimum and desired capacity to zero;
  • delete or disable the profile ALB when DNS downtime is acceptable;
  • retain RDS, S3, ECR, secrets, logs, DNS, and backups; and
  • report the resources that continue to incur cost.

Production shutdown should not be a routine command. Require a separate explicit confirmation boundary and never delete RDS or S3 as part of an ordinary shutdown.

Scale GPU capacity from queue depth and oldest-message age, with explicit maximums to cap spend. Early profiles should favor scale-to-zero and operator-visible limits. Production should favor a small warm capacity only when measured boot time or the product SLA requires it.

Operational baseline

Keep the first version deliberately small:

  • CloudWatch dashboards and alarms for ALB 5xx, ECS task restarts, RDS capacity, SQS age/depth, DLQ depth, failed renders, Spot interruptions, and S3 upload failures;
  • AWS Budgets alerts and mandatory tags for profile, repository, service, and owner;
  • Secrets Manager or encrypted Parameter Store values, never secrets in images or task definitions;
  • least-privilege IAM roles per ECS service and GPU worker; and
  • one tested runbook each for failed deployment, database restore, stuck queue, Spot interruption, and failed render retry.

Use one non-Production AWS account for Pilot/Preview and Early Users initially, with isolated stacks and resource names. Move Production into a separate AWS account before it contains paying-user data.

Application changes implied by this architecture

The deployment decision creates implementation work in all three product repositories:

  • anuvax-cms: production Docker image, stateless Web and worker entrypoints, RDS connection and migration handling, S3-backed asset records, SQS job publishing, regional routing, health checks, and graceful shutdown.
  • anuva-python-server: SQS worker loop, visibility heartbeat, idempotent job claim/completion, S3 download/upload, Spot interruption handling, Unity process supervision, and structured CloudWatch logging.
  • anuva-unity-video-creator: unattended Linux/Windows build validation for the chosen AMI, deterministic output paths, exit codes, GPU memory benchmarks, and reliable cleanup after success or failure.

Before implementation, convert these into repository-scoped Linear issues with dependencies, acceptance checks, verification, documentation updates, and a Product Main completion review.

Deferred decisions

Do not add these until measurements or requirements justify them:

  • Aurora PostgreSQL;
  • NAT Gateways and private-subnet tiers;
  • Kubernetes/EKS;
  • an active-active multi-region Web and database layer;
  • cross-region S3 replication for every object;
  • permanently warm Pilot GPU instances; or
  • elaborate workflow orchestration beyond SQS and idempotent workers.

AWS references