Static Site AWS S3 Cloud Infrastructure

Shows Nuxt.js static site with an arrow into an S3 bucket all in a cloud

In this information and a how-to guide where I document the steps and tradeoffs in creating and maintaining a hosted static site on AWS Cloud Infrastructure. Without a dedicated development operations (devOps) or site reliability engineer (SRE), the infrastructure is designed to be cost-effective, secure, and maintainable for a solo developer who has multiple content sites to publish and manage. After setting up the cloud infrastructure, see my Static Site AWS CICD Pipeline how-to guide.

Information

Site Web Presence

  • Production site with custom domain
  • Staging site with subdomain
  • Development site with subdomain

Inventory

For a static site hosted on AWS, the required cloud infrastructure is minimal and inexpensive. The main components are:

  • Route 53 for a custom domain
  • Certificate Manager (ACM) for https certificate
  • CloudFront for CDN
  • S3 buckets for static site hosting
  • IAM roles and policies for secure access

Costs

Here are my monthly costs for hosting my blog with this infrastructure:

ServiceMonthly CostNotes
Custom Domain$1.25$15/year registration renewal amortized
AWS Certificate ManagerfreeFree for public certificates
AWS Route53$0.551 hosted zone, 0.40 per 1,000,000 queries for the first 1 Billion queries
AWS CloudFrontfree1TB data transfer out, 10 million requests
AWS S3$0.05Requests per 10,000, first 50 TB / month of storage used, varies on demand
AWS CodePipeline/Build/Deploy$0.00Free tier 100 build minutes/month, 1GB storage
Total$1.85Approximate monthly cost per site

Your costs may vary based on usage, data transfer, and additional services used.

Upgrades

For additional security and performance, you might consider upgrading to AWS CloudFront with WAF (Web Application Firewall). This provides enhanced security features and protection against common web exploits. With static-website hosting, this may be overkill, but for API Gateways or database access, it is worthy consideration.

ServiceMonthly CostNotes
AWS CloudFront Business WAF$8.50WAF includes web traffic filtering, bot control, etc.

Prod Infrastructure

Prod (Production) Infrastructure consists of cloud resources that host your web site for public viewing. For JAMStart, the prod infrastructure recommendations are:

  1. Custom Domain
  2. HTTPS Site Certificate
  3. AWS Route53 Hosted zone, subdomain redirect
  4. AWS CloudFront Distribution
  5. AWS S3 Bucket

Dev Infrastructure

For development and testing, you can create a similar infrastructure with subdomains. For example, if your custom domain is example.com, you can create a subdomain dev.example.com for development and testing purposes. This allows you to test changes without affecting the production site.

  1. Subdomain (dev.example.com)
  2. S3 Bucket for dev site

Staging Infrastructure

For staging, you can create another subdomain stage.example.com to test changes before deploying them to production. This allows for a final round of testing in an environment that closely resembles production.

  1. Subdomain (staging.example.com)
  2. S3 Bucket for staging site

How-to Guide

This section provides a step-by-step guide to creating the cloud infrastructure required to host a static site on AWS.

Custom Domain

You need a registered custom domain first. Yes, really. Create, transfer, and/or attach custom domain nameservers in AWS Route 53. Web registration at Amazon is $12-$15/year depending on the domain name. You can also transfer or connect to your domain from another registrar with AWS Route 531. Simplicity is best, so I recommend registering or transferring your domain to AWS Route 53.

Domain Registrar

You can register a new your domain 🌎 with AWS Route 53 or transfer your domain to AWS Route 53 from another registrar.

Hosted Zone

A hosted Zone is the set of domain and subdomain records for your site. It is required for your site to function. If you registered your domain with AWS Route 53, a hosted zone is automatically created for you. To see if you have a hosted zone, navigate to:

  1. Navigate to:
    • AWS Route 53 → Hosted zones
  2. Look for your custom domain name in the hosted zone list.
  3. If found, open the hosted zone and double-check that it is 'Public hosted zone', which shows up as a tag next to the hosted zone name.
  4. If not found, you will need to create a hosted zone.

Create Hosted Zone

You can create a Hosted Zone by following these steps:

  1. Navigate to:
    • Amazon Route 53 → Hosted zones → Create hosted zone
  2. Enter your custom domain name
  3. Choose 'Public hosted zone'
  4. Choose 'Create hosted zone'

Verify

A new hosted zone in Route53, should have two records in it.

RecordTypeValue
{custom domain name}NS{set of AWS name servers}
{custom domain name}SOA{single AWS name server}

Nameservers

Wherever your domain is registered, the domain needs to be updated with your name servers in the NS record in your hosted zone.

Route 53 Domains

