Let’s walk through a full cloud deployment for a 2-tier architecture for a serverless web application using AWS S3, CloudFront, API Gateway, and Lambda. This architecture allows you to host static frontend content and a dynamic, serverless backend logic, offering scalability, cost efficiency, and ease of deployment.
Overview of the Architecture
The architecture we’re going to build involves the following components:
✅ S3: Hosts static frontend files (HTML, CSS, JavaScript).
✅ CloudFront: Distributes the static files to users globally and provides caching for faster access.
✅ API Gateway: Routes HTTP requests from the frontend to backend services.
✅ Lambda: Hosts the serverless backend logic (e.g., processing data, querying a database, etc.)
Prerequisites
The following knowledge will be necessary to understand and flow with this project
✳️ Knowledge of Cloud Services
✳️ Good Knowledge of Git and Bash
✳️ Basic Knowledge of Python and Fastapi
1. Host the Frontend
This static site will be hosted on S3 bucket using Cloudfront
1. 1 Create an S3 Bucket
Start by creating an S3 bucket to store your static frontend files:
✅ Log in to the AWS Management Console and go to S3. Click Create Bucket choose a unique name for the bucket and select a region.
✅ Block all public access, allowing the public to access your files and create the bucket ( leave other settings as seen.
✅ Upload your files into the S3 bucket. this project will only host one file - index.html
.In the S3 bucket, click Upload. Select your frontend files (e.g., index.html) then Click Upload.
1.2 Connect S3 to CloudFront
✅ Go to AWS CloudFront
✅Create Distribution.
✅ Origin Domain Name → Enter your S3 bucket Endpoint.
✅Viewer Protocol Policy → Redirect HTTP to HTTPS.
✅ Web Application Firewall (WAF) - Don’t enable
✅ Create the distribution.
✅ Update Origin Access. Click on the Edit button for that origin. In the Origin Settings, you will see an option to use Legacy access identities. Select your bucket and check the “Yes, update bucket” or Copy the policy and update S3 policy
✅ If you selected - “No, I will update the Bucket”, Now go to your S3 Bucket and Update the Bucket Policy. Navigate to properties > Bucket policy. Edit the policy and paste the provided policy copied from Cloudfront Origin Access and Save.
✅ Go to Cloud invalidation, and create invalidation for path /* to clear cache. Allow deployment to complete, then proceed to view your CloudFront endpoint
2. Host the Application's Backend
Now, let’s dive into setting up the serverless backend. The Backend is an HTTP API, which will sit in Lamda and we’ll use API Gateway to expose HTTP endpoints and Lambda to process the business logic.
This will also include the git actions for auto-deployment
2.1. Create a Lambda Function In the AWS Console:
✅ In the AWS Console, Go to Lambda and click Create function.
✅ Choose an Author from scratch.
✅ Name your function and select a runtime (Python).
2.2 Set Up the Environment Locally and Test
✅ Create your GitHub repository, and clone the repository to your PC using the command below
git clone "your github repo url.git"
✅ Now, proceed with creating our API, your cloned repository will be empty or with just one file readme.md, create or import main.py in your root direct or within a folder called - backend. We won’t elaborate on creating an API, since this article is centered on Serverless deployment. For sample API visit the project repository for the project files
✅ Test the API logic locally and ensure it the app works
python -m venv venv # create venv
.\venv\Scripts\activate # activate it
pip install -r requirements.txt # install requirement
pip unfreeze > requirements.txt # create requirements file
uvicorn backend.main:app --reload # start the server
✅Test Locally and ensure your app runs and you can access all three endpoints
✳️ /test
✳️ /api/funfact
(accepts ?number=<anynumber>)
✳️ api/classify-number
(accepts ?number=<anynumber>)
2.3 Automate Deployment to Lamda with GitHub Actions
This is seamless when automated so that subsequent changes to the repository will be pushed to Git Hub. We will achieve this by creating a Deployment file for Git Actions.
✅ On the newly created GitHub repository, navigate to → Settings → Secrets and Variables, Create a repository secret.
name: AWS_ACCESS_KEY_ID | Value: (gotten from AWS IAM User AccessKey)
name: AWS_SECRET_ACCESS_KEY | Value: (gotten from AWS IAM User AccessKey)
✅ create git actions for deployment to Lamda, create main.yml
file in .github/workflows
(manually create this folder at the root of your repo. Add the deployment file
name: Deploy FastAPI to AWS Lambda
on:
push:
branches:
- master # Runs when pushing to the main branch
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.12"
- name: Install AWS CLI
run: |
if ! command -v aws &> /dev/null; then
echo "AWS CLI not found. Installing..."
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip awscliv2.zip
sudo ./aws/install
else
echo "AWS CLI found. Updating..."
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
unzip -o awscliv2.zip
sudo ./aws/install --update
fi
- name: Install dependencies
run: |
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
pip install fastapi==0.99.0 mangum requests
deactivate
- name: Package and Zip for Deployment
run: |
mkdir package
cp -r backend/main.py package/ # Copy your main.py file
cp -r venv/lib/python*/site-packages/* package/ # Copy dependencies
cd package && zip -r ../deployment.zip . # Create zip file
- name: Deploy to AWS Lambda
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: "us-east-1"
run: |
aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
aws configure set region $AWS_DEFAULT_REGION
aws lambda update-function-code \
--function-name thenumbergame \ #ensure to use your lamda function name
--zip-file fileb://deployment.zip \
--region us-east-1
✅ Commit and push your files to Git Hub. On your Github repo —> action and confirm the workflow was triggered and completed without errors
✅ Also confirm from AWS Console that Lamda is Updated as well
✅ Now, Edit Lamda handler - main.handler, Scroll to Runtime Setting and Edit.
✅ Also, Edit the memory for better efficiency
2.4. Create an API Gateway
Now let's proceed to connect the backend logic to an API Gateway
✅ In the AWS Console, navigate to API Gateway.
✅ Click Create API and select HTTP API. Provide a name and add integration ( in this case - your lambda function)
✅ Define the resource path (e.g., /api/classify-number). you can add all routes available on your API
✅ Enable CORS and Deploy
✅ On successful deployment, get your invoke URL and append the route and view on the browser.
2.5 Final Touches:
We have come this long :) You deserve an accolade. Update your frontend index.html with the correct backend API link to accept requests from your backend Logic. Remember to create invalidation on Cloudfront to clear cache and fetch the recent S3 file.
Now view your cloudfront link, If you can see this page now, YOU MADE IT! 🙂
Got stuck at some point? 🥵 No worries, I’d be happy to help! Connect with me on LinkedIn.
You can find all the project files here. Feel free to share your thoughts in the comments! 🚀