Skip to content

Instantly share code, notes, and snippets.

@j1mmie
Last active May 2, 2023 07:09
Show Gist options
  • Save j1mmie/8d71b1c683cd95e4e0075caaac7aba23 to your computer and use it in GitHub Desktop.
Save j1mmie/8d71b1c683cd95e4e0075caaac7aba23 to your computer and use it in GitHub Desktop.
Static hosting in AWS with http -> https and naked -> www redirects

Static Cloudfront Hosting

Because I've done this so many times in my life but always seem to forget how.

This approach WILL:

  1. Redirect naked domain to www domain in all conditions
  2. Redirect http to https in all conditions
  3. Preserve URL paths and queries. So http://mydomain.com/earth/africa ultimately leads to https://www.mydomain.com/earth/africa

Downsides:

  1. HTTP/Naked URL does two redirects. First is HTTPS/Naked, followed by HTTPS/WWW

Topography:

S3 Buckets:

  1. Public bucket for static files
  2. Empty bucket for naked domain to www redirection

Cloudfront Distributions:

  1. Static content distribution for www
  2. http -> https naked domain redirection

DNS Records:

  1. One A ALIAS record at www to Cloudfront Distrubution #1
  2. One A ALIAS record at apex to Cloudfront Distribution #2

Requirements:

Create certificates in AWS for mydomain.com and www.mydomain.com (or mydomain.com and *.mydomain.com). If you want, these can all be in one certiciate

Instructions:

The general idea is, get your www to work for http and https first. Then get the apex domain to redirect there under http and https.

1. Create www bucket

  1. The bucket can have any name, but its easiest if you use www.mydomain.com
  2. Add public bucket policy for www.mydomain.com. It's in the Permissions tab. Note that the line that says Resource should reflect your public bucket's name.
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::PUBLIC_BUCKET_NAME_HERE/*"
        }
    ]
}
  1. Enable static hosting.
    Select "Host a static website"
    index.html for the default document

2. Create www distribution

  1. Origin Domain: choose the www bucket from the dropdown. AWS will now notify you that you should "use website endpoint". Do that. Ultimately it should look something like this: www.mydomain.com.s3.us-west-1.amazonaws.com
  2. Protocol: HTTP. This is the protocol it will be accessing S3 over, and there's no need to use SSL here.
  3. Name: whatever you want.
  4. Viewer protocol policy: Redirect HTTP to HTTPS
  5. Alternate domain name (CNAME): www.mydomain.com
  6. Custom SSL certificate: ^ The one for this domain

Create! Wait a bit.

3. Add the CNAME

  1. Goto (or create) your zone in Route 53
  2. Create Record
  3. Record name: www
  4. Record type: A
  5. Alias: YES
  6. Route traffic to: Cloudfront
  7. Choose distribution: The distribution from Step #2, for www.mydomain.com

Visit www.mydomain.com in a browser, see if it works.
Also make sure that http redirects to https
curl -v http://www.mydomain.com should show HTTP/1.1 301 Moved Permanently to Location: https://www.mydomain.com/

Pro-tip: Clear your DNS cache. In Mac OS (at least in May 2023): sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder

4. Create the naked domain redirection S3 Bucket

  1. Create a new bucket. The bucket can have any name, but its easiest if you use mydomain.com
  2. Keep it empty
  3. Enable Static Hosting:
  4. Hosting type: Redirect requests for an object
  5. Protocol: None
  6. You might need to turn off the "Block all public access" safeguards here. Can't remember

5. Create the naked domain http -> https redirection Cloudfront Distribution

  1. Create a new Cloudfront Distribution
  2. Origin Domain: choose the naked-domain bucket from the dropdown. AWS will now notify you that you should "use website endpoint". Do that. Ultimately it should look something like this: mydomain.com.s3.us-west-1.amazonaws.com
  3. Name: Whatever you want. "mydomain.com" is fine
  4. Protocol: HTTP only
  5. Viewer protocol policy: Redirect HTTP to HTTPS
  6. Alternate domain name (CNAME): mydomain.com
  7. Custom SSL certificate: ^ the one for mydomain.com

Create! Wait a bit.

6. Create the apex A record for mydomain.com

  1. Record Name: blank
  2. Record type: A
  3. Alias: YES
  4. Route traffic to: Cloudfront
  5. Choose distribution: The one you made in step 5.

Clear DNS cache: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
Visit mydomain.com in a browser, see if it works.
Check ALL protocols/domains and make sure they end up at HTTPS/WWW:

curl -v http://mydomain.com
curl -v http://www.mydomain.com
curl -v https://mydomain.com

Breath a sight of relief

Deploy script for Github:

.github/workflows/deploy-prod.yml

name: Production Deploy

on:
  push:
    branches:
    - production
  workflow_dispatch:
jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
    - name: Configure AWS Credentials
      uses: aws-actions/configure-aws-credentials@v2
      environment: production
      with:
        audience: ${{ vars.AWS_AUDIENCE }}
        role-to-assume: ${{ vars.AWS_ROLE }}
        aws-region: us-west-1
    - name: Checkout
      uses: actions/checkout@v3
    - name: Copy files to S3 Content bucket
      run: |
        aws s3 sync dist/ s3://${{ vars.AWS_S3_CONTENT_BUCKET }}
    - name: Clear Cloudfront cache
      run: |
        aws cloudfront create-invalidation --distribution-id ${{ vars.AWS_CLOUDFRONT_CONTENT_DISTRIBUTION_ID }} --paths "/*"

To get it to work:

  1. Set up an OIDC connector from Github to AWS. Easier than it sounds. Good instructions here
  2. Create an "environment" in Github called "production"
  3. Set the 4 vars needed. They aren't secrets, the OIDC connector handles keys / roles
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment