Regularly register a domain and want to put some web content there? This is a collection of tools you can use to quickly set up a website hosted by Amazon Web Services. This is a very inexpensive hosting option, costing as little as 50 cents per month.
- Registering the domain name with a domain registrar.
- Configuring authoritative name servers for your website. This involves establishing an account with a DNS provider and typing the address of the DNS servers into the registrar. This tells the internet "Which server is responsible for the phone book (DNS) for this domain name?"
- Populating that phone book (DNS) with entries like "www" (what is the IP address that a browser should query when someone types www.domainname.com?)
- Hosting the website somewhere (html files and images stored on a computer that is internet accessible and running 24/7)
Many companies offer all of these parts - or some combination of parts (squarespace, wix, etc). However, you rarely have full control over each, and they tend to be expensive!
This project is meant to be a starting point for people who:
- Want to start from the included React/Vite site or bring their own static build output
- Want to write their own HTML/CSS/JS or use:
- React/Vue/Svelte or similar JavaScript frameworks
- Jekyll/Hugo/Astro or similar static site generators
- Want to learn more about DNS and infrastructure as code
- Want to learn more about Amazon Web Services
- Want to learn more about CI/CD and GitHub Actions
- Want to host a website for as little money as possible
- Want to extend this project to include other AWS resources for dynamic sites (e.g. serverless functions, databases, etc)
This project is NOT ideal for people who:
- Want to run Wordpress, Drupal, or another SQL and PHP based CMS.
- AWS: Amazon Web Services
- S3: Simple Storage Service, an AWS service for storing files. This is where your website will be stored.
- CloudFront: AWS's content delivery network (CDN). This will cache your website's content at edge locations around the world, making your website faster for users. It will also make your website secure (https) by providing an SSL certificate.
- DNS: Domain Name Server. This is the phone book for the internet. It translates domain names (like www.domainname.com) into IP addresses (like 1.2.3.4).
- NS: Name Server. This is a DNS server that is authoritative for a domain name. It is responsible for answering queries about that domain name.
- Route53: AWS's DNS service. This will allow you to point your domain name to your website.
- Terraform: A tool for managing infrastructure as code. Terraform is used to configure the AWS resources.
- GitHub Actions: A tool for automating tasks in GitHub. We will use this to automatically deploy your website to S3 when you commit changes to your GitHub repo. Github offers up to 2000 minutes of free GitHub actions per month, which is plenty for a personal website.
./create-hosted-zone.sh: A shell script that:- Adds a hosted zone in Route53 for your domain
- Prints the NS records for your domain so you can update your registrar
- Detects the current registrar through RDAP/whois when possible
- Prints registrar-specific nameserver instructions and useful links for common registrars
- Can wait and poll public DNS until the registrar delegates the domain to Route53
- Terraform module that does the following:
- Creates an S3 bucket (domainname) and static site hosting with
index.htmlas the index document. - Creates a second S3 bucket for logs (domainname-logs) with a lifecycle policy to delete logs after 15 days
- Creates a CloudFront distribution
- Creates an SSL certificate for the domain name (adding www. as a subject alternative name)
- Creates a Route53 record for the domain name (adding www. as a CNAME)
- Creates an IAM user & policy for a GitHub action. Warning: Check the permissions, they are too liberal right now :).
- (optional) Creates Route53 MX records and TXT validation record for Google Workspace
- Creates an S3 bucket (domainname) and static site hosting with
./set-up-repo.sh: A shell script that:- Creates a new private GitHub repo (called domainname.com) in your GitHub account
- Commits all files in the current directory to the repo
- Adds AWS credentials to your GitHub repo secrets so you can use the GitHub action to deploy your website to the S3 bucket
- Sets up a GitHub action to build the React/Vite site and auto-deploy the
distfolder - Creates a shell script called "manually-deploy.sh" that you can use to manually deploy your website to the S3 bucket
- React/Vite starter site:
npm run devstarts the local development servernpm run buildwrites production assets todist- GitHub Actions runs the build, syncs
distto S3, and invalidates CloudFront
- DNS delegation helper scripts:
./scripts/check-dns-delegation.shprints current registrar, current public nameservers, and expected Route53 nameservers./scripts/check-dns-delegation.sh --waitpolls until public DNS points at Route53./apply.shrefuses to runterraform applyuntil nameserver delegation is correct
- A GitHub account
- A domain registered with your favorite registrar. I use namecheap.com.
- Terraform must be installed.
- An account with AWS. You can sign up for an account here.
- AWS CLI must be installed and configured with FullAccess (configure it by typing
aws configure sso, more information can be found here). - jq must be installed. This is a command-line JSON processor used by the shell scripts.
- gh Github CLI must be installed (and logged in) to create a new private repo and set up GitHub actions.
- Node.js 20+ must be installed if you want to run or build the included React/Vite starter locally.
- Clone this repo! I recommend cloning it into a directory named after your domain name. e.g.
mkdir <domainname.com>
cd <domainname.com>
git clone https://github.com/klinquist/tf-aws-s3-cf-template.git .- Change the variables in the terraform.tfvars file.
- Run
./create-hosted-zone.shto automatically create the hosted zone in AWS Route53. - Login to your domain registrar and update the NS records for your domain to the ones printed by the script above. The script will try to detect your registrar and print a direct link/instructions for common providers.
If your domain's NS records are not pointed to AWS before running terraform, certificate validation will timeout.
You can check the current status at any time:
./scripts/check-dns-delegation.shOr wait until public DNS points to the Route53 nameservers:
./scripts/check-dns-delegation.sh --waitThe checker shows output like:
Status: registrar still points to:
- dns1.registrar-example.com
Waiting for Route53 nameservers:
- ns-123.awsdns-45.com
- Run the following to deploy the infrastructure:
./apply.sh --auto-approve
./apply.sh runs the DNS delegation check first and refuses to continue until the domain is delegated to Route53. It also runs terraform init for you if needed.
- Run
./set-up-repo.shto create a new private repository on GitHub, set up GitHub actions, and add AWS credentials to your GitHub repo secrets. This will make a sample site available on https://www.domainname.com!
Note: This creates resources in us-east-1. If you want to change the default region, you can do so by editing main.tf.
This repo now includes a React/Vite starter. Run it locally with:
npm install
npm run devBuild the production site with:
npm run buildCommit your React app changes and push to GitHub. The GitHub action will run npm ci, build the site into dist, deploy dist to the S3 bucket, and invalidate the CloudFront cache. Your changes should be live in a few minutes.
If you prefer another generator such as Jekyll, Hugo, or Astro, update .github/workflows/deploy.yml and manually-deploy.sh so they build your site and sync the generated output folder to S3.
This repo contains a shell script called ./destroy-all.sh which will:
- Remove everything from the S3 buckets
- Run 'terraform destroy' to remove all terraform-managed resources
- Delete the hosted zone from Route53
- Delete the GitHub repo
- Use the GitHub terraform provider instead of
ghcli? Still requiresghto be installed and authorized or a personal access token to be provided. A shell script would still be required to commit files to the repository. - Set up the Github-AWS OIDC connection rather than generating an AWS user w/ access key & secret. This would make things more secure.