A FastAPI/Starlette-native wrapper for python-ipware that eliminates the need for WSGI-style header conversion.
python-ipware expects WSGI-style headers (HTTP_X_FORWARDED_FOR), but FastAPI uses natural header names (X-Forwarded-For). This wrapper handles the conversion automatically so you don't have to.
Also, the default precedence order is optimized for modern cloud deployments. See the default precedence configuration in the source code. This is different from the default ordering ipware which deprioritizes platform-specific headers, which is often the wrong ordering if you are using something like CloudFlare.
- Zero conversion overhead - Headers converted once at initialization, not on every request
- FastAPI-native API - Works directly with FastAPI/Starlette
Requestobjects - Customizable precedence - Easy to configure header priority for your infrastructure
- Proxy validation - Supports trusted proxy lists and proxy count validation
uv add fastapi-ipwareTake a look at this example usage.
from fastapi import FastAPI, Request
from fastapi_ipware import FastAPIIpWare
app = FastAPI()
ipware = FastAPIIpWare()
@app.get("/")
async def get_ip(request: Request):
ip, trusted = ipware.get_client_ip_from_request(request)
if ip:
return {
"ip": str(ip),
"trusted": trusted,
"is_public": ip.is_global,
"is_private": ip.is_private,
}
return {"error": "Could not determine IP"}from fastapi_ipware import FastAPIIpWare
# Use default configuration (optimized for FastAPI/cloud deployments)
ipware = FastAPIIpWare()
ip, trusted = ipware.get_client_ip_from_request(request)Customize which headers are checked and in what order:
# Prioritize Cloudflare headers
ipware = FastAPIIpWare(
precedence=(
"CF-Connecting-IP",
"X-Forwarded-For",
"X-Real-IP",
)
)
# NGINX configuration
ipware = FastAPIIpWare(
precedence=(
"X-Real-IP",
"X-Forwarded-For",
)
)Validate that requests pass through the expected number of proxies:
# Expect exactly 1 proxy (e.g., AWS ALB)
ipware = FastAPIIpWare(proxy_count=1)
# In strict mode, must be exactly 1 proxy
ip, trusted = ipware.get_client_ip_from_request(request, strict=True)
# In non-strict mode, allow 1 or more proxies
ip, trusted = ipware.get_client_ip_from_request(request, strict=False)Validate that requests pass through specific trusted proxies:
# Trust specific proxy IP prefixes
ipware = FastAPIIpWare(
proxy_list=["10.0.", "10.1."] # AWS internal IPs
)
ip, trusted = ipware.get_client_ip_from_request(request)
# trusted=True only if request came through specified proxiesUse both proxy count and trusted proxy list:
# Expect 1 proxy from a specific IP range
ipware = FastAPIIpWare(
proxy_count=1,
proxy_list=["10.0."]
)The returned IP address object has useful properties:
ip, _ = ipware.get_client_ip_from_request(request)
if ip:
print(f"Is public: {ip.is_global}")
print(f"Is private: {ip.is_private}")
print(f"Is loopback: {ip.is_loopback}")
print(f"Is multicast: {ip.is_multicast}")python-ipware automatically prefers:
- Public (global) IPs first
- Private IPs second
- Loopback IPs last