Automating Serverless Deployment: S3 Frontend with API Gateway & AWS Lambda

Automating Serverless Deployment: S3 Frontend with API Gateway & AWS Lambda

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! 🚀