Deploying a Minimal FastAPI App on DigitalOcean: A Hands-On Guide
Back to Blog
Backend8 min read

Deploying a Minimal FastAPI App on DigitalOcean: A Hands-On Guide

HHazrat Ummar ShaikhJune 21, 20260 views

I remember a couple of months ago, during a late-night debugging session for a particularly stubborn memory leak in a new Ktor service, a few developer friends hit me up. They knew I hosted most of my side projects and many of my Discord bots on DigitalOcean, and lately, they'd been curious about my setup. Not just 'how do you host a website,' but the whole lifecycle: from local dev to a production-ready cloud deployment. I’ve seen countless tutorials that skip vital parts or assume too much, leaving developers with a half-baked understanding.

My friends wanted to see the smallest real app I could deploy. Something that touched on an API, a database, and proper containerization, all running on a cloud VM. This wasn't about a static site or a serverless function; it was about demonstrating a classic, robust backend deployment pattern. So, I built them exactly that: a tiny FastAPI application connected to MongoDB, all orchestrated with Docker and served via Nginx on a DigitalOcean Droplet.

This isn't just theory. This is the exact pattern I use for many of my production microservices, scaled up or down. Whether I'm building a new backend for a Jetpack Compose Android app or a complex Discord bot, the principles remain consistent. If you're looking to understand the mechanics of taking a Python backend to the cloud, this guide is for you.

Detailed high-tech concept illustration of a developer's workstation, multiple holographic screens displaying Python cod

The "Smallest Real App": A Simple Counter Service

To keep things minimal yet demonstrative, I chose a simple counter service. It exposes a single endpoint that increments a counter and returns its current value. The state (the counter's value) is persisted in a MongoDB database. This allows us to demonstrate:

  • A functional API endpoint.
  • Database integration and persistence.
  • Containerization of both the application and the database.
  • Deployment to a cloud VM.
  • Basic reverse proxy setup with Nginx.
Clean dark mode UI presentation style illustration showing a simplified deployment pipeline from local code, through a D

1. The FastAPI Application

First, let's set up our FastAPI application. If you haven't worked with FastAPI before, I highly recommend checking out its official documentation. It's a fantastic framework for building high-performance APIs with Python, leveraging Starlette and Pydantic. I've even written a detailed comparison between Ktor and FastAPI that you can find at /blog/ktor-fastapi-backend-comparison, highlighting why FastAPI often wins for specific use cases.

Create a directory for your project, say do-counter-app. Inside, create a file named main.py:

# main.py

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from pymongo import MongoClient
from pymongo.errors import ConnectionFailure
import os
import uvicorn

app = FastAPI()

# MongoDB Configuration
MONGO_URI = os.getenv("MONGO_URI", "mongodb://localhost:27017/")
DATABASE_NAME = os.getenv("DATABASE_NAME", "counter_db")
COLLECTION_NAME = os.getenv("COLLECTION_NAME", "counters")

client = None
db = None

try:
    client = MongoClient(MONGO_URI)
    db = client[DATABASE_NAME]
    # The ping command is cheap and does not require auth.
    client.admin.command('ping')
    print("Successfully connected to MongoDB!")
except ConnectionFailure as e:
    print(f"Could not connect to MongoDB: {e}")
    # In a real app, you might want to retry or exit
    client = None
    db = None

class Counter(BaseModel):
    value: int = 0

@app.get("/")
async def read_root():
    return {"message": "Welcome to the DigitalOcean Counter App!"}

@app.post("/increment", response_model=Counter)
async def increment_counter():
    if not db:
        raise HTTPException(status_code=500, detail="Database connection not established.")
    
    counters_collection = db[COLLECTION_NAME]
    
    # Atomically increment the counter or insert if it doesn't exist
    result = counters_collection.find_one_and_update(
        {"_id": "global_counter"},
        {"$inc": {"value": 1}},
        upsert=True,
        return_document=True
    )
    
    if result:
        return Counter(value=result["value"])
    else:
        raise HTTPException(status_code=500, detail="Failed to increment counter.")

@app.get("/current", response_model=Counter)
async def get_current_counter():
    if not db:
        raise HTTPException(status_code=500, detail="Database connection not established.")

    counters_collection = db[COLLECTION_NAME]
    counter_doc = counters_collection.find_one({"_id": "global_counter"})

    if counter_doc:
        return Counter(value=counter_doc["value"])
    else:
        return Counter(value=0) # Default to 0 if not found

if __name__ == "__main__":
    # This block is for local testing with `python main.py`
    # For production, Uvicorn is run via Gunicorn or direct `uvicorn main:app` command.
    uvicorn.run(app, host="0.0.0.0", port=8000)

And our dependencies in requirements.txt:

# requirements.txt

fastapi==0.111.0
uvicorn[standard]==0.29.0
pymongo==4.7.2
pydantic==2.7.1
Highly detailed 3D digital art of a miniature city built on a circuit board, with small server towers representing dropl

2. Dockerizing the Application and Database

Containerization is non-negotiable for modern deployments. Docker provides consistency between development and production environments, eliminating

Need Help with Custom APIs or Backend Systems?

I build robust, secure, and scalable backend services, databases, and microservices using FastAPI, Ktor, Node.js, and MongoDB. Let's build your server infrastructure!

H

Written by

Hazrat Ummar Shaikh

Android Developer with 4+ years of experience. Built production Android apps, Ktor backends, Discord bots, and SaaS products using Kotlin, Python, and MongoDB. Passionate about building robust systems and writing clean code.

Related Posts

Mastering Python MCP Servers: A Practical GitHub API Integration Guide
Backend

Unlock advanced AI integration with Model Context Protocol. I'll show you how to build a robust Python MCP server from scratch, leveraging the GitHub API for real-world context.

#python#ai#mcp
Jun 20, 2026
Read More
Beyond Keywords: Building Smart Job Agents with FastAPI & MongoDB
Backend

I tested a dozen job search tools and found them all lacking. Discover how to build your own high-performance, context-aware job agent.

#career#opensou#python
Jun 21, 2026
Read More
Automating ITR Filings: A Python Deep Dive Saving 209 Hours
Backend

A weekend Python script I engineered saved a CA firm 209 hours during ITR season. I'll break down the FastAPI, MongoDB, and automation strategies that unlocked this massive efficiency gain.

#python#automation#fintech
Jun 20, 2026
Read More