AWS Builder Center

Build a CI/CD Pipeline for a Static Website Using GitHub Actions and Amazon S3

Learn how to automatically deploy a static website to Amazon S3 whenever code is pushed to GitHub. This beginner-friendly guide explains CI/CD, GitHub Actions, AWS authentication, S3 deployment, workflow files, and common deployment errors.

CSE Student passionate about Cloud Computing, AWS, and Software Development.

Build a CI/CD Pipeline for a Static Website Using GitHub Actions and Amazon S3

Deploying a website manually every time you make a change can become repetitive.
Imagine making a change to index.html, pushing it to GitHub, and having AWS automatically update your website.
This is where CI/CD comes in.
In this tutorial, we will build a simple CI/CD pipeline using:
  • GitHub
  • GitHub Actions
  • Amazon S3
  • AWS IAM
  • HTML/CSS
The final workflow will look like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Developer
|
| git push
v
GitHub Repository
|
v
GitHub Actions
|
| Authenticate with AWS
v
Amazon S3
|
v
Static Website

1. What is CI/CD?

CI stands for Continuous Integration.
It means that developers frequently push their code to a shared repository and automatically run checks or build processes.
CD stands for Continuous Delivery or Continuous Deployment.
It means that the application can automatically be delivered or deployed after changes are made.
Without CI/CD:
1
2
3
4
5
6
7
8
9
Edit website
↓
Save files
↓
Open AWS Console
↓
Upload files manually
↓
Repeat every time
With CI/CD:
1
2
3
4
5
6
7
8
9
Edit website
↓
git push
↓
GitHub Actions
↓
Automatic deployment
↓
Website updated
This saves time and reduces manual work.

2. What We Are Going to Build

We will create a simple static website.
For example:
1
2
3
4
5
6
7
8
my-website/
│
├── index.html
├── style.css
│
└── .github/
└── workflows/
└── deploy.yml
The website files will be stored in GitHub.
Whenever we push changes to the main branch:
1
git push origin main
GitHub Actions will automatically deploy the latest files to Amazon S3.

3. Prerequisites

Before starting, you need:
  • An AWS account
  • A GitHub account
  • A GitHub repository
  • Basic Git knowledge
  • A simple HTML website
You don't need a complicated application.
A simple HTML page is enough to understand the complete CI/CD process.

4. Create a Simple Website

Create a folder called:
1
my-website
Inside it, create:
1
index.html
Add:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!DOCTYPE html>
<html>
<head>
<title>My AWS Website</title>
<link rel="stylesheet" href="style.css">
</head>

<body>

<h1>Hello from AWS!</h1>

<p>
This website is deployed automatically using
GitHub Actions and Amazon S3.
</p>

</body>
</html>
Now create:
1
style.css
Add:
1
2
3
4
5
6
7
8
9
10
11
12
13
body {
font-family: Arial, sans-serif;
text-align: center;
margin-top: 100px;
}

h1 {
font-size: 40px;
}

p {
font-size: 20px;
}
Your folder should now look like:
1
2
3
4
my-website
│
├── index.html
└── style.css

5. Create a GitHub Repository

Create a new repository on GitHub.
For example:
1
aws-cicd-static-website
Then open your project folder in PowerShell or Git Bash.
Run:
1
git init
This initializes Git in the project.
Add the files:
1
git add .
Create the first commit:
1
git commit -m "Initial website"
Connect the local project to GitHub:
1
git remote add origin YOUR_REPOSITORY_URL
Rename the branch to main:
1
git branch -M main
Push the project:
1
git push -u origin main
Now your website files are available in GitHub.

6. Create an S3 Bucket

Open the Amazon S3 console.
Create a bucket.
For example:
1
my-cicd-static-website
Bucket names must be globally unique, so you may need to add a unique suffix.
For example:
1
my-cicd-static-website-2026
Choose the AWS Region you want to use.
For example:
1
2
Asia Pacific (Mumbai)
ap-south-1
Create the bucket.

7. Why Are We Using S3?

Amazon S3 can store static website files such as:
1
2
3
4
HTML
CSS
JavaScript
Images
Instead of storing website files only on our laptop, we can store them in S3.
Our deployment process will therefore be:
1
2
3
4
5
GitHub
↓
GitHub Actions
↓
S3

8. Create an IAM Policy

