Skip to content

About

multi-container backend application built to understand how FastAPI, PostgreSQL, Redis, Nginx, and pgAdmin work together using Docker Compose

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

ย 

History

1 Commit

Folders and files

Repository files navigation

๐Ÿš€ Dockerized Full-Stack FastAPI Application

A hands-on multi-container backend application built to understand how FastAPI, PostgreSQL, Redis, Nginx, and pgAdmin work together using Docker Compose.

Python FastAPI PostgreSQL Redis Nginx Docker


๐Ÿ“Œ Table of Contents


๐Ÿ“– Project Overview

This project demonstrates how a backend application can be split into multiple services and run together using Docker Compose.

The application contains:

  • FastAPI โ†’ REST API and core application logic
  • PostgreSQL โ†’ Persistent relational database
  • Redis โ†’ In-memory caching layer
  • Nginx โ†’ Reverse proxy and public application entry point
  • pgAdmin โ†’ Web-based PostgreSQL administration interface

The project was built as a hands-on learning exercise to understand:

  • Docker containerization
  • Multi-container application architecture
  • Service-to-service communication
  • Docker networking & isolation
  • Persistent volume storage
  • Environment-based configuration
  • Caching strategies & invalidation
  • Reverse proxy configurations
  • Container health checks

The architecture is intentionally production-inspired, while remaining lightweight enough to spin up locally with a single command.


๐ŸŽฏ Objectives

The primary goals of this project are:

  • Containerize a FastAPI application using a production-ready Dockerfile
  • Run multiple independent services in sync using Docker Compose
  • Connect FastAPI with PostgreSQL using an asynchronous driver/ORM
  • Implement Redis caching for read-heavy operations
  • Configure Nginx as a reverse proxy entry point
  • Attach Docker volumes for persistent database storage
  • Manage secrets and parameters using environment files
  • Isolate traffic across dedicated frontend and backend Docker networks
  • Implement container health checks to ensure proper boot sequencing
  • Master container-to-container communication using internal DNS

โœจ Features

  • โœ… FastAPI REST API: Asynchronous, high-performance web API
  • โœ… PostgreSQL Database: Robust relational data storage
  • โœ… SQLModel Integration: Unified ORM and Pydantic validation
  • โœ… Psycopg Driver: Modern Python driver for PostgreSQL
  • โœ… Redis Caching: Fast key-value retrieval for repeated queries
  • โœ… Cache Invalidation: Automatic Redis cache purges upon user mutations
  • โœ… Nginx Reverse Proxy: Traffic routing, header management, and isolation
  • โœ… pgAdmin Web UI: Visual database dashboard for monitoring data
  • โœ… Production-Style Dockerfile: Multi-stage build support
  • โœ… Docker Compose Orchestration: Declarative multi-service setup
  • โœ… Persistent Volumes: Data survives container lifecycles
  • โœ… Network Segregation: Distinct frontend and backend bridge networks
  • โœ… Health Checks: Container startup dependencies tied to service readiness
  • โœ… Interactive Docs: Out-of-the-box Swagger UI via /docs

๐Ÿ—๏ธ Architecture

The application follows a decoupled multi-tier architecture:

                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚     Browser     โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                  โ”‚
                           localhost:8080
                                  โ”‚
                                  โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚      Nginx      โ”‚
                         โ”‚ Reverse Proxy   โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                  โ”‚
                         frontend network
                                  โ”‚
                                  โ–ผ
                         โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                         โ”‚     FastAPI     โ”‚
                         โ”‚    Backend      โ”‚
                         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚ โ”‚
                         backend โ”‚ โ”‚ network
                    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
                    โ–ผ                           โ–ผ
             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
             โ”‚ PostgreSQL  โ”‚             โ”‚    Redis    โ”‚
             โ”‚  Database   โ”‚             โ”‚    Cache    โ”‚
             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                    โ–ฒ
                    โ”‚
             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”
             โ”‚   pgAdmin   โ”‚
             โ”‚ DB Manager  โ”‚
             โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Why These Components?

Component Why It Exists
FastAPI Provides the core backend REST API and business logic
PostgreSQL Stores relational application data persistently
Redis Provides ultra-fast temporary/cache storage
Nginx Acts as a reverse proxy, security barrier, and entry point
pgAdmin Provides a browser-based management interface for PostgreSQL
Docker Packages applications and dependencies into reproducible containers
Docker Compose Declares, connects, and orchestrates all containers together

