Introduction
In today's fast-paced development environment, automating your deployment process is no longer a luxury—it's a necessity. Continuous Integration and Continuous Deployment (CI/CD) has become the industry standard for delivering software efficiently and reliably. In this blog post, I'll walk you through setting up a complete CI/CD pipeline using GitHub Actions to automatically deploy a static website to Amazon S3.
Why CI/CD Matters
Before diving into the technical details, let's understand why CI/CD is so important:
- Faster Delivery: Automate repetitive tasks to release features more quickly
- Higher Quality: Catch bugs early through automated testing
- Reduced Risk: Small, incremental changes are easier to troubleshoot
- Consistency: Every deployment follows the same process
- Developer Focus: Less time on operations means more time for coding
For static websites specifically, a CI/CD pipeline ensures that every change you push to your repository is automatically tested and deployed, eliminating manual FTP uploads or console interactions.
The Architecture
Our CI/CD pipeline follows this simple flow:
- Developer pushes code to GitHub repository
- GitHub Actions detects the change and triggers a workflow
- The workflow builds and tests the website
- If successful, the workflow deploys the site to AWS S3
- The website is immediately available to visitors
This architecture provides several benefits:
- Scalability: S3 can handle virtually unlimited traffic
- Cost-Effective: Pay only for what you use
- Reliable: AWS's infrastructure ensures high availability
- Secure: Access controls and encryption protect your content
Source Git Link: https://github.com/ravindrasinghh/github-actions-s3-workshop/tree/master
Prerequisites
To follow along with this tutorial, you'll need:
- A GitHub account
- An AWS account
- Basic understanding of HTML, CSS, and JavaScript
- Familiarity with Git commands
Step 1: Setting Up Your S3 Bucket
First, we need to create an S3 bucket configured for static website hosting:
- Log in to the AWS Management Console and navigate to S3
- Click "Create bucket"
- Enter a globally unique name for your bucket
- Choose your preferred region
- Uncheck "Block all public access" (since this is a public website)
- Enable "Static website hosting" under the Properties tab
- Set "index.html" as both the index and error document
- Add a bucket policy to allow public read access:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::your-bucket-name/*"
}
]
}
Step 2: Creating IAM Credentials
For GitHub Actions to access your S3 bucket, you'll need IAM credentials:
- Navigate to IAM in the AWS Console
- Create a new policy with the following permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::your-bucket-name",
"arn:aws:s3:::your-bucket-name/*"
]
}
]
}
- Create a new IAM user with programmatic access
- Attach the policy you just created
- Save the Access Key ID and Secret Access Key securely
Step 3: Setting Up Your GitHub Repository
- Create a new repository or use an existing one
- Add your static website files to the repository
- Navigate to Settings > Secrets and variables > Actions
- Add the following secrets:
-
AWS_ACCESS_KEY_ID
: Your IAM user's access key -
AWS_SECRET_ACCESS_KEY
: Your IAM user's secret key -
S3_BUCKET_NAME
: Your S3 bucket name
-
Step 4: Creating the GitHub Actions Workflow
The heart of our CI/CD pipeline is the GitHub Actions workflow file. Create a new file at .github/workflows/deploy-to-s3.yml
with the following content:
name: Deploy Static Website to S3
on:
push:
branches: [ main ]
workflow_dispatch: # Allows manual triggering
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
# No build step needed for this simple static website
# Just update the deployment timestamp in the JavaScript file
- name: Update deployment timestamp
run: |
echo "// Updating timestamp for deployment on $(date)" >> js/script.js
echo "// Deployment ID: ${{ github.run_id }}" >> js/script.js
# Configure AWS credentials
- 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: "ap-south-1"
# Deploy to S3 bucket - directly sync the repository contents
- name: Deploy to S3
run: |
aws s3 sync ./ s3://${{ secrets.S3_BUCKET_NAME }}/ \
--delete \
--exclude ".git/*" \
--exclude ".github/*" \
--exclude "README.md"
Let's break down what this workflow does:
- Triggers: The workflow runs whenever code is pushed to the main branch or when manually triggered
- Checkout: Fetches the latest code from your repository
- Timestamp: Adds a deployment timestamp to your JavaScript file
- AWS Credentials: Configures AWS credentials using your GitHub secrets
- Deployment: Syncs your website files to the S3 bucket, excluding unnecessary files
- Confirmation: Outputs the URL where your website can be accessed
Step 5: Testing the Pipeline
Now it's time to see your CI/CD pipeline in action:
- Commit and push your changes to the main branch
- Go to the "Actions" tab in your GitHub repository
- Watch as your workflow runs automatically
- Once completed, click on the workflow run to see the details
- Visit your website URL to confirm the deployment was successful
Understanding the Workflow
Let's dive deeper into some key aspects of our GitHub Actions workflow:
The Trigger
on:
push:
branches: [ main ]
workflow_dispatch:
This section defines when the workflow should run. In our case, it runs on pushes to the main branch and can also be triggered manually using the "workflow_dispatch" event.
AWS Credentials
- 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: 'us-east-1'
This step uses the official AWS GitHub Action to configure credentials. The credentials are stored securely as GitHub secrets and are never exposed in logs.
S3 Sync
- name: Deploy to S3
run: |
aws s3 sync ./ s3://${{ secrets.S3_BUCKET_NAME }}/ \
--delete \
--exclude ".git/*" \
--exclude ".github/*" \
--exclude "README.md" \
--exclude "*.md" \
--exclude ".vscode/*"
The aws s3 sync
command efficiently uploads only the files that have changed. The --delete
flag removes files from the bucket that don't exist in your repository, ensuring your website is always in sync with your code.
Common Issues and Troubleshooting
Here are some common issues you might encounter and how to fix them:
Access Denied Errors
If you see "Access Denied" errors in your workflow:
- Double-check your IAM permissions
- Verify that your bucket policy allows the necessary actions
- Ensure your GitHub secrets are correctly set
Files Not Updating
If your website isn't reflecting the latest changes:
- Check that you're pushing to the correct branch
- Look for errors in the GitHub Actions logs
- Try clearing your browser cache
Workflow Not Triggering
If your workflow isn't running:
- Verify that the workflow file is in the correct location (
.github/workflows/
) - Check that the trigger conditions match your push event
- Ensure the workflow file has valid YAML syntax
Conclusion
Setting up a CI/CD pipeline with GitHub Actions and AWS S3 is a powerful way to streamline your website deployment process. By automating these tasks, you can focus on what matters most—building great websites.
I hope this guide helps you implement your own automated deployment pipeline. Happy coding!
Solid article!