Configuration Files
4 files
Production-ready configuration files with detailed comments and best practices. Each file works together as a complete deployment solution.
Complete AWS infrastructure for S3 + CloudFront hosting
terraform
# Terraform configuration for React on AWS S3 + CloudFront
terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = var.aws_region
}
variable "aws_region" {
default = "us-east-1"
}
variable "app_name" {
default = "my-react-app"
}
variable "domain_name" {
description = "Custom domain (optional)"
default = ""
}
# S3 Bucket for static website
resource "aws_s3_bucket" "website" {
bucket = "${var.app_name}-website"
}
resource "aws_s3_bucket_website_configuration" "website" {
bucket = aws_s3_bucket.website.id
index_document {
suffix = "index.html"
}
error_document {
key = "index.html" # SPA routing
}
}
resource "aws_s3_bucket_public_access_block" "website" {
bucket = aws_s3_bucket.website.id
block_public_acls = false
block_public_policy = false
ignore_public_acls = false
restrict_public_buckets = false
}
resource "aws_s3_bucket_policy" "website" {
bucket = aws_s3_bucket.website.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "PublicReadGetObject"
Effect = "Allow"
Principal = "*"
Action = "s3:GetObject"
Resource = "${aws_s3_bucket.website.arn}/*"
}
]
})
depends_on = [aws_s3_bucket_public_access_block.website]
}
# CloudFront Origin Access Identity
resource "aws_cloudfront_origin_access_identity" "website" {
comment = "OAI for ${var.app_name}"
}
# CloudFront Distribution
resource "aws_cloudfront_distribution" "website" {
enabled = true
is_ipv6_enabled = true
default_root_object = "index.html"
price_class = "PriceClass_100" # US, Canada, Europe
origin {
domain_name = aws_s3_bucket.website.bucket_regional_domain_name
origin_id = "S3-${var.app_name}"
s3_origin_config {
origin_access_identity = aws_cloudfront_origin_access_identity.website.cloudfront_access_identity_path
}
}
default_cache_behavior {
allowed_methods = ["GET", "HEAD", "OPTIONS"]
cached_methods = ["GET", "HEAD"]
target_origin_id = "S3-${var.app_name}"
forwarded_values {
query_string = false
cookies {
forward = "none"
}
}
viewer_protocol_policy = "redirect-to-https"
min_ttl = 0
default_ttl = 3600
max_ttl = 86400
compress = true
}
# SPA routing - return index.html for 404s
custom_error_response {
error_code = 404
response_code = 200
response_page_path = "/index.html"
}
custom_error_response {
error_code = 403
response_code = 200
response_page_path = "/index.html"
}
restrictions {
geo_restriction {
restriction_type = "none"
}
}
viewer_certificate {
cloudfront_default_certificate = true
}
}
# Outputs
output "s3_bucket_name" {
value = aws_s3_bucket.website.id
}
output "cloudfront_distribution_id" {
value = aws_cloudfront_distribution.website.id
}
output "cloudfront_domain_name" {
value = aws_cloudfront_distribution.website.domain_name
}
output "website_url" {
value = "https://${aws_cloudfront_distribution.website.domain_name}"
} Pro Tips
- 💰 S3 costs ~$0.023/GB/month, CloudFront ~$0.085/GB for first 10TB
- 🌍 PriceClass_100 covers US, Canada, Europe (cheapest option)
- ⚡ CloudFront caching reduces S3 requests by 90%+
- 🔒 HTTPS enabled by default with CloudFront certificate
- 🎯 SPA routing: 404s redirect to index.html for client-side routing
- 💡 Run "terraform apply" to create all infrastructure
- 📊 Add custom domain by updating viewer_certificate block
- ⚠️ Remember "terraform destroy" when done testing
Vite build configuration optimized for AWS deployment
typescript
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
export default defineConfig({
plugins: [react()],
build: {
outDir: 'dist',
sourcemap: true,
rollupOptions: {
output: {
manualChunks: {
vendor: ['react', 'react-dom'],
},
// Cache busting with content hashes
entryFileNames: 'assets/[name].[hash].js',
chunkFileNames: 'assets/[name].[hash].js',
assetFileNames: 'assets/[name].[hash].[ext]'
},
},
},
}) Pro Tips
- 📦 Content hashes enable long-term caching (1 year)
- ⚡ Vendor chunk separates React from app code
- 🗺️ Source maps help debug production issues
- 💡 CloudFront caches assets with immutable headers
- 🎯 Manual chunks improve cache hit rates
Project dependencies and deployment scripts
json
{
"name": "my-react-app",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"deploy": "npm run build && aws s3 sync dist/ s3://my-react-app-website --delete"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.20.0"
},
"devDependencies": {
"@types/react": "^18.2.43",
"@types/react-dom": "^18.2.17",
"@vitejs/plugin-react": "^4.2.1",
"typescript": "^5.2.2",
"vite": "^5.0.8"
}
} Pro Tips
- 🚀 "deploy" script for manual deployments
- 📦 react-router-dom for client-side routing
- ⚡ TypeScript type-checks before building
- 💡 Update S3 bucket name in deploy script
- 🎯 Use GitHub Actions for automated deployments
Environment variables for AWS deployment
bash
# AWS Configuration (for local deployment script) AWS_REGION=us-east-1 AWS_PROFILE=default # S3 Bucket (created by Terraform) S3_BUCKET=my-react-app-website # CloudFront Distribution ID (from Terraform output) CLOUDFRONT_DISTRIBUTION_ID=E1234567890ABC # Public environment variables (baked into build) VITE_API_URL=https://api.example.com VITE_APP_NAME=My React App VITE_ENABLE_ANALYTICS=true
Pro Tips
- 🔒 Never commit .env to git (add to .gitignore)
- 💡 VITE_ prefix makes variables available in browser
- ⚠️ All VITE_ variables are PUBLIC (in bundle)
- 🎯 Use AWS Secrets Manager for sensitive data
- 📝 Copy to .env.local for local development
- 🚀 GitHub Actions uses repository secrets instead