Deploy to S3 + CloudFront
Starting point: npm run build has been run. The out/ folder exists with all static HTML, JS, CSS, and assets.
End point: Site live on a CloudFront HTTPS URL.
Part 1 — S3 Bucket
Step 1: Create the bucket
- Open AWS Console → S3 → Create bucket
- Bucket name:
sonkar-me - AWS Region: pick your closest region (e.g.
ap-south-1for Mumbai) - Under "Block Public Access settings for this bucket" — uncheck "Block all public access"
- Tick the acknowledgement checkbox that appears
- Leave everything else as default
- Click Create bucket
Step 2: Enable static website hosting
- Click into the
sonkar-mebucket → Properties tab - Scroll to the bottom → Static website hosting → click Edit
- Select Enable
- Index document:
index.html - Error document:
404.html - Click Save changes
After saving, scroll back to Static website hosting — copy the Bucket website endpoint URL. It looks like:
http://sonkar-me.s3-website.ap-south-1.amazonaws.com
Keep this URL handy for CloudFront setup.
Step 3: Set bucket policy (public read)
- Permissions tab → scroll to Bucket policy → click Edit
- Paste the following policy exactly:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::sonkar-me/*"
}
]
}
- Click Save changes
The bucket Permissions tab will now show a red "Publicly accessible" badge — this is expected and required.
Step 4: Upload the out/ folder contents
- Click the Objects tab → Upload
- Click Add files and Add folder
- Upload the contents inside
out/— not theout/folder itself. Your upload should include:index.htmlabout/(folder)notes/(folder)work/(folder)404.html_next/(folder — contains all JS/CSS chunks)images/,fonts/,robots.txt,sitemap.xml, etc.
- Leave all upload settings as default — S3 auto-detects content types
- Click Upload and wait for it to complete (may take a minute with
_next/assets)
Tip: On Windows, open
out/in Explorer, select all files and folders inside it (Ctrl+A), then drag them into the S3 upload interface.
✅ Checkpoint 1 — Test S3 directly
Visit the bucket website endpoint URL you copied in Step 2 (http://sonkar-me.s3-website...).
You should see your portfolio homepage. Click through to /about/, /notes/, a note article — all should work.
If you get 403 Forbidden: the bucket policy in Step 3 is missing or wrong.
If you get 404: the index.html at root was not uploaded, or static website hosting isn't enabled.
Part 2 — CloudFront Distribution
Step 5: Create the distribution
-
Open AWS Console → CloudFront → Create distribution
-
Origin domain:
- Do not select from the dropdown (it will suggest the S3 REST endpoint which breaks directory routing)
- Manually paste the S3 website endpoint URL from Step 2, without
http://:
sonkar-me.s3-website.ap-south-1.amazonaws.com -
Protocol: select HTTP only
(S3 website endpoints only speak HTTP — CloudFront handles HTTPS for visitors) -
Origin path: leave empty
Step 6: Configure viewer settings
Still on the same Create distribution page, scroll to Default cache behavior:
- Viewer protocol policy:
Redirect HTTP to HTTPS - Allowed HTTP methods:
GET, HEAD - Cache policy:
CachingOptimized(default) - Origin request policy: leave as None
Step 7: Distribution settings
Scroll to Settings:
- Default root object:
index.html - Price class:
Use only North America and Europe(cheapest) — or choose All Edge Locations for best global performance - WAF: skip for now (leave disabled)
- Description (optional):
sonkar-me portfolio
Click Create distribution.
Step 8: Configure custom error pages (critical)
After the distribution is created:
-
Click into your distribution → Error pages tab → Create custom error response
-
Add this response:
Field Value HTTP error code 403Customize error response Yes Response page path /404.htmlHTTP response code 404 -
Click Create custom error response, then add a second one:
Field Value HTTP error code 404Customize error response Yes Response page path /404.htmlHTTP response code 404
This handles deep-link navigation — e.g. typing
yoursite.com/notes/bloom-filters/directly into a browser. Without this, CloudFront returns a 403 instead of routing to the page.
✅ Checkpoint 2 — Wait for deployment
- Go to CloudFront → Distributions
- Your distribution shows Status: Deploying — wait until it changes to Enabled (typically 5–15 minutes)
- Copy the Distribution domain name — it looks like:
d1a2b3c4defgh.cloudfront.net
✅ Checkpoint 3 — Verify the live site
Visit https://d1a2b3c4defgh.cloudfront.net (your actual domain).
Test these specifically:
- Homepage loads (
/) -
/about/loads -
/notes/loads - A note article loads e.g.
/notes/bloom-filters/ -
/work/loads - HTTPS padlock is present
- Typing a URL directly (not clicking a link) works — this confirms error pages are set up correctly
Part 3 — Redeploying after changes
When you update the site (npm run build → new out/ folder):
Step 9: Re-upload to S3
- S3 →
sonkar-me→ Objects tab → select all → Delete - Re-upload the new
out/contents (same as Step 4)
Step 10: Invalidate CloudFront cache
CloudFront aggressively caches files. After uploading new files, old versions are served until the cache expires. Force an immediate refresh:
- CloudFront → your distribution → Invalidations tab → Create invalidation
- Object paths:
/* - Click Create invalidation
Wait ~30 seconds. The new version is now live.
Cost note: AWS gives 1,000 invalidation paths free per month.
/*counts as 1 path, so normal deployments are free.
Summary
out/ folder
→ uploaded to S3 bucket "sonkar-me" (static website hosting ON, public read policy)
→ CloudFront distribution (origin = S3 website endpoint, HTTP only)
→ Viewer: HTTPS redirect, custom error pages → /404.html
→ Live at https://dXXXXXXXXXXXX.cloudfront.net
Next: Setting Up Custom Domain — connect sonkar.dev to this distribution using Route 53 and an ACM certificate.