Skip to main content

FastAPI Azure Deployment

Introduction

Deploying your FastAPI application to a cloud provider like Microsoft Azure allows you to make your API available to users worldwide with high reliability and scalability. Azure offers multiple services for hosting web applications, and in this guide, we'll walk through the process of deploying a FastAPI application to Azure App Service, one of the most straightforward deployment options.

By the end of this tutorial, you'll understand:

  • What Azure App Service is and why it's suitable for FastAPI
  • How to prepare your FastAPI app for Azure deployment
  • Step-by-step deployment process using different methods
  • How to monitor and troubleshoot your deployed application

Prerequisites

Before we begin, make sure you have:

  • A FastAPI application ready for deployment
  • A Microsoft Azure account (you can create a free account if needed)
  • Azure CLI installed on your machine
  • Git for version control
  • Python 3.6 or higher installed locally

Understanding Azure App Service

Azure App Service is a fully managed platform for building, deploying, and scaling web apps. It supports multiple programming languages, including Python, and provides built-in infrastructure maintenance, security patching, and scaling.

Key benefits for FastAPI deployment:

  1. Built-in support for Python: Run your FastAPI app without complex configuration
  2. Easy scaling: Adjust resources as your traffic grows
  3. Continuous deployment: Connect to GitHub for automatic deployments
  4. Managed SSL certificates: Secure your API endpoints
  5. Custom domains: Use your own domain name

Preparing Your FastAPI App for Azure

Before deployment, we need to structure our FastAPI app correctly for Azure App Service:

1. Project Structure

A typical project structure should look like:

my-fastapi-app/
├── app/
│ ├── __init__.py
│ ├── main.py # Your FastAPI application
│ ├── routers/ # API routes
│ └── models/ # Data models
├── requirements.txt
└── startup.txt # For Azure

2. Ensure Your main.py Is Properly Set Up

Your main FastAPI file should expose the app object. Here's a simple example:

python
from fastapi import FastAPI
import uvicorn

app = FastAPI(title="My API", description="Deployed on Azure")

@app.get("/")
async def root():
return {"message": "Hello World from Azure!"}

@app.get("/health")
async def health():
return {"status": "healthy"}

if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8000)

3. Create Requirements File

Make sure your requirements.txt file includes all dependencies:

fastapi==0.95.0
uvicorn==0.21.1
gunicorn==20.1.0
python-multipart==0.0.6
# Add other dependencies your app needs

4. Create Startup Command File

Create a file named startup.txt in your project root with the following content:

gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app

This tells Azure how to start your FastAPI application.

Deploying to Azure App Service

Let's go through the deployment process step by step:

Method 1: Using Azure Portal

  1. Create a Web App in Azure Portal:

    • Log into the Azure Portal
    • Click "Create a resource" > "Web App"
    • Fill in the basic details:
      • Resource Group: Create new or select existing
      • Name: Choose a unique name (e.g., my-fastapi-app)
      • Publish: Code
      • Runtime stack: Python 3.9 or higher
      • Operating System: Linux
      • Region: Choose the closest to your users
    • Click "Review + create" and then "Create"
  2. Configure deployment settings:

    • Once the web app is created, go to its dashboard
    • Navigate to "Settings" > "Configuration"
    • In "General settings", set:
      • Stack: Python
      • Startup Command: gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app
    • Click "Save"
  3. Deploy your code:

    • Go to "Deployment Center"
    • Choose your source (GitHub, Azure Repos, or Local Git)
    • Follow the wizard to connect your repository
    • Once connected, Azure will deploy your application

Method 2: Using Azure CLI

For a more streamlined approach, you can use the Azure CLI:

  1. Login to Azure:
bash
az login
  1. Create a resource group:
bash
az group create --name FastAPIResourceGroup --location eastus
  1. Create an App Service plan:
bash
az appservice plan create --name FastAPIAppPlan --resource-group FastAPIResourceGroup --sku B1 --is-linux
  1. Create a web app:
bash
az webapp create --resource-group FastAPIResourceGroup --plan FastAPIAppPlan --name my-fastapi-app --runtime "PYTHON|3.9"
  1. Configure the startup command:
bash
az webapp config set --resource-group FastAPIResourceGroup --name my-fastapi-app --startup-file "gunicorn -w 4 -k uvicorn.workers.UvicornWorker app.main:app"
  1. Deploy your code using Git:
bash
az webapp deployment source config-local-git --name my-fastapi-app --resource-group FastAPIResourceGroup
  1. Get the Git deployment URL:
bash
az webapp deployment list-publishing-credentials --name my-fastapi-app --resource-group FastAPIResourceGroup --query scmUri --output tsv
  1. Add the Azure remote to your local Git:
bash
git remote add azure <URL-from-previous-step>
  1. Push your code to Azure:
bash
git push azure main

Advanced Configuration

Environment Variables

To add environment variables (for API keys, database connections, etc.):

  1. In the Azure Portal, go to your App Service
  2. Navigate to "Settings" > "Configuration" > "Application settings"
  3. Click "+ New application setting"
  4. Add your key-value pairs
  5. Click "Save"

In your FastAPI code, access these as environment variables:

python
import os
from fastapi import FastAPI

app = FastAPI()
DATABASE_URL = os.environ.get("DATABASE_URL")

@app.get("/")
async def root():
return {"database_configured": DATABASE_URL is not None}

Custom Domain and HTTPS

