DEV Community

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

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
Enter fullscreen mode Exit fullscreen mode

Step 2: Install Dependencies

Run the following commands on the instance:

sudo apt update && sudo apt install -y nginx python3 python3-venv python3-pip
Enter fullscreen mode Exit fullscreen mode

Verify that Nginx is installed:

nginx -v
Enter fullscreen mode Exit fullscreen mode

Start and enable Nginx:

sudo systemctl start nginx
sudo systemctl enable nginx
Enter fullscreen mode Exit fullscreen mode

Step 3: Deploy the FastAPI Application

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

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
Enter fullscreen mode Exit fullscreen mode
  1. Start the FastAPI service:
   sudo systemctl daemon-reload
   sudo systemctl enable fastapi
   sudo systemctl start fastapi
   sudo systemctl status fastapi
Enter fullscreen mode Exit fullscreen mode

Step 4: Configure Nginx as a Reverse Proxy

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

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;
       }
   }
Enter fullscreen mode Exit fullscreen mode
  1. Enable the configuration:
   sudo ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/
   sudo nginx -t
   sudo systemctl restart nginx
Enter fullscreen mode Exit fullscreen mode

Test if Nginx is serving the FastAPI app:

curl http://localhost
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Step 6: Adding Secrets to GitHub

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

  • SERVER_IP: Your EC2 instance IP
  • SSH_PRIVATE_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
Enter fullscreen mode Exit fullscreen mode
  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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Top comments (2)

Collapse
 
kenryikegbo profile image
Ikegbo Ogochukwu

boyyyy, this is comprehensive and clear

Collapse
 
glenzzy profile image
Efuetlancha Glenn Tanze Fonche • Edited

Thank you, I'm glad it could help 😊
You can help others with it