In this post, we’ll show how to configure and deploy your Angular SPA application to Amazon S3 with GitHub Actions.
Prerequisites
This is the list of all the prerequisites for following this story:
- Node
- Angular CLI
- An active AWS account
- A GitHub repository
- Git
What is Amazon S3?
Amazon S3 is a simple storage service that helps developers and IT teams to store, backup, archive, and retrieve data from anywhere on the web. It allows administrators to store data in categories, add tags to objects, configure access controls for multiple clients, perform high-volume data analysis, get insights into the storage usage, and measure trends based on activities.
Setting Up S3 bucket in AWS Console
Create s3 bucket
After you log in to the AWS Management Console (https://console.aws.amazon.com/console/home),
Go to Services -> Storage -> S3
Then press **Create bucket** button.


Add Bucket policy
Go to Bucket > Permissions Tab > Bucket policy
Add Bucket policy written in JSON
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::angular-app-github-action/*"
}
]
}
To fix “An error occurred (AccessControlListNotSupported) while calling the PutObject operation: The bucket does not allow ACLs”, we need to enable bucket ACLs
Go to Bucket > Permissions Tab > Object Ownership

Create an IAM User for Github
Go to https://console.aws.amazon.com/iam/. In the navigation pane, choose Users and then select **Add user**.

Press Next: Permissions button -> go to Set permissions for our new user.
Now, choose Attach existing policies directly -> filter policy type s3, then check **AmazonS3FullAccess**. Then click on “Next Review“.

Once you have successfully created the user, download .csv for downloading the credentials. {Access key ID, Secret access key}.
GitHub repository setup
Create a project repository
In your GitHub account, Create a public repository

Add Actions secrets
Click on the menu Settings > Secrets > Actions
Populate keys/values with access key ID and secret access key. ex: for ‘access key ID’ we will name the key AWS_ACCESS_KEY_ID and the values are those obtained from AWS. We will do the same for the secret access key (AWS_SECRET_ACCESS_KEY)

Creating and configuring the Angular application
Now, let’s create the angular project.
- Clone project
git clone https://github.com/anicetkeric/angular-app-github-actions-s3.git
- Create a new workspace and an initial application
ng new angular-app-github-actions-s3
- Serve the application
ng serve --open
The --open (or just -o) option automatically opens your browser to http://localhost:4200/.

Create the .github/workflows/main-deploy.yml file in the project directory
name: deploy aws S3
# Controls when the action will run. Triggers the workflow on push
# events but only for the main branch
on:
push:
branches:
- main
jobs:
deploy-to-s3:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Check out Git repository
uses: actions/checkout@v2
#install node and npm
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: '14.x'
# Allows for re-using node_modules caching, making builds a bit faster.
- name: node_modules caching
uses: actions/cache@v1
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
# Install the node modules
- name: NPM Install
run: npm install
# Run all tests
- name: Run tests
run: |
npm test -- --no-watch --no-progress --browsers=ChromeHeadlessCI
# Create dev build
- name: NPM build Angular
run: npm run build
# Create production build
#- name: Production Build
# run: npm run build --prod
# Deploy to S3
- name: Deploy to S3
uses: jakejarvis/s3-sync-action@v0.5.1
with:
# --acl public read => makes files publicly readable(i.e. makes sure that your bucket settings are also set to public)
# --delete => permanently deletes files in S3 bucket that are not present in latest build
args: --acl public-read --follow-symlinks --delete
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_S3_BUCKET: ${{ secrets.AWS_S3_BUCKET }}
AWS_REGION: ${{ secrets.AWS_REGION }}
SOURCE_DIR: 'dist/angular-app-github-actions-s3/'
- AWS_ACCESS_KEY_ID: AWS Access Key
- AWS_SECRET_ACCESS_KEY: AWS Secret Access Key
- AWS_S3_BUCKET: The name of the bucket we’re syncing to.
- AWS_REGION: The region in which the bucket was created.
Now, push the code to main branch.

As we can see in the image above, all the steps we created have been executed successfully.
Our application is available in the AWS S3 bucket, it can be accessed with the bucket website endpoint.

All done.
The complete source code is available on GitHub.