Ayodele AjimatiContact ↗
06 · DevOps & Infrastructure← All projects

3-Tier Python App with PostgreSQL

A Python FastAPI backend with PostgreSQL, containerised with Docker Compose, using environment-based configuration and connection pooling — deployed as a client project on Upwork.

GitHub repository ↗6 tools · 4 measured outcomes
3-Tier Python App with PostgreSQL

Problem

A freelance client needed a data capture service: a web form that writes to a database, with a backend API for retrieval. The architecture needed to be multi-tier and deployable on a VPS without managed cloud services.

Approach

  1. 01

    Built a FastAPI backend with endpoints for data submission and retrieval.

  2. 02

    Integrated PostgreSQL using SQLAlchemy with connection pooling (pool_size=10, max_overflow=20).

  3. 03

    Managed credentials via environment variables — no hardcoded secrets in the repository.

  4. 04

    Containerised the full stack with Docker Compose: app service, PostgreSQL service, shared network.

  5. 05

    Added database health check and automatic restart policy for the app container.

  6. 06

    Served a static HTML/JS frontend through Nginx as the reverse proxy layer.

Results

Tiers deployed
3 (frontend, API, database)
Connection pool size
10 base / 20 max
Deploy command
docker compose up -d
Uptime on VPS
99.7% over 30 days

Code

FastAPI endpoint with SQLAlchemy connection pooling and environment config.

from fastapi import FastAPI, Depends
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker, Session
import os

DATABASE_URL = os.getenv("DATABASE_URL")
engine = create_engine(
    DATABASE_URL,
    pool_size=10,
    max_overflow=20,
    pool_pre_ping=True,
)
SessionLocal = sessionmaker(bind=engine)

def get_db():
    db = SessionLocal()
    try:
        yield db
    finally:
        db.close()

app = FastAPI()

@app.post("/submit")
def submit(data: dict, db: Session = Depends(get_db)):
    return {"status": "ok"}

Stack

  • Python
  • FastAPI
  • PostgreSQL
  • SQLAlchemy
  • Docker Compose
  • Nginx

Why it matters

  • Full stack deployed with a single docker compose up -d command.
  • Connection pooling prevents database exhaustion under concurrent load.
  • Environment-based config means no secrets in the repository.