This template deploys a secure, scalable, and high-performance static website using an S3 bucket for hosting and a CloudFront distribution for content delivery. The S3 bucket is private and accessible only via CloudFront using an Origin Access Identity (OAI).
This template provides the core infrastructure for hosting a static website on AWS. It includes:
- An S3 Bucket (private, not public) for static content, accessible only via CloudFront OAI.
- A CloudFront Distribution to cache and serve your content globally, providing low-latency access to your users.
- A CloudFront Origin Access Identity (OAI) to ensure that your S3 content is only accessible through CloudFront.
- CloudWatch Alarms for monitoring the health of the CloudFront distribution (e.g., 4xx and 5xx error rates).
The infrastructure code is located in the infra/ directory and is managed by Terraform. Example static content is in the app/ directory.
Global Users
│
▼
┌──────────────────────────────────┐
│ │
│ CloudFront Distribution │
│ (Edge Locations Worldwide) │
│ - HTTPS Enabled │
│ - Caching at Edge │
│ │
└────────────────┬─────────────────┘
│
│ Origin Access Identity (OAI)
│ (Secure Access Only)
▼
┌──────────────────────────────────┐
│ │
│ S3 Bucket (Private) │
│ - Versioning Enabled │
│ - Encryption at Rest │
│ - Bucket Policy (OAI Only) │
│ │
│ ├── index.html │
│ ├── css/ │
│ ├── js/ │
│ └── images/ │
│ │
└──────────────────────────────────┘
Security & Performance:
- S3 bucket is private - no public access
- CloudFront OAI is the only entity with S3 GetObject permissions
- Content is cached at 200+ edge locations worldwide
- HTTPS enforced with CloudFront default certificate
- Automatic compression for faster delivery
First, navigate to the infra directory:
cd infraThen, you can initialize and deploy the infrastructure:
-
Initialize Terraform:
terraform init
-
Plan the deployment: Review the
variables.tffile for available parameters. You must provide at leastbucket_nameanddistribution_name. To ensure the S3 bucket name is globally unique, a random suffix will be automatically appended to the name you provide.terraform plan -var="bucket_name=my-static-site" -var="distribution_name=my-static-site"
-
Apply the configuration: Confirm the plan to deploy your infrastructure. The final bucket name will be shown in the output.
terraform apply -var="bucket_name=my-static-site" -var="distribution_name=my-static-site"
After the infrastructure is deployed, you can upload your website's files to the S3 bucket. The full, unique name of the bucket is available in the Terraform output bucket_id.
You can use the AWS CLI to sync your app folder to the S3 bucket:
aws s3 sync ../app s3://$(terraform output -raw bucket_id)Once the files are uploaded, your website will be available at the distribution_domain_name provided in the Terraform outputs.
bucket_id: The unique S3 bucket namebucket_arn: The ARN of the S3 bucketdistribution_domain_name: The CloudFront URL for your siteorigin_access_identity_id: The CloudFront OAI IDorigin_access_identity_iam_arn: The OAI IAM ARN (used in the S3 bucket policy)
- The S3 bucket is not public. Only CloudFront (via the OAI) can access objects in the bucket.
- The S3 bucket policy is automatically managed by Terraform and grants
s3:GetObjectonly to the OAI.
- Access Denied via CloudFront?
- Make sure you uploaded your files to the correct S3 bucket (
bucket_idoutput). - Ensure the CloudFront distribution is fully deployed (status: Deployed).
- Wait a few minutes for propagation after changes.
- The S3 bucket policy must reference the OAI IAM ARN (managed automatically by this template).
- If you change the OAI or bucket, re-apply Terraform.
- Make sure you uploaded your files to the correct S3 bucket (
- Run
make helpto see all available commands and get help with common tasks - Open a support ticket at https://senora.dev/NewTicket
This template is maintained by Senora.dev.