For domains registered with AWS, the names servers should already be correct, validate they are correct. For domains registered elsewhere but later transferred into AWS, you will need to update the name servers within AWS Route 53.

  1. Find your NS record name servers at:
    • Amazon Route 53 → Hosted zones → (pick your hosted zone)
  2. Open the NS record
    • find the nameservers. There should be four name server records with names like ns-1247.awsdns-27.org, ns-614.awsdns-12.net, etc.
  3. Find your registered domain names at
    • Amazon Route 53 → Registered domains - (pick your custom domain)
  4. Validate that name servers are the same as the NS record, or update.

To update:

  1. Choose Actions drop down and Edit nameservers
  2. Replace the domain nameservers with your hosted zone NS record nameservers.

Note it can take up to 24 hours ⌛ for nameserver changes to propagate throughout the internet. You will need to wait that long in order to use DNS Validation for your site certificate.

Domains not on AWS

For domains that are not registered with AWS Route 53, you will need to update your domain registrar directly with these nameservers, by removing any name servers and adding the four from your hosted zone NS record.

Note it can take up to 48 hours ⌛ for nameserver changes to propagate throughout the internet.

Site S3 Buckets

Create three AWS S3 buckets to host your static site. For each bucket repeat this procedure:

  1. Create S3 Bucket with proper name
  2. Set Bucket Permissions for public object access
  3. Set Bucket Properties for static website hosting

You can use the AWS CLI (aws s3 mb <name>, etc.) for these steps but I will document the process using the AWS Console.

Create Bucket

  1. Make sure your bucket is in correct region close to your users, e.g. us-east-1 (N. Virginia) for east coast USA
  2. Navigate to:
    • Amazon S3 → Create bucket
  3. Choose 'General purpose' bucket
  4. Name the bucket exactly the same name as your Custom Domain or Subdomain, including the any periods . and all lower-case. Otherwise, your endpoint will not be visible as an alias for the Route 53 record creation.
    • Production: You must name the S3 Bucket exactly the same name as your Custom Domain name, i.e. for example.com custom domain, create a bucket named example.com.
    • Staging: pick a subdomain name the same as your staging subdomain (or will be when you create it), i.e. for stage.example.com subdomain, create a bucket named stage.example.com.
    • Development: pick a subdomain name the same as your development subdomain (or will be when you create it), i.e. for dev.example.com subdomain, create a bucket named dev.example.com.
  5. Leave the other options as default or you also use 'Copy settings from an existing bucket' to copy settings from a previous bucket.
  6. Choose 'Create Bucket' to create the bucket.

Bucket Permissions

