Open the AWS Console search bar, type acm, and select Certificate Manager.

In ACM, click Request certificate.

Select Request a public certificate, then click Next.

Enter fully qualified domain name as <your-domain> (example: auth.example.com).
Keep export option as Disable export.
Select validation method DNS validation.
Keep key algorithm RSA 2048.

Scroll down and click Request.

Open the created certificate and check domain validation details.
If Route 53 hosts your domain, click Create records in Route 53.
If not, manually create the shown CNAME name and CNAME value in your DNS provider.
Initial status is typically Pending validation.

Wait until certificate status becomes Issued.
Copy and keep the certificate ARN for CloudFront in later steps.

Open S3 Console - Buckets - Create bucket.

Set Bucket type to General purpose.
Enter Bucket name as <your-frontend-bucket-name>.
Keep Object Ownership as ACLs disabled (Bucket owner enforced).
Keep Block all public access enabled.

Keep Bucket Versioning enabled.
Keep Default encryption as SSE-S3.
Keep Object Lock disabled.
Click Create bucket.

Open the created bucket - Permissions tab.
Verify Block public access remains enabled.
Click Edit in Bucket policy.

Add a CloudFront read policy for this bucket.
Set AWS:SourceArn to your CloudFront distribution ARN pattern:
arn:aws:cloudfront::<account-id>:distribution/<your-distribution-id>
Save changes.
Use the following bucket policy JSON:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <YOUR_CLOUDFRONT_OAI_ID>"
},
"Action": [
"s3:GetBucket*",
"s3:GetObject*",
"s3:List*"
],
"Resource": [
"arn:aws:s3:::<your-s3-bucket-name>",
"arn:aws:s3:::<your-s3-bucket-name>/*"
]
},
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <YOUR_CLOUDFRONT_OAI_ID>"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<your-s3-bucket-name>/*"
},
{
"Sid": "AllowCloudFrontServicePrincipal",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::<your-s3-bucket-name>/*",
"Condition": {
"ArnLike": {
"AWS:SourceArn": "arn:aws:cloudfront::YOUR_ACCOUNT_ID:distribution/<your-cloudfront-name>"
}
}
}
]
}

Objects tab and upload your frontend build output.index.html and assets are present.

Open CloudFront Console - Distributions - Create distribution.

Select plan: Free.

Enter Distribution name as <your-distribution-name>.
Select Distribution type: Single website or app.

Select Origin type: Amazon S3.
Select your frontend S3 bucket as origin.

Keep security protections enabled.
Click Create distribution.

Wait for status to become Deployed.
Copy CloudFront domain name as <your-cloudfront-domain>.
Open your distribution - General tab - click Add domain.

Enter Domains to serve as <your-domain>.
Click Next.

Select the ACM certificate from section 1.
Click Next.

Review domain and TLS certificate values.
Click Add domains.

Open distribution settings and click Edit.

Enter Default root object as index.html.
Save changes.

Open Origins tab.
Click Create origin.

Enter Origin domain as <your-alb-dns-name>.
Select Protocol: HTTP only.
Enter Name as <your-backend-origin-name>.
Click Create origin.

Open Behaviors tab.
Click Create behavior.

Enter Path pattern: /api/*.
Select Origin: <your-backend-origin>.
Select Compress objects automatically: Yes.
Select Viewer protocol policy: Redirect HTTP to HTTPS.
Select Allowed HTTP methods: GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE.

Select Cache policy: Managed-CachingDisabled.
Select Origin request policy: Managed-AllViewer.
Save behavior.

Repeat the same behavior configuration for /auth/*, /user/*, and /test/*.
Verify all API behaviors point to backend origin and default (*) points to S3 origin.

Deployed.Issued.index.html.HTTP only./api/*, /auth/*, /user/*, /test/* use Managed-CachingDisabled and Managed-AllViewer.web on port 8080.CORS_ALLOWED_ORIGINS includes https://<your-domain>.