A starter template for deploying a static website to AWS using S3 and CloudFront, provisioned with AWS CDK (TypeScript).
If you use an AI coding agent such as GitHub Copilot or Claude Code, you can bootstrap the entire setup — from creating your GitHub repo to deploying the site — with a single prompt. Make sure you have the prerequisites installed first, then try something like:
I want to create a website called "My Website" using https://github.com/ecliptical/aws-static-website-template as a template. The website should be hosted on https://www.example.com — the domain is managed by Route 53 in hosted zone example.com. The home page should say "Hello, world!" I want to host my code in a private repo at https://github.com/myuser/my-website.
The agent will walk through the first-time setup workflow: creating the repo, configuring CDK, deploying the infrastructure, setting up the GitHub Actions secret, and verifying the site is live.
- AWS S3 + CloudFront for global static site hosting
- AWS CDK (TypeScript) for infrastructure as code
- Custom domain support with ACM TLS certificates
- Route 53 integration for DNS management (optional)
- GitHub Actions workflow with OIDC authentication for automated deployment
- GitHub Pages as an optional alternative deployment target
- React 18 minimal frontend example
Your website files live in the docs/ directory. When you push changes to GitHub, a GitHub Actions workflow uses AWS CDK to deploy them to a private S3 bucket. A CloudFront CDN distribution sits in front of S3, serving your site to users over HTTPS with low latency worldwide. GitHub Actions authenticates to AWS securely via OIDC — no long-lived access keys needed.
Optionally, you can attach a custom domain with a TLS certificate from ACM, and use Route 53 for DNS. GitHub Pages is also available as a simpler alternative or secondary hosting option.
flowchart LR
Developer["Developer"]
GH["GitHub Repository"]
GHA["GitHub Actions"]
GHP["GitHub Pages<br/>(optional)"]
subgraph AWS
IAM["IAM OIDC<br/>Provider + Role"]
CDK["AWS CDK"]
S3["S3 Bucket<br/>(private)"]
CF["CloudFront<br/>Distribution"]
ACM["ACM Certificate<br/>(optional)"]
R53["Route 53<br/>(optional)"]
end
Users["Users"]
Developer -- "git push" --> GH
GH -- "workflow trigger" --> GHA
GH -. "GitHub Pages<br/>(optional)" .-> GHP
GHA -- "OIDC auth" --> IAM
IAM -- "assume role" --> CDK
CDK -- "deploy content" --> S3
CDK -- "create/update" --> CF
CDK -. "provision cert" .-> ACM
CDK -. "manage DNS" .-> R53
ACM -. "TLS" .-> CF
R53 -. "alias record" .-> CF
CF -- "OAC" --> S3
Users -- "HTTPS" --> CF
Users -. "HTTPS" .-> GHP
This guide assumes you're on macOS. Install each tool in order — later steps depend on earlier ones.
Homebrew is used to install most of the tools below. Open Terminal (found in Applications → Utilities) and run:
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"Follow the on-screen instructions. After installation, verify it works:
brew --versionGit is the version control system used to manage this repository. macOS includes Git via Xcode Command Line Tools, but you can also install it via Homebrew:
brew install gitConfigure your identity (use the email associated with your GitHub account):
git config --global user.name "Your Name"
git config --global user.email "you@example.com"You'll need a free GitHub account to use this template and deploy via GitHub Actions.
The GitHub CLI (gh) is used by the included helper script to set deployment secrets. Install and authenticate:
brew install gh
gh auth loginFollow the prompts to authenticate with your GitHub account.
Node.js (v18 or later) is required to run AWS CDK. Install it via Homebrew:
brew install nodeVerify the installation:
node --version # should print v18 or later
npm --versionYou'll need an AWS account — the free tier covers most resources used by this template.
Install the AWS CLI and configure it with your credentials:
brew install awscli
aws configureaws configure will prompt you for:
| Prompt | Value |
|---|---|
| AWS Access Key ID | From the IAM console (see below) |
| AWS Secret Access Key | From the IAM console (see below) |
| Default region name | us-east-1 |
| Default output format | json |
To create access keys: open the IAM console → Users → select your user → Security credentials → Create access key.
The AWS CDK CLI is the command-line tool for deploying infrastructure:
npm install -g aws-cdkVerify:
cdk --versionCDK requires a one-time bootstrap step per AWS account/region. Replace ACCOUNT-ID with your 12-digit AWS account ID:
cdk bootstrap aws://ACCOUNT-ID/us-east-1You can find your account ID by running aws sts get-caller-identity.
- Use this template — Click "Use this template" on GitHub, or clone the repository
- Configure — Edit
infra/cdk.jsoncontext with your settings (see Configuration) - Deploy infrastructure —
cd infra && npm install && cdk deploy - Set GitHub secret — Run
cd infra && ./setup-github-secret.shor manually copyDeployRoleArn(see GitHub Actions Setup) - Deploy content — Push to GitHub and run the "Deploy to AWS" action
/
├── .agents/
│ └── skills/
│ └── setup-site/
│ └── SKILL.md # First-time setup skill for AI agents
├── .github/
│ ├── dependabot.yml # Dependabot configuration
│ └── workflows/
│ ├── ci.yml # CI checks on pull requests
│ └── deploy-aws.yml # GitHub Action for content deployment
├── docs/ # Website content (deployed to S3)
│ ├── favicon.svg # Site favicon
│ └── index.html # Main landing page
├── infra/ # AWS CDK infrastructure
│ ├── bin/app.ts # CDK app entry point
│ ├── lib/static-site-stack.ts # Infrastructure stack
│ ├── cdk.json # CDK configuration
│ ├── package.json
│ ├── package-lock.json
│ └── tsconfig.json
├── .gitignore
├── AGENTS.md
├── LICENSE
└── README.md
Edit infra/cdk.json to set your configuration in the context section:
| Setting | Required | Description |
|---|---|---|
domainName |
No | Custom domain (e.g., www.example.com) |
hostedZoneName |
No | Route 53 hosted zone (e.g., example.com); enables automatic cert validation and DNS records |
certificateArn |
No | Pre-existing ACM certificate ARN (alternative to Route 53 for custom domain) |
Example with a custom domain and Route 53:
{
"context": {
"domainName": "www.example.com",
"hostedZoneName": "example.com"
}
}cd infra
npm install
cdk deployThe stack is deployed to us-east-1 (required for CloudFront + ACM certificate integration). S3 content is served globally via CloudFront regardless of bucket region.
When a GitHub remote is detected, all resources in the stack are tagged with project: <owner>/<repo> (e.g., project: myuser/my-website) for easy identification in the AWS console.
CDK will output the values needed for GitHub Actions:
| CDK Output | Set in GitHub as |
|---|---|
DeployRoleArn |
Secret: AWS_ROLE_ARN |
Save this value as a GitHub repository secret so the deployment workflow can authenticate to AWS. See GitHub Actions Setup for instructions.
Note: The stack creates a GitHub OIDC identity provider in your AWS account if one doesn't already exist. If a provider is already present (from another project), it will be reused automatically.
This is the fully automated path. If your domain is registered outside of AWS, you first need to delegate DNS to Route 53:
- Create a hosted zone in the Route 53 console
- Go to Hosted zones → Create hosted zone
- Enter your domain name (e.g.,
example.com) and click Create
- Update name servers at your domain registrar
- Copy the 4 NS record values from the new Route 53 hosted zone
- Replace the name servers at your domain registrar with these values
- Wait for DNS propagation (can take up to 48 hours, but usually minutes)
- Configure CDK — Set both
domainNameandhostedZoneNameininfra/cdk.json - Deploy — Run
cdk deploy. CDK will automatically:- Create an ACM TLS certificate (validated via Route 53 DNS)
- Configure CloudFront with your custom domain
- Create Route 53 A and AAAA alias records pointing to CloudFront
If you prefer to manage DNS entirely outside of AWS:
- Create an ACM certificate in the ACM console (must be in us-east-1)
- Request a public certificate for your domain
- Choose DNS validation
- Add the provided CNAME record at your DNS provider
- Wait for validation to complete
- Configure CDK — Set
domainNameandcertificateArnininfra/cdk.json - Deploy — Run
cdk deploy - Create DNS record at your DNS provider pointing to the CloudFront domain (from the
DistributionDomainNameoutput):- For a subdomain (e.g.,
www.example.com): add a CNAME record - For an apex domain (e.g.,
example.com): CNAME records don't work — use Route 53 (Option A) or a DNS provider that supports ALIAS/ANAME records
- For a subdomain (e.g.,
After running cdk deploy, configure your GitHub repository with the deploy role:
Option A: Automated (recommended)
cd infra && ./setup-github-secret.shThis reads the DeployRoleArn from the CloudFormation stack and sets it as the AWS_ROLE_ARN GitHub secret automatically. Requires the GitHub CLI (gh) to be installed and authenticated.
Option B: Manual
- Go to Settings → Secrets and variables → Actions
- Add a Repository secret:
AWS_ROLE_ARN(from CDK outputDeployRoleArn)
Then go to Actions → Deploy to AWS → Run workflow to deploy content.
cd infra && npx cdk deploy --require-approval neverThe site can also be published via GitHub Pages since web assets live in the docs/ directory:
- Go to Settings → Pages in your GitHub repository
- Under Source, select Deploy from a branch
- Set the branch to
mainand the folder to/docs - Click Save
The site will be available at https://<owner>.github.io/<repo>/ and updates automatically on push.
Note: GitHub Pages is independent of the AWS deployment. You can use one or both.
This template is licensed under the MIT License.
When you create a project from this template, you are free to replace the license with one of your own choosing — including proprietary licenses. The MIT license permits this explicitly. Simply replace the contents of the LICENSE file (and update any license references) to reflect the terms you want for your project.