To add a custom domain and enable HTTPS:

  1. In the Azure Portal, go to your App Service
  2. Navigate to "Settings" > "Custom domains"
  3. Click "+ Add custom domain"
  4. Follow the instructions to verify your domain
  5. Once added, click on the domain and select "Add binding" to add an SSL certificate

Scaling Your App

To scale your FastAPI application:

  1. In Azure Portal, go to your App Service
  2. Navigate to "Settings" > "Scale up (App Service plan)" to increase VM size
  3. Or go to "Scale out" to increase the number of instances

Real-world Example: A FastAPI Todo API on Azure

Let's deploy a more practical example—a simple Todo API with Azure Database for PostgreSQL:

  1. Create a PostgreSQL database in Azure:
bash
az postgres server create --resource-group FastAPIResourceGroup --name my-fastapi-postgres --location eastus --admin-user myuser --admin-password MyPassword123! --sku-name B_Gen5_1
  1. Create the Todo API app:
python
# app/main.py
from fastapi import FastAPI, HTTPException, Depends
from pydantic import BaseModel
from typing import List, Optional
import os
import databases
import sqlalchemy

DATABASE_URL = os.environ.get("DATABASE_URL")
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()

todos = sqlalchemy.Table(
"todos",
metadata,
sqlalchemy.Column("id", sqlalchemy.Integer, primary_key=True),
sqlalchemy.Column("title", sqlalchemy.String),
sqlalchemy.Column("completed", sqlalchemy.Boolean),
)

class TodoIn(BaseModel):
title: str
completed: bool = False

class Todo(BaseModel):
id: int
title: str
completed: bool

app = FastAPI(title="Todo API")

@app.on_event("startup")
async def startup():
await database.connect()

@app.on_event("shutdown")
async def shutdown():
await database.disconnect()

@app.post("/todos/", response_model=Todo)
async def create_todo(todo: TodoIn):
query = todos.insert().values(title=todo.title, completed=todo.completed)
last_record_id = await database.execute(query)
return {**todo.dict(), "id": last_record_id}

@app.get("/todos/", response_model=List[Todo])
async def read_todos():
query = todos.select()
return await database.fetch_all(query)

@app.get("/todos/{todo_id}", response_model=Todo)
async def read_todo(todo_id: int):
query = todos.select().where(todos.c.id == todo_id)
todo = await database.fetch_one(query)
if todo is None:
raise HTTPException(status_code=404, detail="Todo not found")
return todo

@app.put("/todos/{todo_id}", response_model=Todo)
async def update_todo(todo_id: int, todo: TodoIn):
query = todos.update().where(todos.c.id == todo_id).values(title=todo.title, completed=todo.completed)
await database.execute(query)
return {**todo.dict(), "id": todo_id}

@app.delete("/todos/{todo_id}", response_model=dict)
async def delete_todo(todo_id: int):
query = todos.delete().where(todos.c.id == todo_id)
await database.execute(query)
return {"message": "Todo deleted successfully"}
  1. Update requirements.txt:
fastapi==0.95.0
uvicorn==0.21.1
gunicorn==20.1.0
databases[postgresql]==0.7.0
sqlalchemy==1.4.46
psycopg2-binary==2.9.5
  1. Deploy to Azure as shown earlier

  2. Add the DATABASE_URL environment variable in Azure portal:

postgresql://myuser:[email protected]:5432/postgres

Monitoring and Troubleshooting

After deployment, monitor your application:

  1. View logs:

    • In Azure Portal, go to your App Service
    • Navigate to "Monitoring" > "Log stream" to see real-time logs
  2. Set up Application Insights:

    • In Azure Portal, go to your App Service
    • Navigate to "Settings" > "Application Insights"
    • Click "Turn on Application Insights"
  3. Configure logging in your FastAPI app:

python
import logging
from fastapi import FastAPI, Request

app = FastAPI()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("uvicorn")

@app.middleware("http")
async def log_requests(request: Request, call_next):
logger.info(f"Request: {request.method} {request.url}")
response = await call_next(request)
logger.info(f"Response status: {response.status_code}")
return response

@app.get("/error-test")
async def create_error():
try:
# Simulate error
1/0
except Exception as e:
logger.error(f"An error occurred: {str(e)}")
return {"error": str(e)}

Common Issues and Solutions

  1. Application not starting:

    • Check your startup command
    • Ensure all dependencies are in requirements.txt
    • Look at the logs for error messages
  2. Database connection issues:

    • Verify environment variables are set correctly
    • Check that the Azure PostgreSQL firewall allows connections from Azure services
  3. Performance issues:

    • Consider scaling up your App Service plan
    • Enable Application Insights to identify bottlenecks

Summary

In this guide, we've covered how to deploy a FastAPI application to Azure App Service. We started with the basics, including preparing your app structure, creating the necessary Azure resources, and deploying using different methods. We then explored advanced topics like environment variables, custom domains, and database integration, and finished with monitoring and troubleshooting techniques.

Azure App Service provides a robust platform for hosting FastAPI applications, with features that support all stages of your application lifecycle, from development to production.

Additional Resources

Exercises

  1. Deploy a basic FastAPI application to Azure App Service using the Azure CLI.
  2. Add a custom domain to your deployed FastAPI application.
  3. Implement environment-specific configuration for development and production environments.
  4. Create a CI/CD pipeline using GitHub Actions to automatically deploy your FastAPI app to Azure when you push to main.
  5. Add Application Insights to your FastAPI application and analyze the performance metrics.

Happy deploying!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)