A multi-tenant API Gateway built with a split-architecture design β a Django Control Plane for management and a FastAPI Data Plane for high-performance request proxying, authentication, and rate limiting.
- Overview
- Architecture
- Features
- Project Structure
- Tech Stack
- Getting Started
- Usage
- Rate Limiting
- Test Data
- Running Tests
Gateway is a self-hosted API gateway that lets you register upstream APIs behind a unified proxy layer. Each tenant (organization) can register multiple APIs, generate API keys with custom rate-limit plans, and route traffic through the gateway β all with built-in authentication, per-minute and per-month rate limiting, and usage tracking.
The project follows a two-plane architecture:
βββββββββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββββββββββ
β CONTROL PLANE β β DATA PLANE β
β (Django) β β (FastAPI) β
β β β β
β β’ Tenant registration/login β β β’ Reverse proxy to upstream β
β β’ API registration β β β’ API key authentication β
β β’ API key generation β β β’ Per-minute rate limiting β
β β’ Billing plan management β β β’ Per-month rate limiting β
β β’ Dashboard UI β β β’ Usage tracking (Redis) β
β β’ Django Admin β β β’ Client ID-based routing β
β β β β
β Port: 8000 β β Port: 7000 β
ββββββββββββββ¬βββββββββββββββββββββ ββββββββββββββββ¬ββββββββββββββββββββ
β β
βββββββββββββ Shared SQLite DB βββββββββββββ
+
Redis (usage/rate limits)
- Multi-Tenancy β Each user registers as a tenant with a unique slug. Tenants are fully isolated.
- API Registration β Register upstream APIs with a name, slug, and base URL. Access them through the gateway at
/{tenant_slug}/{api_slug}/{path}. - API Key Authentication β SHA-256 hashed API keys passed via the
X-API-Keyheader. Keys are shown only once on creation. - Client ID Support β Optional
X-Client-IDheader for per-client rate limiting within a tenant. - Billing Plans β Create plans with configurable
requests_per_minuteandrequests_per_monthlimits. - Rate Limiting β Redis-backed per-minute and per-month rate limiting enforced at the data plane.
- Usage Tracking β Asynchronous background usage recording to Redis.
- Dashboard UI β Dark-themed tenant dashboard to manage APIs, keys, and plans.
- Graceful Fallback β Falls back to
fakeredisif Redis is unavailable, so development works without Redis.
Gateway/
βββ control_plane/ # Django management app (port 8000)
β βββ control_plane/ # Django project settings & URLs
β β βββ settings.py
β β βββ urls.py
β β βββ wsgi.py
β βββ tenants/ # Tenant registration, login, dashboard
β β βββ models.py # Tenant model
β β βββ views.py # Auth views, dashboard, API/key creation
β β βββ forms.py # RegisterForm, APIForm, APIKeyForm
β β βββ urls.py
β β βββ tests.py
β β βββ templates/ # Dashboard, login, register HTML
β β βββ static/ # CSS styles
β βββ apis/ # API & APIKey models and views
β β βββ models.py # API, APIKey, Client models
β β βββ views.py
β β βββ templates/
β βββ billing/ # Billing plan model
β β βββ models.py # Plan model (RPM & RPM limits)
β βββ usage/ # Usage tracking app
β βββ setup_test_data.py # Script to seed test data
β βββ manage.py
βββ data_plane/ # FastAPI proxy app (port 7000)
β βββ fastapi_app/
β βββ main.py # FastAPI app factory
β βββ proxy.py # Reverse proxy + auth + rate limiting
β βββ dependencies.py # X-API-Key header extraction
β βββ tables.py # SQLAlchemy table definitions
β βββ config.py # Database & Redis URL configuration
β βββ lifespan.py # App startup/shutdown (DB, Redis, HTTP)
β βββ state.py # AppState dataclass
β βββ usage.py # Async usage recording
βββ requirements.txt
βββ .gitignore
| Layer | Technology |
|---|---|
| Control Plane | Django 5.2, SQLite |
| Data Plane | FastAPI, Uvicorn, httpx, SQLAlchemy |
| Rate Limiting | Redis (with fakeredis fallback) |
| Database | SQLite (shared between planes) |
| Templating | Django Templates, Tailwind CSS |
- Python 3.10+
- Redis (optional β falls back to
fakeredisfor development) - Docker + Docker Compose (optional β for the fully dockerized setup)
# Clone the repository
git clone https://github.com/Soumik8114/Gateway.git
cd Gateway
# Create and activate a virtual environment
python -m venv venv
source venv/bin/activate # Linux/macOS
venv\Scripts\activate # Windows
# Install dependencies
pip install -r requirements.txtcd control_plane
# Run migrations
python manage.py migrate
# Create a superuser (for Django Admin)
python manage.py createsuperuserTerminal 1 β Control Plane (Django):
cd control_plane
python manage.py runserver 8000Terminal 2 β Data Plane (FastAPI):
uvicorn data_plane.fastapi_app.main:app --host 0.0.0.0 --port 7000 --reloadThis repo includes a docker-compose.yml that runs the full stack:
control_plane(Django) onhttp://localhost:8000data_plane(FastAPI) onhttp://localhost:7000redisonlocalhost:6379
The Control Plane and Data Plane share the same SQLite DB via a named Docker volume mounted at /data/db.sqlite3.
Start (foreground):
docker compose up --buildStart (background):
docker compose up --build -dStop:
docker compose downStop and remove volumes (clears Redis + SQLite data):
docker compose down -vThe control_plane container runs migrations automatically on startup, but youβll still likely want a superuser for Django Admin.
Create a superuser:
docker compose exec control_plane python manage.py createsuperuserRun migrations manually (optional):
docker compose exec control_plane python manage.py migrateSeed test data:
docker compose exec control_plane python setup_test_data.pyRun tests:
docker compose exec control_plane python manage.py test- Navigate to
http://localhost:8000/register/ - Fill in your username, email, tenant name, and password
- You'll be redirected to the tenant dashboard
From the dashboard, register an upstream API:
| Field | Example |
|---|---|
| Name | My API |
| Slug | my-api |
| Upstream Base URL | https://httpbin.org |
| Auth Header Name | X-API-Key |
From the dashboard, create an API key with a billing plan:
| Field | Example |
|---|---|
| Plan Name | Starter Plan |
| Requests per Minute | 60 |
| Requests per Month | 10000 |
β οΈ The raw API key is shown only once. Save it securely.
Send requests through the gateway:
curl -H "X-API-Key: <your-api-key>" \
http://localhost:7000/{tenant-slug}/{api-slug}/getExample:
curl -H "X-API-Key: secret_key_12345" \
http://localhost:7000/test-tenant/test-api/getThis proxies the request to https://httpbin.org/get.
Rate limits are enforced at the data plane using Redis:
| Limit Type | Scope | Response on Exceed |
|---|---|---|
| Per-Minute | Per API Key or Client ID | 429 Rate limit exceeded |
| Per-Month | Per API Key or Client ID | 429 Monthly rate limit exceeded |
If an X-Client-ID header is provided, rate limits are applied per client rather than per API key.
Seed the database with sample data for development:
cd control_plane
python setup_test_data.pyThis creates:
| Resource | Value |
|---|---|
| User | testuser / password |
| Tenant | test-tenant |
| API | test-api β https://httpbin.org |
| Plan | 5 req/min, 100 req/month |
| API Key | secret_key_12345 |
cd control_plane
python manage.py test