๐Ÿ”„ Request Flow

1. GET /users (Read Flow)

Client
   โ”‚
   โ–ผ
Nginx :8080
   โ”‚
   โ–ผ
FastAPI :8000
   โ”‚
   โ–ผ
Check Redis
   โ”‚
   โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Cache Hit โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–บ Return Cached Users
   โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Cache Miss
                โ”‚
                โ–ผ
           PostgreSQL
                โ”‚
                โ–ผ
         Store Result in Redis
                โ”‚
                โ–ผ
          Return Users

Why cache? Avoids querying PostgreSQL every time repeated, non-mutated data is requested, dramatically reducing database load.

2. POST /users (Write Flow)

Client
   โ”‚
   โ–ผ
Nginx
   โ”‚
   โ–ผ
FastAPI
   โ”‚
   โ–ผ
PostgreSQL (Write record)
   โ”‚
   โ–ผ
Invalidate Redis "users" Cache
   โ”‚
   โ–ผ
Return Created User

Why invalidate? Ensures clients never receive stale user lists on subsequent reads after an insert.


๐Ÿงฉ Services

Service Purpose Container Port Host Port Network
fastapi REST API Backend 8000 8000 (optional) frontend, backend
postgres Database 5432 Not exposed backend
redis In-Memory Cache 6379 Not exposed backend
nginx Reverse Proxy 80 8080 frontend
pgadmin Database UI 80 5050 backend

Core Concept: Port Forwarding

Host ports and container ports do not need to match:

ports:
  - "8080:80"
Host Machine (localhost:8080)
    โ”‚
    โ–ผ
Nginx Container (port 80)

๐Ÿงฐ Technology Stack

Technology Purpose
Python Core programming language
FastAPI High-performance backend web framework
SQLModel ORM layer combining SQLAlchemy and Pydantic
Psycopg Modern Python driver for PostgreSQL
PostgreSQL Primary relational database
Redis In-memory key-value cache
Nginx Reverse proxy and HTTP gateway
pgAdmin PostgreSQL management GUI
Docker Containerization platform
Docker Compose Multi-container coordination

๐Ÿ“‚ Project Structure

.
โ”œโ”€โ”€ main.py              # FastAPI application and API endpoints
โ”œโ”€โ”€ database.py          # Database connection, SQLModel engine, session dependencies
โ”œโ”€โ”€ models.py            # SQLModel data models & schemas
โ”œโ”€โ”€ requirements.txt     # Python application dependencies
โ”‚
โ”œโ”€โ”€ Dockerfile           # FastAPI container image definition
โ”œโ”€โ”€ docker-compose.yml   # Multi-service composition configuration
โ”œโ”€โ”€ nginx.conf           # Reverse proxy configuration
โ”‚
โ”œโ”€โ”€ .env                 # Local secrets and config (do NOT commit)
โ”œโ”€โ”€ .env.example         # Template for environment variables
โ”œโ”€โ”€ .gitignore           # Git untracked file rules
โ”œโ”€โ”€ .dockerignore         # Docker context exclusions
โ”‚
โ””โ”€โ”€ README.md            # Comprehensive project documentation

โš™๏ธ Prerequisites

Ensure you have the following installed locally:

Verify installations:

docker --version
docker compose version

๐Ÿš€ Getting Started

1. Clone the Repository

git clone <YOUR_GITHUB_REPOSITORY_URL>
cd <PROJECT_FOLDER>

2. Configure Environment Variables

Copy the sample environment file:

cp .env.example .env

Update credentials inside .env:

POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_password
POSTGRES_DB=myapp
PGADMIN_DEFAULT_EMAIL[email protected]
PGADMIN_DEFAULT_PASSWORD=your_password

3. Build & Run

Run all services using Docker Compose:

docker compose up --build -d

4. Verify Status

docker compose ps
docker compose logs -f

๐Ÿ” Environment Variables

Variable Description
POSTGRES_USER PostgreSQL superuser username
POSTGRES_PASSWORD PostgreSQL superuser password
POSTGRES_DB Application database name
PGADMIN_DEFAULT_EMAIL Web login username/email for pgAdmin
PGADMIN_DEFAULT_PASSWORD Web login password for pgAdmin

Internal Service Discovery

Inside Docker Compose networks, service names act as internal hostnames:

  • Database URL: postgresql+psycopg://postgres:your_password@postgres:5432/myapp
  • Redis URL: redis://redis:6379

