(Note: The diagram below is also available at docs/architecture.mmd and can be viewed rendered natively on GitHub.)
flowchart TD
subgraph Client [Client]
Internet([Internet])
Cloudflare([Cloudflare DNS/Proxy])
end
subgraph GitHub [GitHub]
GHA[GitHub Actions]
GHCR[(GHCR)]
end
subgraph VPS [VPS Host]
Fail2Ban[fail2ban]
subgraph Docker Compose
NGINX[NGINX]
Certbot[Certbot]
FastAPI[FastAPI App]
PostgreSQL[(PostgreSQL)]
Redis[(Redis)]
Prometheus[Prometheus]
Grafana[Grafana]
end
end
Internet -- "HTTPS" --> Cloudflare
Cloudflare -- "HTTPS (port 443) proxied" --> NGINX
NGINX -- "HTTP (port 8000, internal)" --> FastAPI
FastAPI -- "SQL queries (port 5432)" --> PostgreSQL
FastAPI -- "Cache read/write (port 6379)" --> Redis
Prometheus -- "Scrapes metrics" --> FastAPI
Grafana -- "Queries metrics" --> Prometheus
Fail2Ban -. "Monitors logs & Bans IPs" .-> NGINX
GHA -- "Build/push image" --> GHCR
GHA -- "Deploy via SSH" --> NGINX
Certbot <-->|"Cert volume shared"| NGINX
The FastAPI Task Management API is a production-grade, RESTful web service for managing tasks. It is containerized and deployed on a single Ubuntu VPS using Docker Compose, demonstrating a complete DevOps lifecycle including infrastructure provisioning, CI/CD, observability, and backup strategies.
Internet
│
▼
┌────────────────┐
│ Cloudflare CDN │
└────────┬───────┘
│ (HTTPS / 443)
▼
┌──────────────────────────────┐
┌──────────────┐ │ NGINX (Reverse Proxy) │
│ fail2ban │<──>│ (TLS Termination via Let's │
│ (Host level) │ │ Encrypt / Certbot) │
└──────────────┘ └──────────────┬───────────────┘
│
▼
┌──────────────────────────────┐◄────────┐
│ FastAPI App │ │
│ (Task Management, Rate │ │
│ Limiting Middleware) │ │
└──────┬───────────────┬───────┘ ┌────┴────┐
│ │ │ Prom- │
┌──────▼───────┐ ┌─────▼───────┐ │ etheus │
│ PostgreSQL │ │ Redis │◄───┤ + │
│ (Persistent │ │ (Rate Limit │ │ Grafana │
│ Database) │ │ & Cache) │ └─────────┘
└──────────────┘ └─────────────┘
| Service | Technology/Image | Purpose | Internal Port | Public Port |
|---|---|---|---|---|
| NGINX | nginx:1.25-alpine |
Reverse proxy, TLS termination, static asset serving, security headers. | 80 | 80, 443 |
| App | Custom (python:3.12-slim) |
Core business logic, rate-limiting, and REST API endpoints. | 8000 | None |
| PostgreSQL | postgres:16-alpine |
Authoritative persistent storage for tasks and user data. | 5432 | None |
| Redis | redis:7-alpine |
Read-through cache for tasks list and rate-limiting counters. | 6379 | None |
| Certbot | certbot/certbot:latest |
Automated Let's Encrypt SSL certificate issuance and renewal. | N/A | None |
| Prometheus | prom/prometheus:v2.51.0 |
Scrapes and stores metrics from the FastAPI application. | 9090 | 9090 (via 127.0.0.1) |
| Grafana | grafana/grafana:10.4.0 |
Dashboards for visualizing Prometheus metrics. | 3000 | 3000 (via 127.0.0.1) |
| fail2ban | Host Package | Parses NGINX logs and bans IPs with high failure rates at the firewall level. | N/A | None |
All services are connected via a user-defined Docker bridge network (backend_net).
- Internal Only: The
app,postgres, andrediscontainers are completely isolated from the host's public network interface. They do not expose ports to the Internet. - Public Facing: Only
nginxexposes ports 80 and 443 to the Internet. This ensures that all incoming traffic must pass through the reverse proxy, which enforces TLS and security headers before forwarding traffic to the FastAPI application.
- Client Request: A user makes an HTTPS request to
https://api.example.com/tasks. - TLS Termination: NGINX receives the request on port 443 (proxied via Cloudflare), decrypts the TLS payload using the Let's Encrypt certificate, and forwards the plain HTTP request to the internal
appcontainer on port 8000. - Rate Limiting Middleware: The FastAPI app intercepts the request, checks the client IP against Redis counters. If the limit is exceeded, it returns a
429 Too Many Requests. - Cache & Database: If it's a read request (e.g.,
GET /tasks), the app checks Redis for a cached response. If a cache miss occurs, or if it's a write request, the app queries PostgreSQL. - Response: The database returns the data to the app, which caches it in Redis (if applicable), serializes it to JSON, and sends it back through NGINX to the client.
- FastAPI: Chosen for its high performance (ASGI), automatic OpenAPI documentation, and Python-native type hints.
- PostgreSQL: Selected for robust ACID compliance, reliability, and structured relational data management.
- Redis: Ideal for high-speed, transient data like API rate limits and short-lived caching, significantly reducing database load.
- NGINX: Industry-standard, high-performance reverse proxy. Handles connection management and TLS termination much better than Python web servers like Uvicorn.
- Docker Compose: Keeps the single-VPS architecture simple, declarative, and easy to orchestrate without the overhead and complexity of Kubernetes.