Deploying a FastAPI Application on AWS EC2 with Nginx and CI/CD

Introduction Deploying a FastAPI application with Nginx on AWS EC2 can be challenging for beginners. This guide will walk you through setting up an EC2 instance, installing necessary dependencies, configuring Nginx as a reverse proxy, and setting up a CI/CD pipeline with GitHub Actions. Prerequisites Before you begin, ensure you have the following: An AWS account (Create one here) A GitHub repository with your FastAPI application Basic knowledge of Linux and SSH Step 1: Launch an AWS EC2 Instance Log in to the AWS Console. Navigate to EC2 Dashboard. Click Launch Instance. Choose an Ubuntu 22.04 AMI. Select an instance type (e.g., t2.micro for free-tier users). Configure security groups to allow ports 22 (SSH), 80 (HTTP), and 8000 (FastAPI). Download and save the .pem key securely. Launch the instance and connect via SSH: ssh -i your-key.pem ubuntu@your-instance-ip Step 2: Install Dependencies Run the following commands on the instance: sudo apt update && sudo apt install -y nginx python3 python3-venv python3-pip Verify that Nginx is installed: nginx -v Start and enable Nginx: sudo systemctl start nginx sudo systemctl enable nginx Step 3: Deploy the FastAPI Application Clone your repository: git clone https://github.com/your-repo.git fastapi-app cd fastapi-app Set up a virtual environment and install dependencies: python3 -m venv venv source venv/bin/activate pip install -r requirements.txt Create a systemd service file for FastAPI: sudo nano /etc/systemd/system/fastapi.service Add the following content: [Unit] Description=FastAPI application After=network.target [Service] User=ubuntu WorkingDirectory=/home/ubuntu/fastapi-app ExecStart=/home/ubuntu/fastapi-app/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 Restart=always [Install] WantedBy=multi-user.target Start the FastAPI service: sudo systemctl daemon-reload sudo systemctl enable fastapi sudo systemctl start fastapi sudo systemctl status fastapi Step 4: Configure Nginx as a Reverse Proxy Create a new Nginx configuration file: sudo nano /etc/nginx/sites-available/fastapi Add the following configuration: server { listen 80; server_name your-domain-or-ip; location / { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } Enable the configuration: sudo ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl restart nginx Test if Nginx is serving the FastAPI app: curl http://localhost Step 5: Set Up CI/CD with GitHub Actions Create .github/workflows/ci.yml for Continuous Integration: name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v3 with: python-version: '3.10' - name: Install dependencies run: | python -m venv venv source venv/bin/activate pip install -r requirements.txt - name: Run Tests run: | source venv/bin/activate pytest Create .github/workflows/cd.yml for Continuous Deployment: name: CD on: push: branches: - main jobs: deploy: runs-on: ubuntu-latest steps: - name: Deploy via SSH uses: appleboy/ssh-action@master with: host: ${{ secrets.SERVER_IP }} username: ubuntu key: ${{ secrets.SSH_PRIVATE_KEY }} script: | cd /home/ubuntu/fastapi-app git pull origin main source venv/bin/activate pip install -r requirements.txt sudo systemctl restart fastapi sudo systemctl restart nginx Step 6: Adding Secrets to GitHub Go to your repository settings on GitHub and add the following secrets under Settings -> Secrets and Variables -> Actions: EC2_HOST: Your EC2 instance IP EC2_SSH_KEY: Your private SSH key (from .pem file) Step 7: Test Your CI/CD Pipeline Push changes to GitHub: git add . git commit -m "Set up CI/CD" git push origin main Go to GitHub Actions to verify CI/CD runs successfully. SSH into your instance and check if the application is running: sudo systemctl status fastapi sudo systemctl status nginx Step 8: Fix the Missing book_id Endpoint @router.get("/{book_id}", response_model=Book, status_code=status.HTTP_200_OK) # New endpoint async def get_book(book_id: int): book = db.books.get(book_id) if not

Feb 12, 2025 - 17:12
 0
Deploying a FastAPI Application on AWS EC2 with Nginx and CI/CD

Introduction

Deploying a FastAPI application with Nginx on AWS EC2 can be challenging for beginners. This guide will walk you through setting up an EC2 instance, installing necessary dependencies, configuring Nginx as a reverse proxy, and setting up a CI/CD pipeline with GitHub Actions.

Prerequisites

Before you begin, ensure you have the following:

  • An AWS account (Create one here)
  • A GitHub repository with your FastAPI application
  • Basic knowledge of Linux and SSH

Step 1: Launch an AWS EC2 Instance

  1. Log in to the AWS Console.
  2. Navigate to EC2 Dashboard.
  3. Click Launch Instance.
  4. Choose an Ubuntu 22.04 AMI.
  5. Select an instance type (e.g., t2.micro for free-tier users).
  6. Configure security groups to allow ports 22 (SSH), 80 (HTTP), and 8000 (FastAPI).
  7. Download and save the .pem key securely.
  8. Launch the instance and connect via SSH:
   ssh -i your-key.pem ubuntu@your-instance-ip

