Static site deployment manually with a shell script, S3, and CloudFront

That was fast too!

How to script testing, compiling, and deploying a static site to AWS S3 and CloudFront from your laptop.

In a previous article we showed you how to automate testing, compiling, and deploying a static site to AWS S3 and CloudFront using CircleCI. What if you don’t like CircleCI? What if you don’t want to depend on a continuous integration service? What if you just want to quickly deploy a static site manually from your laptop?

We’re using harpjs “The static web server with built-in preprocessing” to compile our static site.

Create S3 and CloudFront resources

Create an S3 bucket

Create a CloudFront Distribution

Create an IAM user

Create an IAM user with the appropriate IAM policy access to S3 and CloudFront. We’ll interact with S3 and CloudFront using this IAM user.

Here’s an example IAM policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:List*"
            ],
            "Resource": "arn:aws:s3:::*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": "arn:aws:s3:::example.com"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": "arn:aws:s3:::example.com/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": "arn:aws:s3:::staging.example.com"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": "arn:aws:s3:::staging.example.com/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": "arn:aws:s3:::acceptance.example.com"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:*"
            ],
            "Resource": "arn:aws:s3:::acceptance.example.com/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "cloudfront:CreateInvalidation"
            ],
            "Resource": "*"
        }
    ]
}

Install the AWS Command Line Interface

Run the command pip install awscli to install the aws cli using pip.

Configure the AWS Command Line Interface

Configure the aws cli with the appropriate credentials and configuration options.

Run the command aws configure set preview.cloudfront true to enable the cloudfront preview service.

Run the command aws configure set preview.create-invalidation true to enable the create-invalidation preview service.

Write a script

We’ll write a simple shell script containing all of the commands needed to test, compile, and deploy our static site.

Notes about our example shell script
Here’s an example shell script
#/bin/bash
set -x

# Run this script from the root of your repository

test () {
  npm test
}

prepare () {
  rm -rf www/
  npm run compile
}

sync () {
  if [ ! -d "www" ]; then
    echo 'Exiting because the directory www does not exist.'
    exit
  fi
  aws s3 sync www/. s3://$1 --delete --size-only --cache-control max-age=$2
}

invalidate () {
  aws cloudfront create-invalidation --cli-input-json "{\"DistributionId\":\"$1\",\"InvalidationBatch\":{\"Paths\":{\"Quantity\":1,\"Items\":[\"/*\"]},\"CallerReference\":\"$(date +%s)\"}}"
}

case "$1" in
  "acceptance" | "")
    test
    prepare
    sync acceptance.example.com 0
    ;;

  "staging")
    test
    prepare
    sync staging.example.com 60
    ;;

  "production")
    test
    prepare
    sync example.com 1800
    invalidate ABCDEFGHIJKLMNOP
    ;;

  *)
    echo "Error: Something went wrong."
    echo "Usage: ./script.sh <environment> i.e. ./script.sh acceptance"
    exit 1
    ;;

esac

Troubleshooting

If you have any trouble try to simplify things, for instance, running the individual commands from your laptop. You might run into issues with IAM policies, awscli configuration, or command quoting.

Run the script

Of course you’ll need to customize the example script, write your own script in your favorite language, put it where you want, and execute it how you want. If you use a script like the one above, you’ll just cd into the appropriate directory and run the script ./script.sh acceptance