GitHub Actions needs permission to upload files to our S3 bucket.
We should not give it unnecessary AWS permissions.
Create an IAM policy that allows the required S3 operations.
A simple example is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME"
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:DeleteObject"
],
"Resource": "arn:aws:s3:::YOUR-BUCKET-NAME/*"
}
]
}
Replace:
1
YOUR-BUCKET-NAME
with your actual bucket name.
For example:
1
my-cicd-static-website-2026

9. Why Should We Avoid Permanent AWS Access Keys?

A common beginner approach is to create an AWS access key and store it in GitHub.
However, long-lived access keys can create security risks if they are accidentally exposed.
A better approach is to use GitHub Actions OIDC with an AWS IAM role.
The basic idea is:
1
2
3
4
5
6
7
8
9
GitHub Actions
|
| OIDC identity
v
AWS IAM
|
| Assume Role
v
Temporary AWS permissions
This means we don't need to store a permanent AWS secret access key in the GitHub repository.

10. Create an IAM Role for GitHub Actions

Create an IAM role that GitHub Actions can assume.
The role should trust GitHub's OIDC identity provider.
The trust relationship should restrict access to your specific repository.
Conceptually, we want:
1
2
3
4
5
Only my GitHub repository
↓
Can assume this role
↓
Can access my S3 bucket
For example, the repository condition can be restricted to:
1
repo:YOUR_USERNAME/YOUR_REPOSITORY:ref:refs/heads/main
This is important because we don't want every GitHub repository to be able to assume our AWS role.
Attach the S3 deployment policy created earlier to this role.

11. Add the AWS Role ARN to GitHub

After creating the IAM role, copy its ARN.
It will look similar to:
1
arn:aws:iam::123456789012:role/GitHubActionsS3DeployRole
In your GitHub repository:
1
2
3
4
5
6
7
Settings
↓
Secrets and variables
↓
Actions
↓
New repository secret
Create:
1
AWS_ROLE_ARN
and add your IAM role ARN as its value.

12. Create the GitHub Actions Workflow

Now comes the most important part.
Inside your project, create:
1
.github
Inside it:
1
workflows
Inside that:
1
deploy.yml
Your project becomes:
1
2
3
4
5
6
7
8
my-website/
│
├── index.html
├── style.css
│
└── .github/
└── workflows/
└── deploy.yml
Add this to deploy.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
name: Deploy Website to S3

on:
push:
branches:
- main

permissions:
id-token: write
contents: read

jobs:
deploy:

runs-on: ubuntu-latest

steps:

- name: Checkout repository
uses: actions/checkout@v4

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-south-1

- name: Deploy website to S3
run: |
aws s3 sync . s3://YOUR-BUCKET-NAME --delete \
--exclude ".git/*" \
--exclude ".github/*"
Replace:
1
YOUR-BUCKET-NAME
with your S3 bucket name.
For example:
1
aws s3 sync . s3://my-cicd-static-website-2026 --delete \

13. Understand the Workflow

Let's understand the important parts.

Workflow name

1
name: Deploy Website to S3
This is the name shown in GitHub Actions.

Trigger

1
2
3
4
on:
push:
branches:
- main
This means:
Run this workflow whenever code is pushed to the main branch.
For example:
1
git push origin main
will trigger the workflow.

Permissions

1
2
3
permissions:
id-token: write
contents: read
GitHub Actions needs permission to obtain an OIDC token and read the repository.

Runner

1
runs-on: ubuntu-latest
GitHub provides a temporary Ubuntu environment to execute the workflow.

Checkout

1
uses: actions/checkout@v4
This downloads the repository files into the GitHub Actions environment.

AWS authentication

1
uses: aws-actions/configure-aws-credentials@v4
This configures temporary AWS credentials using the IAM role.

S3 deployment

1
aws s3 sync . s3://YOUR-BUCKET-NAME --delete
This synchronizes the files from the GitHub Actions environment to S3.
The --delete option removes S3 objects that no longer exist in the repository.
For example:
1
2
3
4
GitHub:

index.html
style.css
S3 also contains:
1
2
3
index.html
style.css
old.html
After synchronization:
1
2
index.html
style.css
The old file can be removed.

14. Push the Workflow

Now commit the workflow:
1
git add .
Then:
1
git commit -m "Add CI/CD deployment workflow"
Push it:
1
git push origin main
Now go to:
1
2
3
GitHub Repository
↓
Actions
You should see:
1
Deploy Website to S3
GitHub will start running the workflow.

15. Watch the Pipeline

A successful pipeline will look conceptually like:
1
2
3
4
5
✓ Checkout repository
↓
✓ Configure AWS credentials
↓
✓ Deploy website to S3
If all steps succeed, the latest website files have been uploaded to S3.

