Automate Deployment to S3 with GitHub Actions

This is the last part of the series.

So far we have set up Angular Universal with prerender and we have a S3 bucket ready to host our prerendered content.

Now let's set up the GitHub Actions so that every time we push to the GitHub repository it will prerender it and copy it to AWS S3.

To get started with GH Actions all you need is to create a .yml file in your projects directory in a specific location.

👉 .github/workflows/deploy.yml

With our GH Action we want to achieve that everytime we make a push to the main branch it will build the web page and copy it to the AWS S3 bucket.

There are several things we want the action to do:

  1. Run the micro backend in the background on the Github Action server
  2. Run the Angular Universal prerender
  3. Copy the files to the AWS S3 bucket

As a prerequisite we will need an AWS user and an appropriate Policy that has permissions to update the bucket where we want our website to be hosted.

First create a Policy with the following content:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:ListBucket",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::angular-prerender-markdown",
                "arn:aws:s3:::angular-prerender-markdown/*"
            ]
        }
    ]
}

Then create a user with the Programatic access type, and attach the newly created policy to that user.

Go to the Github Repository and add the following as Secrets:

  • AWS_S3_BUCKET - the name of the bucket
  • AWS_ACCESS_KEY_ID - the key that you received for that newly created user
  • AWS_SECRET_ACCESS_KEY - the access key that you received for the new created user
  • AWS_S3_BUCKET_REGION - the region of the bucket

To access the GH Secrets go to the repository > settings > secrets. There you can input the secrets and use it in your GH Actions.

Remember that you never want to commit sensitive info like credentials. That's what GH Secrets are for.

After the secrets are set in the GH repositories secrets, add the following content to the .github/workflows/deploy.yml.

name: Deploy website

on:
  push:
    branches:
    - main

jobs:

  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '14'

      - name: Cache npm dependencies
        id: cache-npm-deps
        uses: actions/cache@v2
        with:
          path: './node_modules'
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}

      - name: Install npm deps
        if: steps.cache-npm-deps.outputs.cache-hit != 'true'
        run: npm ci

      - name: Build backend
        run: npm run backend:build

      - name: Start backend
        run: npm run backend:start &

      - name: Prerender
        run: npm run prerender

      - name: Archive build artifacts
        uses: actions/upload-artifact@v2
        with:
          name: dist-angular-prerender-markdown
          path: |
            dist/angular-prerender-markdown/browser

  deploy:
    runs-on: ubuntu-latest
    needs: ['build']
    steps:
    - name: Download build artifact
      uses: actions/download-artifact@v2
      with:
        name: dist-angular-prerender-markdown

    - uses: jakejarvis/s3-sync-action@master
      with:
        args: --delete
      env:
        AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
        AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
        AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
        AWS_REGION: ${{ secrets.AWS_S3_BUCKET_REGION }}
        SOURCE_DIR: '.'

Now every time you push to your main branch, this action will do the deployment automatically.

As the last step this created a simple way to re-deploy the website. From this point on it's simple to add new content, modify existing one, change styles, and commit.

Please let me know if this series was helpful. Or if there are some things that are unclear, or you get stuck with.

You can join my Discord server and post a message there, I will try to respond ASAP.