Photo by Andy Hermawan on Unsplash
Deploy React (CRA) App to Amazon S3 using Github Actions
Here, I will walk through one of the ways of deploying Create React App to Amazon S3 using GitHub actions.
Create an S3 bucket in AWS
Go to the S3 service in AWS.
Go to Create Bucket page.
Enter the bucket name. (e.g. my-site). Uncheck Block all public access and select the acknowledgment checkbox.
Submit.
Update permissions and properties of the bucket
Now that you have the created S3 bucket in your bucket list, open that bucket and follow the below steps:
Go to Permissions tab of the bucket.
Scroll to Bucket Policy, edit and add following policy there:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::my-site/*"
}
]
}
Note: Replace "my-site" with your actual bucket name.
- After saving the above changes, go to Properties of the bucket and scroll down to "Static website hosting".
Enable Static website hosting.
Add "index.html" in the input of Error document similar to the Index document. It is required because of the SPA (Single Page Application) nature of create-react-app. Otherwise, when we open any URL directly from the address bar, it would lead to a 404 S3 error.
- After saving the above changes, you will find the Bucket website endpoint under "Static website hosting" of S3 properties. That will be our web app's URL.
Create an IAM user for GitHub Actions
Go to AWS IAM. Navigate to Policies from the sidebar and click Create policy.
Select the JSON tab and paste the following code after replacing "my-site" with your S3 bucket name. Make sure bucket name is correctly added at both places.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowS3SyncCommand",
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:Listbucket",
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::my-site",
"arn:aws:s3:::my-site/*"
]
}
]
}
Skip the Tags step and name your policy (e.g. "my-site-github-action").
Once that's created, navigate to User groups from left sidebar and click Create group.
Name it (e.g. "my-site") and select the above-added policy in the Attach permissions policies section.
After creating it, navigate to Users from left sidebar and click Add users.
Enter name (e.g. "my-site-github-actions"). Select Access key - Programmatic access in "Select AWS access type".
Select the user group that is created in the above step. Skip the Tags step, review and create a user.
Make a note of
AWS_ACCESS_KEY_ID
,AWS_SECRET_ACCESS_KEY
andAWS_REGION
.
Setup GitHub Actions
Open your GitHub repository. Go to Settings > Secrets > Actions. Add the above secrets to your GitHub repository.
Create
.github/workflows/deploy.yml
and add the following code.
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: ["main"]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install packages
run: npm install
- name: Build React app
run: npm run build
env:
REACT_APP_API_URL: ${{ secrets.REACT_APP_API_URL }}
# add other env similarly
- 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: ${{ secrets.AWS_REGION }}
- name: Deploy to S3 bucket
run: aws s3 sync ./build/ s3://my-site --delete
Note: Replace bucket name or branch name based on your code. You can also add a bucket name as a secret.
That's it. Once you push the next commit to the main
branch, it will auto-deploy it. You can visit the site with the URL we mentioned above.
Setup Multi-environment deployment (optional)
If you want multiple environments for deployment like staging and production, then you can set the secrets based on different branches and add them in the above workflow file.
However, at the time of writing this, GitHub only provides branch-based environments for Pro or Team accounts. So, in that case, you can do a workaround with a prefix depending on the branch to load environment variables like below:
# .github/workflows/deploy.yml
name: Deploy website
on:
push:
branches: ["staging", "main"]
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set develop env
if: ${{ github.ref == 'refs/heads/staging' }}
run: echo "prefix_env=DEV" >> $GITHUB_ENV
- name: Set main env
if: ${{ github.ref == 'refs/heads/main' }}
run: echo "prefix_env=PROD" >> $GITHUB_ENV
- name: Install packages
run: npm install
- name: Build React app
run: npm run build
env:
REACT_APP_API_URL: ${{ secrets[format('{0}_REACT_APP_API_URL', env.prefix_env)] }}
- 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: ${{ secrets.AWS_REGION }}
- name: Deploy to S3 bucket (Staging)
if: ${{ github.ref == 'refs/heads/staging' }}
run: aws s3 sync ./build/ s3://my-site-staging --delete
- name: Deploy to S3 bucket (Production)
if: ${{ github.ref == 'refs/heads/main' }}
run: aws s3 sync ./build/ s3://my-site-prod --delete
Note: You need to create different S3 buckets with the same process mentioned above for staging and production. While adding environment variables in GitHub secrets, you have to prefix like DEV_REACT_APP_API_URL
and PROD_REACT_APP_API_URL
for all of your environment variables.
Summary
Here, we have seen the process of deploying our static single-page React application to AWS S3. Also, you can create an environment-based deployment with the process we covered in the last section.
Hope this has helped you deploy your application to S3.