16. Test Automatic Deployment

Now make a change to your website.
For example, change:
1
<h1>Hello from AWS!</h1>
to:
1
<h1>My CI/CD Website</h1>
Save the file.
Then:
1
git add .
1
git commit -m "Update website title"
1
git push origin main
You don't need to manually upload the updated HTML file to S3.
GitHub Actions automatically starts the deployment.
1
2
3
4
5
6
7
8
9
10
11
Code change
↓
Git push
↓
GitHub Actions
↓
AWS authentication
↓
S3 synchronization
↓
Updated website
This is the main benefit of CI/CD.

17. Common Errors

Error 1: AccessDenied

You may see:
1
AccessDenied
This usually means the IAM role does not have the required S3 permissions.
Check:
  • Bucket name
  • IAM policy
  • IAM role
  • Repository trust relationship

Error 2: Role cannot be assumed

If GitHub Actions cannot assume the IAM role, check the IAM trust policy.
Make sure the repository condition matches your actual GitHub repository.
For example:
1
repo:username/repository:ref:refs/heads/main
A small difference in the repository name or branch can cause authentication to fail.

Error 3: Wrong AWS Region

Make sure the region in your workflow matches the region you selected.
For example:
1
aws-region: ap-south-1

Error 4: Wrong S3 Bucket Name

Check the bucket name carefully.
Your workflow should contain the exact bucket name:
1
aws s3 sync . s3://my-cicd-static-website-2026

18. CI/CD Architecture

The complete architecture is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Developer
|
| git push
v
+------------------+
| GitHub Repository |
+------------------+
|
v
+------------------+
| GitHub Actions |
+------------------+
|
| OIDC
v
+------------------+
| AWS IAM |
| Role |
+------------------+
|
| Temporary permissions
v
+------------------+
| Amazon S3 |
+------------------+
|
v
Static Website

19. Why This Project Is Useful

This small project teaches several important cloud and DevOps concepts at the same time.
You learn:
  • Git
  • GitHub
  • GitHub Actions
  • CI/CD
  • IAM
  • IAM roles
  • OIDC authentication
  • Amazon S3
  • AWS CLI
  • YAML
  • Automated deployment
These concepts are useful beyond static websites.
The same CI/CD idea can later be extended to:
1
2
3
4
5
6
7
8
9
10
11
GitHub
↓
Build
↓
Test
↓
Docker Image
↓
Amazon ECR
↓
Amazon ECS
or:
1
2
3
4
5
6
7
GitHub
↓
Build
↓
Test
↓
AWS Lambda

20. Security Best Practices

When building CI/CD pipelines, security is extremely important.

1. Avoid hard-coded credentials

Don't put AWS access keys directly into:
1
2
3
workflow files
source code
GitHub repositories

2. Use IAM roles

Give GitHub Actions only the permissions it needs.

3. Follow least privilege

If the workflow only needs to deploy to one S3 bucket, don't give it administrator access.

4. Restrict the GitHub repository

The IAM trust relationship should identify the repository and branch that are allowed to assume the role.

5. Review GitHub secrets

Never print sensitive credentials in workflow logs.

21. What Happens When We Push Code?

Let's summarize the complete process.
Suppose we change:
1
index.html
Then:
1
2
3
git add .
git commit -m "Update homepage"
git push origin main
GitHub receives the change.
Then:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
GitHub detects push
↓
Workflow starts
↓
Repository is checked out
↓
GitHub obtains OIDC identity
↓
AWS IAM verifies the identity
↓
IAM role is assumed
↓
AWS credentials are configured
↓
Files are synchronized to S3
↓
Website is updated
No manual AWS upload is required.

22. Final Result

We started with a simple static website.
Instead of manually uploading every change, we created an automated deployment pipeline.
The final process is:
1
2
3
4
5
6
7
8
9
10
11
12
13
Write Code
↓
Git Commit
↓
Git Push
↓
GitHub Actions
↓
AWS IAM
↓
Amazon S3
↓
Updated Website
This is a simple but powerful introduction to CI/CD on AWS.

Conclusion

CI/CD is one of the most useful practices in modern software development because it reduces repetitive manual deployment work.
By combining GitHub Actions, AWS IAM, OIDC, and Amazon S3, we can create a secure and automated deployment workflow for a static website.
Once this workflow is understood, the same concepts can be extended to larger applications, Docker containers, serverless applications, and other AWS services.
The important idea is simple:
Push your code, and let the pipeline handle the deployment.
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article