How To Use GitHub Actions To Deploy an 11ty Website To S3
11 February 2021
I use 11ty to generate a static website and S3 to host it. This post describes how I set up a workflow in GitHub Actions to build and deploy the website. The workflow uses the AWS - CLI S3 - sync command to transfer the files.
This post describes how to:
- create an AWS policy with only those permission needed by the
sync
command - create an AWS individual IAM user with the above policy
- create a GitHub Action workflow using the
sync
command to upload the files
I will provide the policy and workflow files first for those wanting only the code. A detailed walkthrough is provided below these files. This post assumes you already have set up an S3 bucket. If not, please see the Hosting a static website using Amazon S3 guide.
s3_sync_policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject",
"s3:GetBucketLocation"
],
"Resource": [
"arn:aws:s3:::your-bucket-name",
"arn:aws:s3:::your-bucket-name/*"
]
}
]
}
github_build_and_deploy_workflow.yml
name: Build and Deploy to S3
on: [push]
jobs:
build_and_deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/[email protected]
# Uncomment if you want to specify a certain
# Node version. Otherwise the Node version installed
# on the GitHub VM will be used. For more details
# see: https://github.com/actions/virtual-environments
# - name: Setup Node.js environment
# uses: actions/[email protected]
# with:
# node-version: '15.7.0'
# Uncomment if your project uses dependencies
# - name: Install dependencies
# run: npm ci
- name: Build the website
run: npx @11ty/eleventy
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2 # replace this with your aws-region
- name: Upload files to S3 with AWS CLI
run: |
aws s3 sync _site/ s3://${{ secrets.S3_BUCKET }} --delete
Walk-through
There are many menus to navigate to set this up. I’ve created a video walk through to help explain where everything is. If you want just the text write up then please skip to the AWS Setup section below.
AWS Setup
Using an individual IAM account with limited permissions is a best practice. Creating a new user, rather than using an existing one, means the credentials are not shared across services. If the credentials change then GitHub alone will be affected. Plus, we can restrict the user to only those permissions needed by the workflow. In this case, the account will only have permissions for the actions needed by the sync
command. For more details on credential best practices, see the configure-aws-credentials documentation.
Create a policy
The first step is to create a policy that will only contain the permissions needed by the sync
command. This policy will be used during the account creation step.
To create the policy:
- Sign in to the IAM Console.
- Goto Access Management -> Policies -> Create Policy.
- Click the JSON tab and paste in the JSON policy from above.
- Click the ‘Review’ Policy button.
- Next, name the policy. I used S3-Sync-Policy.
- Click the ‘Create Policy’ button.
This policy does the following:
- Allows the following actions:
s3:PutObject
- “Grants permission to add an object to a bucket”
s3:GetObject
- “Grants permission to retrieve objects from Amazon S3”
s3:ListBucket
- “Grants permission to list some or all of the objects in an Amazon S3 bucket”
s3:DeleteObject
- “Grants permission to remove the null version of an object and insert a delete marker, which becomes the current version of the object”
s3:GetBucketLocation
- Grants permission to return the Region that an Amazon S3 bucket resides in”
- Specifies the resources the actions can be applied to. Ensure you change the
your-bucket-name
value.arn:aws:s3:::your-bucket-name
- Applied to the bucket:
your-bucket-name
- Applied to the bucket:
arn:aws:s3:::your-bucket-name/*
- Applied to all objects in
your-bucket-name
- Applied to all objects in
You can also create the policy using the Visual Editor rather than pasting in the JSON code. Note: You do not need to do both. The Visual Editor is a second way to create the policy. The video demonstrates using the Visual Editor.
Create a user
The next step is to create a user and apply the policy to it.
To create a user:
- Goto Access Management -> Users -> Add user
- On the first screen:
- Enter a name in the “User Name” field. I chose github-actions.
- Select “Programmatic access” in the “Access Type” section. This user does not need “AWS Management Console access”.
- Click the “Next: Permissions” button.
- On the second screen:
- Click on the “Attach existing policies directly” box in the “Set permissions” section.
- Use the search feature to find the policy created in the previous section. Select it.
- Click the “Next: Tags” button.
- On the third screen:
- Optionally add a tag (or more) for the user.
- Click the “Next: Review” button.
- On the fourth screen:
- Review the user settings.
- Click the “Create User” button.
- On the fifth screen:
- This screen displays the user’s AWS credentials. These will be used with the GitHub repo. WARNING: This is the only time the credentials will be available to download. Either keep this screen open while setting up GitHub, OR click the Download button.
GitHub Setup
Setup AWS Credentials
The GitHub action will need the AWS credentials in order to work. Add the credentials to your repo by doing the following:
- Go to your repo
- Click Settings -> Secrets -> New Repository Secret
- Using the credentials created in the previous section, add keys for:
AWS_ACCESS_KEY_ID
AWS_SECRET_ACCESS_KEY
- Also, add an
S3_BUCKET
key with the name of your S3 bucket.
Create a GitHub Workflow
Now to create a workflow that will build the website and upload it to S3. The workflow will do the following:
- Use the configure-aws-credentials to access the AWS access and secret keys
- Build the website using 11ty
- Use the AWS-CLI to upload the generated site to the S3 bucket
To create the workflow:
- In your repo click the Actions link.
- Click on the “Skip this and set up a workflow yourself” link.
- Remove the template code and replace it with the yml file from above.
- Change the
aws-region
location to your bucket’s region. - Optionally, rename the file.
- Click the “Start Commit” button.
Below is a description of what each line does:
name: Build and Deploy to S3
- The name of this workflow. It will show under the Actions tab in your repository. Name the workflow whatever you like.
on: [push]
- This is the event that will trigger this workflow. In this example, it will run on any push to the repository. See Events that trigger workflows for other options.
jobs:
- Groups together the jobs that run in this workflow (Build and Deploy to S3).
build_and_deploy:
- The name of the job. This name can be whatever you would like it to be.
runs-on: ubuntu-latest
- In this example, the workflow will run in an ubuntu virtual environment using the latest version supported by GitHub. See Specifications for GitHub-hosted runners for other options.
steps:
- Groups together all the steps that run during the build_and_deploy job.
- name: Checkout repository`
uses: actions/[email protected]
- This block of code is one step. The
name
is optional. If provided it will be displayed in the output when the workflow runs. Theuses
keyword retrieves the action to run in this step. An action is a reusable piece of code. In this case, the step uses the public action actions/[email protected] to checkout your repository. See the Checkout documentation for more details.
- name: Build the website
run: npx @11ty/eleventy
- This step uses the
run
keyword to execute a command-line program using the OS’s default shell. In this case,npx
is used to generate the 11ty website.
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: us-west-2 # replace this with your aws-region
- This step uses the public
configure-aws-credentials
action to set up the credentials for the workflow. Thewith
keyword is a map of input parameters to the action. Here, the repo’s AWS secret keys are passed to the action. See “Configure AWS Credentials” Action For GitHub Actions for more details on this Action.
- name: Upload files to S3 with AWS CLI
run: |
aws s3 sync _site/ s3://${{ secrets.S3_BUCKET }} --delete
- This step uses the AWS CLI to transfer the files generated by the “Build the website” step to the S3 bucket. The AWS CLI is installed by default on the virtual machine. See the GitHub Actions Virtual Environments for more details on pre-installed tools.
- The S3 sync command recursively copies files from the
_site
directory to the S3 bucket. The--delete
option deletes any files in the S3 bucket that are not in the_site
directory.
Run the workflow
The workflow will run when a commit is pushed to the repo. You can see the output of a run by going to the ‘Actions’ menu for the repo. Here is an example of the output of the workflow.
Thank you for reading! I hope you found this useful!