Step 2: Install Dependencies

Run the following commands on the instance:

sudo apt update && sudo apt install -y nginx python3 python3-venv python3-pip

Verify that Nginx is installed:

nginx -v

Start and enable Nginx:

sudo systemctl start nginx
sudo systemctl enable nginx

Step 3: Deploy the FastAPI Application

  1. Clone your repository:
   git clone https://github.com/your-repo.git fastapi-app
   cd fastapi-app
  1. Set up a virtual environment and install dependencies:
   python3 -m venv venv
   source venv/bin/activate
   pip install -r requirements.txt
  1. Create a systemd service file for FastAPI:
   sudo nano /etc/systemd/system/fastapi.service

Add the following content:

   [Unit]
   Description=FastAPI application
   After=network.target

   [Service]
   User=ubuntu
   WorkingDirectory=/home/ubuntu/fastapi-app
   ExecStart=/home/ubuntu/fastapi-app/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000
   Restart=always

   [Install]
   WantedBy=multi-user.target
  1. Start the FastAPI service:
   sudo systemctl daemon-reload
   sudo systemctl enable fastapi
   sudo systemctl start fastapi
   sudo systemctl status fastapi

Step 4: Configure Nginx as a Reverse Proxy

  1. Create a new Nginx configuration file:
   sudo nano /etc/nginx/sites-available/fastapi

Add the following configuration:

   server {
       listen 80;
       server_name your-domain-or-ip;

       location / {
           proxy_pass http://127.0.0.1:8000;
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       }
   }
  1. Enable the configuration:
   sudo ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/
   sudo nginx -t
   sudo systemctl restart nginx

Test if Nginx is serving the FastAPI app:

curl http://localhost

Step 5: Set Up CI/CD with GitHub Actions

Create .github/workflows/ci.yml for Continuous Integration:

name: CI
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set up Python
        uses: actions/setup-python@v3
        with:
          python-version: '3.10'
      - name: Install dependencies
        run: |
          python -m venv venv
          source venv/bin/activate
          pip install -r requirements.txt
      - name: Run Tests
        run: |
          source venv/bin/activate
          pytest

Create .github/workflows/cd.yml for Continuous Deployment:

name: CD
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy via SSH
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SERVER_IP }}
          username: ubuntu
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: |
            cd /home/ubuntu/fastapi-app
            git pull origin main
            source venv/bin/activate
            pip install -r requirements.txt
            sudo systemctl restart fastapi
            sudo systemctl restart nginx

Step 6: Adding Secrets to GitHub

Go to your repository settings on GitHub and add the following secrets under Settings -> Secrets and Variables -> Actions:

  • EC2_HOST: Your EC2 instance IP
  • EC2_SSH_KEY: Your private SSH key (from .pem file)

Step 7: Test Your CI/CD Pipeline

  1. Push changes to GitHub:
   git add .
   git commit -m "Set up CI/CD"
   git push origin main
  1. Go to GitHub Actions to verify CI/CD runs successfully.
  2. SSH into your instance and check if the application is running:
   sudo systemctl status fastapi
   sudo systemctl status nginx

Image description

Step 8: Fix the Missing book_id Endpoint

@router.get("/{book_id}", response_model=Book, status_code=status.HTTP_200_OK)  # New endpoint
async def get_book(book_id: int):
    book = db.books.get(book_id)
    if not book:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, 
            detail="Book not found"
        )
    return book

Image description

Drawing a Lesson from This Project: Object-Oriented Programming (OOP) Concepts in Action

Throughout this project, we followed a structured and modular approach, which mirrors key principles of Object-Oriented Programming (OOP) in software development. Here’s how:

  1. Encapsulation – Just like OOP encourages bundling data and behavior together in objects, we kept different parts of the system isolated and well-structured. The FastAPI service, Nginx configuration, CI/CD pipelines, and AWS deployment were all handled separately but worked together cohesively.

  2. Abstraction – The CI/CD pipelines abstract away the complexity of deployment. Developers don’t need to manually set up servers every time they push changes. Instead, GitHub Actions automates the process, similar to how OOP hides internal logic behind methods and interfaces.

  3. Modularity and Reusability – Our project followed a modular approach:

    • The API routes were defined separately.
    • The Nginx configuration was structured in a reusable way.
    • CI/CD workflows were reusable across different environments. This reflects OOP’s emphasis on writing reusable and maintainable code.
  4. Inheritance and Scalability – OOP allows new classes to extend existing ones without modifying them. Similarly, this deployment can be extended—new features, new API endpoints, or even another service (like a database) can be integrated without breaking the existing setup.

Conclusion

This project teaches an important software engineering lesson: structured, modular, and automated approaches lead to scalable and maintainable systems. Just as OOP helps manage complexity in code, well-structured CI/CD pipelines, infrastructure automation, and API design help manage complexity in real-world applications.

And

You have successfully deployed your FastAPI application on AWS EC2 with Nginx and automated deployment using GitHub Actions. Now, every push to the main branch will trigger an automated deployment!