After the bucket has been created, select your new bucket and choose the 'Permissions' tab.

  1. Set Block public access (bucket settings) to Off, unchecked
    • you may have to acknowledge that you are allowing public access
  2. Add a Bucket Policy, choose 'Edit' under 'Bucket policy'
  • Add the following JSON policy to allow public read access to objects in the bucket, replace {{bucket_name}} with your bucket name for the bucket your are editing.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::{{bucket_name}}/*"
        }
    ]
}
  1. Choose 'Save changes'

Bucket Properties

Change the bucket properties to set up website hosting.

Navigate to:

  • Amazon S3 → (pick your bucket)
  1. Choose the 'Properties' tab and scroll down to 'Static website hosting', then choose 'Edit'.
  2. Set the following S3 bucket properties as appropriate.
PropertyState
Static website hostingEnable
Hosting typeHost a static website
Index documentindex.html
Error document - optional404.html (or whatever you have)
  1. Choose 'Save changes'

Repeat bucket creation

Repeat the above steps to create S3 buckets for your staging and development subdomains if desired.

Site CloudFront

Create a CloudFront distribution to serve your static site from the S3 bucket with your custom domain and certificate, this also provides CDN caching and HTTPS support.

Flow Chart with Route53 CloudFront ACM and S3

Chart showing site flowchart with Route 53, CloudFront, ACM and S3

Create CloudFront Distribution

Make sure you are in the 'us-east-1' (N. Virginia) region for CloudFront.

Navigate to:

  • AWS CloudFront → Create Distribution

Use the step-by-step wizard to create the distribution.

StepFieldStateNotes
1Choose a PlanFreeFree is good, but you upgrade this later if necessary
2Distribution Name"{custom_domain_name} cloudfront"just use your domain name, e.g. pennockprojects.com cloudfront
2Domainenter {custom_domain_name}Choose 'Check domain', should get Domain managed by Route 53
2Add a subdomaintype www in the box next to custom_domain_nameadd others as necessary
3Origin typeAmazon S3just S3
3Origin : S3 originChoose "Browse S3" and select your S3 bucketChoose 'Use website endpoint'
3Settingsleave defaultused recommended and defaults
4Enable SecurityUse the base level WAF - defaultsincluded in the plan at no charge
5Get TLS certificatechoose 'Create certificate`should complete quickly, you can also choose 'Create certification in ACM' and follow these instructions
6Review and CreateCreate Distributionleave defaults

Verify

Check your Route53 hosted zone. Navigate to:

  • Amazon Route 53 → Hosted zones → (pick your hosted zone)

You should have three record types, with multiple CNAME records, in the hosted zone record set

  1. NS record
  2. SOA record
  3. CNAME record(s) for certificate verification for each domain name (2 if you included 'www')

Dev Subdomains

These A-NAME record will not have TLS/HTTPS support and are for development and deployment purposes

The Cloudfront distribution covers your domain and www. subdomain with certificate TLS. For your other 'development' subdomains (stage. and dev.) you will need to add a subdomain A-NAME record in your hosted zone. You can also use this method for your domain name if you do not want to use CloudFront, but that is not recommended.

Flow Chart with Route53 and S3 static bucket

Chart showing User using Route53 A-NAME to S3 site bucket

Subdomain ANAME to S3 Bucket

Open your hosted zone. Navigate to:

  • Amazon Route 53 → Hosted zones → (pick your hosted zone)

Choose 'Create record'

FieldState
Record nametype dev. or stage. subdomain that match your S3 bucket name (leave blank for root domains)
Record typeA - Routes traffic to AWS resource
Aliasenable checkbox
Route traffic toChoose 'Alias to S3 website endpoint`
Choose Region(choose your region)
Choose S3 bucket endpoint(pick your endpoint, should be in dropdown list)
Route traffic to endpointAlias to S3 website endpoint
Route traffic to region(choose your region)
Enter S3 endpoint(pick your endpoint, should be in dropdown list)
Routing policySimple routing
Evaluate target healthleave unchecked for subdomains, checked for domains

Verify

After your certificate is issued and the CloudFront distribution is deployed, you can validate that your custom domain opens your static site hosted from S3 after you deploy it.

Conclusion

You now have the cloud infrastructure required to host a static site on AWS. Here are further relevant guides for your next steps:

Appendix

Manual Certificate

To request a new certificate 🎫 use the AWS certificate manager. You need to create the certificates from the Global From the AWS Console navigate to:

  • AWS Certificate Manager → Certificates → Request

Certificate properties

Your custom domain name is required for the certificate, e.g. example.com It is recommended to include the 'www.' subdomain as well, e.g. www.example.com 2

For each domain name in the public certificate request you will need to create a CNAME record for DNS certification and an ANAME record for routing.

In AWS Certificate Manager choose 'Request a public certificate' and change the following, leaving other properties at default:

FieldState
Domain names : Fully qualified domain namescustom_domain_name
Domain names : Add another name to this certificatewww.custom_domain_name
Validation methodDNS validation

Then choose 'Request' to create the certificate request.

DNS Validation

DNS validation is for each domain name in the certificate you add a CNAME record to your hosted zone which prove that you own the domain for which you are requesting a certificate.

For DNS certificate validation you need a CNAME record to your AWS domain hosted zone for each domain or subdomain on the certificate request (2 if you choose to include www.). Conveniently from the certificate request details you can automatically create these records. Choose the 'create CNAME records' button.

🛑 Important - DNS validation requires these CNAME records to be created.

Verify CNAME records

Your hosted zone should now have at least two additional CNAME records in the record set, one for each domain name on the certificate request. Navigate to:

  • Amazon Route 53 → Hosted zones → (pick your hosted zone)
  • Look for the new CNAME records in the record set.

Check Certificate Status

Certificate Validation should complete in about 30 minutes to an hour after certificate request but can take longer. Go to:

  • ACM → Certificates → (pick your certificate) To check the status, look in Certificate Status until is state changes to 'Issued'.

⌛ Wait for your certificate to validate before creating the CloudFront distribution.

Subdomain redirect

Optionally, if you've created your certificate and CloudFront distribution with 'www', you need to create an ANAME 'www' redirect. In your hosted zone choose 'Create record' for your root

FieldState
Record name'www'
Record typeA - Routes traffic to AWS resource
Route traffic to endpointAlias to another record in this hosted zone
Route traffic to Choose record(pick your ANAME domain without the 'www')

Footnotes

Footnotes

  1. If you have a domain registered with another registrar, you can change the nameservers to point to AWS Route 53 and manage the DNS records in Route 53.
  2. You can also include other subdomains such as 'blog.', 'shop.', 'stage.' etc. I recommend including subdomains separately rather than the subdomain wildcard *.example.com. But for me, I just normally do example.com and www.example.com.