๐Ÿณ Docker Commands

Action Command
Start in background docker compose up -d
Rebuild images & start docker compose up --build -d
List container statuses docker compose ps
Follow all logs docker compose logs -f
Follow service logs `docker compose logs -f <fastapi
Stop containers docker compose stop
Tear down containers docker compose down
Tear down & delete volumes docker compose down -v โš ๏ธ

๐ŸŒ Application URLs

Service URL Notes
Nginx โ†’ FastAPI http://localhost:8080 Public Entry Point
FastAPI Direct http://localhost:8000 Internal/Host debugging
Swagger UI Docs http://localhost:8080/docs Interactive API exploration
Health Check http://localhost:8080/health Uptime check
Redis Cache Test http://localhost:8080/redis_test Redis sanity endpoint
pgAdmin Web UI http://localhost:5050 Database administration

๐Ÿ“ก API Endpoints

1. Health Check

  • Endpoint: GET /health
  • Response:
    {
      "status": "healthy"
    }

2. Create User

  • Endpoint: POST /users
  • Payload:
    {
      "name": "Vijay",
      "email": "[email protected]"
    }
  • Action: Inserts user into PostgreSQL and clears the cached user list from Redis.

3. Get All Users

  • Endpoint: GET /users
  • Action: Fetches from Redis cache if available; queries PostgreSQL and populates cache on miss.

4. Test Redis Connectivity

  • Endpoint: GET /redis_test
  • Response:
    {
      "redis_msg": "hello from redis"
    }

๐Ÿ—„๏ธ PostgreSQL & pgAdmin

FastAPI connects to PostgreSQL across the internal Docker bridge network using postgres:5432.

Accessing pgAdmin

  1. Open http://localhost:5050.
  2. Authenticate with PGADMIN_DEFAULT_EMAIL and PGADMIN_DEFAULT_PASSWORD.
  3. Add a new server connection using:
    • Host name/address: postgres
    • Port: 5432
    • Maintenance database: myapp
    • Username: postgres
    • Password: <POSTGRES_PASSWORD>

โšก Redis Caching

Redis acts as a low-latency read-through cache layer:

GET /users
      โ”‚
      โ–ผ
 Check Redis
      โ”‚
 โ”Œโ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”
 โ”‚         โ”‚
Hit       Miss
 โ”‚         โ”‚
 โ–ผ         โ–ผ
Return   PostgreSQL
Data        โ”‚
            โ–ผ
        Store in Redis
            โ”‚
            โ–ผ
        Return Data

Cache invalidation occurs immediately when data changes:

POST /users โ”€โ”€โ–บ PostgreSQL โ”€โ”€โ–บ Delete "users" Redis Key

๐ŸŒ Nginx Reverse Proxy

Nginx acts as the single public gateway on port 8080:

Browser โ”€โ”€โ–บ Nginx (:80) โ”€โ”€โ–บ FastAPI (:8000)

Configuration snippet from nginx.conf:

events {}
http {
    server {
        listen 80;
        location / {
            proxy_pass http://fastapi:8000;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
        }
    }
}

๐Ÿ’พ Docker Volumes

PostgreSQL uses a named volume to ensure persistence across container removals:

volumes:
  postgres_data:

Mounted to:

/var/lib/postgresql/data

Key Takeaway: Stopping or recreating a container does not delete stored records. Data persists safely inside postgres_data until wiped with docker compose down -v.


๐Ÿ”— Docker Networks

Network isolation ensures backend services are never directly reachable from the host machine or public internet.

                 frontend
                    โ”‚
                  Nginx
                    โ”‚
                 FastAPI
                    โ”‚
                 backend
             โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”
             โ”‚      โ”‚      โ”‚
        PostgreSQL Redis  pgAdmin
  • Frontend Network: Accessible by Nginx and FastAPI.
  • Backend Network: Accessible by FastAPI, PostgreSQL, Redis, and pgAdmin.

โค๏ธ Health Checks

Container startup does not guarantee application readiness. Health checks ensure services only accept connections when fully booted:

  • PostgreSQL: Checked via pg_isready
  • Redis: Checked via redis-cli ping
  • FastAPI: Checked via GET /health

In docker-compose.yml:

depends_on:
  postgres:
    condition: service_healthy
  redis:
    condition: service_healthy

๐Ÿ” Security Considerations

This project focuses on architectural fundamentals. Good practices implemented:

  • Credentials managed via .env and excluded from source control via .gitignore
  • .env excluded from image layers via .dockerignore
  • Database and Cache ports (5432, 6379) are unexposed to the host
  • All internal communication happens within isolated private bridge networks

Recommended for Production

  • SSL/TLS Termination via Let's Encrypt / Certbot on Nginx
  • HashiCorp Vault or AWS Secrets Manager for credential storage
  • Rate limiting and WAF rules via Nginx
  • JWT-based authentication & role-based authorization
  • Automated database backup cron jobs to external storage (e.g., AWS S3)

๐Ÿงช Testing

The system was verified across key integration layers:

  • FastAPI: Verified endpoints (/health, /users, /docs) via Swagger and curl
  • Redis: Confirmed cache hits and invalidation logic with /redis_test and /users
  • PostgreSQL: Validated persistent data storage after container restarts
  • Nginx: Confirmed reverse proxy forwarding to upstream FastAPI containers
  • Docker: Monitored real-time system logs using docker compose logs

๐Ÿ” Troubleshooting

โŒ PostgreSQL password authentication failed

PostgreSQL sets credentials on initial database creation. If .env is updated after the volume has already been initialized, the password won't change automatically.

Development Fix:

docker compose down -v
docker compose up --build -d

โš ๏ธ Note: This deletes the database volume and all existing data.

โŒ FastAPI cannot connect to PostgreSQL

Do not use localhost:5432 from inside a container. Use the Docker service name:

DATABASE_URL = "postgresql+psycopg://postgres:password@postgres:5432/myapp"
โŒ FastAPI cannot connect to Redis

Use the Redis container service name:

REDIS_URL = "redis://redis:6379"
โŒ Nginx cannot reach FastAPI

Verify that both services share the frontend network and that proxy_pass points to http://fastapi:8000;. Check logs:

docker compose logs nginx
docker compose logs fastapi
โŒ Host port 8080 already in use

Change the host mapping in docker-compose.yml:

ports:
  - "8081:80"
โŒ Stale or inconsistent Redis cache data

Restart the Redis container to flush memory:

docker compose restart redis

๐ŸŽฅ Project Demonstration

Key concepts verified during live testing:

  1. Docker Images & Multi-Stage Builds: Creating lean application runtime layers.
  2. Container Lifecycle: Running multi-service topologies in detached mode.
  3. Volume Persistence: Proving data survival across container destructions.
  4. Service Discovery: Validating name resolution via Docker internal DNS.
  5. End-to-End Traffic Routing: Tracing requests from client browser through Nginx to FastAPI, PostgreSQL, and Redis.

๐Ÿ“š What I Learned

  • Docker Fundamentals: Images vs. containers, bind mounts vs. named volumes, bridge networks.
  • Service Orchestration: Coordinating dependencies and health status with Docker Compose.
  • Backend Architecture: Structuring production-ready APIs with FastAPI, SQLModel, and Psycopg.
  • Caching Mechanics: Handling read-through patterns and mitigating cache staleness.
  • Network Boundaries: Segmenting public-facing proxies from private backend databases.

๐Ÿ”ฎ Future Improvements

  • Automated database migrations using Alembic
  • Redis key expiration policies (TTL)
  • Unit & integration test suites run via Pytest in CI/CD
  • Centralized metric monitoring using Prometheus & Grafana
  • Cloud deployment via Kubernetes & Terraform
  • SSL/TLS automation using Let's Encrypt

๐Ÿง  Key Takeaways

Application โ”€โ”€โ–บ FastAPI โ”€โ”€โ”ฌโ”€โ”€โ–บ PostgreSQL
                          โ””โ”€โ”€โ–บ Redis
                             โ–ฒ
                             โ”‚
                           Nginx
                             โ–ฒ
                             โ”‚
                           Client

Understanding how individual services communicate, isolate, and persist data is far more valuable than simply knowing how to run docker compose up. Fundamentals compound.


๐Ÿ‘จโ€๐Ÿ’ป Author

Vijay Rangvani
IT Engineer | Backend & Cloud Explorer

  • Focus Areas: Python, FastAPI, Docker, Kubernetes, Cloud Architecture

โญ Final Note

"Small steps look ordinary today, but they build the foundations for tomorrow."

About

multi-container backend application built to understand how FastAPI, PostgreSQL, Redis, Nginx, and pgAdmin work together using Docker Compose

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages