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.
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 Website1. 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 timeWith CI/CD:
1
2
3
4
5
6
7
8
9
Edit website
↓
git push
↓
GitHub Actions
↓
Automatic deployment
↓
Website updatedThis 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.ymlThe website files will be stored in GitHub.
Whenever we push changes to the
main branch:1
git push origin mainGitHub 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-websiteInside it, create:
1
index.htmlAdd:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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.cssAdd:
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.css5. Create a GitHub Repository
Create a new repository on GitHub.
For example:
1
aws-cicd-static-websiteThen open your project folder in PowerShell or Git Bash.
Run:
1
git initThis 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_URLRename the branch to
main:1
git branch -M mainPush the project:
1
git push -u origin mainNow 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-websiteBucket names must be globally unique, so you may need to add a unique suffix.
For example:
1
my-cicd-static-website-2026Choose the AWS Region you want to use.
For example:
1
2
Asia Pacific (Mumbai)
ap-south-1Create the bucket.
7. Why Are We Using S3?
Amazon S3 can store static website files such as:
1
2
3
4
HTML
CSS
JavaScript
ImagesInstead 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
↓
S38. 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-NAMEwith your actual bucket name.
For example:
1
my-cicd-static-website-20269. 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 permissionsThis 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 bucketFor example, the repository condition can be restricted to:
1
repo:YOUR_USERNAME/YOUR_REPOSITORY:ref:refs/heads/mainThis 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/GitHubActionsS3DeployRoleIn your GitHub repository:
1
2
3
4
5
6
7
Settings
↓
Secrets and variables
↓
Actions
↓
New repository secretCreate:
1
AWS_ROLE_ARNand 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
.githubInside it:
1
workflowsInside that:
1
deploy.ymlYour project becomes:
1
2
3
4
5
6
7
8
my-website/
│
├── index.html
├── style.css
│
└── .github/
└── workflows/
└── deploy.ymlAdd 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-NAMEwith 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 S3This is the name shown in GitHub Actions.
Trigger
1
2
3
4
on:
push:
branches:
- mainThis means:
Run this workflow whenever code is pushed to themainbranch.
For example:
1
git push origin mainwill trigger the workflow.
Permissions
1
2
3
permissions:
id-token: write
contents: readGitHub Actions needs permission to obtain an OIDC token and read the repository.
Runner
1
runs-on: ubuntu-latestGitHub provides a temporary Ubuntu environment to execute the workflow.
Checkout
1
uses: actions/checkout@v4This downloads the repository files into the GitHub Actions environment.
AWS authentication
1
uses: aws-actions/configure-aws-credentials@v4This configures temporary AWS credentials using the IAM role.
S3 deployment
1
aws s3 sync . s3://YOUR-BUCKET-NAME --deleteThis 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.cssS3 also contains:
1
2
3
index.html
style.css
old.htmlAfter synchronization:
1
2
index.html
style.cssThe 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 mainNow go to:
1
2
3
GitHub Repository
↓
ActionsYou should see:
1
Deploy Website to S3GitHub 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 S3If 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 mainYou 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 websiteThis is the main benefit of CI/CD.
17. Common Errors
Error 1: AccessDenied
You may see:
1
AccessDeniedThis 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/mainA 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-1Error 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-202618. 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 Website19. 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 ECSor:
1
2
3
4
5
6
7
GitHub
↓
Build
↓
Test
↓
AWS Lambda20. 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 repositories2. 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.htmlThen:
1
2
3
git add .
git commit -m "Update homepage"
git push origin mainGitHub 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 updatedNo 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 WebsiteThis 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.
Enjoyed reading this content? Let the author know!
Your likes, comments, shares, and saves help creators reach more builders.
Loading recommendations
Loading article