Back to Insights
Blog

Hosting Private Angular Applications on AWS with S3 and Internal ALB

This guide shows how to host an Angular application privately on AWS using S3 and an Internal Application Load Balancer. The application is only accessible from within your VPC—there are no public endpoints.

Overview

This architecture serves Angular applications from S3 through an Internal ALB, using a VPC Endpoint to keep all traffic private.

What you get:

  • Application accessible only from your VPC (via VPN or Direct Connect)
  • No EC2 instances to manage
  • S3 handles storage and scaling
  • Full support for Angular's client-side routing

How it works:

  1. Users connect to your VPC through VPN or Direct Connect
  2. Requests go to an Internal ALB (no public IP)
  3. ALB forwards requests to S3 through a VPC Endpoint
  4. S3 serves your Angular application files

Components

  • Internal ALB — Receives HTTPS requests, only accessible within VPC
  • Target Group — Routes traffic to VPC Endpoint IPs
  • VPC Endpoint — Connects to S3 without internet access
  • S3 Bucket — Stores Angular application files
  • ACM Certificate — Provides HTTPS encryption

How Angular Routing Works

Angular uses client-side routing. When a user navigates to /dashboard, the browser requests that path from the server. But /dashboard doesn't exist as a file in S3—only index.html and the JavaScript bundles exist.

The ALB solves this with listener rules:

  • Priority 10-13: Patterns like *.js, *.css, *.png → Forward to S3
  • Priority 50: Root path / → Redirect to /index.html
  • Priority 100: Catch-all /* → Redirect to /index.html

Static files go directly to S3. All other requests redirect to index.html, which loads Angular, and Angular handles the route.

Get the code: github.com/CC-Tech-Digital/private-angular-app

Prerequisites

Your network team needs to create these resources first:

  • VPC — At least 2 private subnets in different Availability Zones
  • VPC Endpoint — Interface type for S3, Private DNS must be disabled
  • ALB Security Group — Allow HTTPS (443) inbound from your user network
  • VPC Endpoint Security Group — Allow HTTPS (443) from ALB security group
  • ACM Certificate — Valid for your application domain

Get VPC Endpoint IPs

After creating the VPC Endpoint, get the private IPs:

aws ec2 describe-network-interfaces \
 --filters "Name=vpc-endpoint-id,Values=vpce-xxxxx" \
 --query 'NetworkInterfaces[*].PrivateIpAddress' \
 --output text

You need these IPs for the Target Group configuration.

Deployment

Step 1: Create Parameters File

Copy parameters/template.json and fill in your values:

[
 {"ParameterKey": "ProjectName", "ParameterValue": "my-app"},
 {"ParameterKey": "Environment", "ParameterValue": "prod"},
 {"ParameterKey": "VPCId", "ParameterValue": "vpc-xxxxx"},
 {"ParameterKey": "PrivateSubnetIds", "ParameterValue": "subnet-aaa,subnet-bbb"},
 {"ParameterKey": "VPCEndpointPrivateIPs", "ParameterValue": "10.0.1.50,10.0.2.50"},
 {"ParameterKey": "VPCEndpointId", "ParameterValue": "vpce-xxxxx"},
 {"ParameterKey": "ALBSecurityGroupId", "ParameterValue": "sg-xxxxx"},
 {"ParameterKey": "DomainName", "ParameterValue": "app.example.internal"},
 {"ParameterKey": "CertificateArn", "ParameterValue": "arn:aws:acm:..."},
 {"ParameterKey": "EnableAccessLogs", "ParameterValue": "false"}
]

Step 2: Deploy the Stack

aws cloudformation create-stack \
 --stack-name my-app-prod \
 --template-body file://infrastructure-stack.yaml \
 --parameters file://parameters/prod.json \
 --capabilities CAPABILITY_AUTO_EXPAND \
 --region us-east-1

aws cloudformation wait stack-create-complete \
 --stack-name my-app-prod \
 --region us-east-1

Step 3: Get the S3 Bucket Name

aws cloudformation describe-stacks \
 --stack-name my-app-prod \
 --query 'Stacks[0].Outputs[?OutputKey==`S3BucketName`].OutputValue' \
 --output text

Step 4: Deploy Your Angular Application

npm run build

aws s3 sync dist/your-app/browser/ s3://BUCKET_NAME/ --delete

Step 5: Configure DNS

Create a DNS record pointing your domain to the ALB. For Route53 private hosted zones, use an alias record.

Get the ALB DNS name:

aws cloudformation describe-stacks \
 --stack-name my-app-prod \
 --query 'Stacks[0].Outputs[?OutputKey==`ALBDNSName`].OutputValue' \
 --output text

Step 6: Verify

Check that the ALB targets are healthy:

TG_ARN=$(aws cloudformation describe-stacks \
 --stack-name my-app-prod \
 --query 'Stacks[0].Outputs[?OutputKey==`TargetGroupArn`].OutputValue' \
 --output text)

aws elbv2 describe-target-health \
 --target-group-arn $TG_ARN \
 --output table

Both targets should show healthy.

Updating the Application

To deploy a new version:

npm run build
aws s3 sync dist/your-app/browser/ s3://BUCKET_NAME/ --delete

Changes are live immediately. No infrastructure changes needed.

Troubleshooting

Targets Show Unhealthy
  1. Verify the VPC Endpoint IPs in your parameters match the actual ENI IPs
  2. Check that the VPC Endpoint security group allows HTTPS from the ALB security group
403 Forbidden

The bucket policy may have the wrong VPC Endpoint ID. Check it:

aws s3api get-bucket-policy --bucket BUCKET_NAME

The aws:SourceVpce condition must match your VPC Endpoint ID.

Deep Links Return 404

Verify the listener rules exist and have the correct priorities. Static asset rules should be 10-13, root path should be 50, and catch-all should be 100.

Cleanup

aws s3 rm s3://BUCKET_NAME --recursive

aws cloudformation delete-stack \
 --stack-name my-app-prod \
 --region us-east-1

Note: The S3 bucket has a retain policy. If stack deletion fails, delete the bucket manually first.

Repository

The CloudFormation template and full documentation are available on GitHub:

https://github.com/CC-Tech-Digital/private-angular-app

Summary

This architecture hosts Angular applications privately using:

  • Internal ALB for HTTPS termination and routing
  • VPC Endpoint for private S3 access
  • S3 for storage and serving files
  • ALB listener rules for SPA routing support

All traffic stays within AWS. There are no public endpoints.

Back to Insights

Ready to elevate your strategy?

Schedule a call with our experts today and unlock your business's potential.

Generative AI

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse varius enim in eros elementum tristique. Duis cursus, mi quis viverra ornare, eros dolor interdum nulla, ut commodo diam libero vitae erat.