> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/fastapi/fastapi/llms.txt
> Use this file to discover all available pages before exploring further.

# Running Behind a Proxy

> Configure FastAPI to work correctly behind reverse proxies and load balancers

When running FastAPI behind a reverse proxy (like Nginx, Apache, or a cloud load balancer), you need to configure your application to correctly handle proxied requests and generate accurate URLs.

## Understanding Proxy Scenarios

Reverse proxies sit between clients and your FastAPI application:

```
Client → Reverse Proxy → FastAPI App
```

The proxy may:

* Terminate SSL/TLS (serve HTTPS while talking to your app over HTTP)
* Add a path prefix (serve your app at `/api/v1` instead of `/`)
* Forward headers about the original request

<Info>
  Without proper configuration, your FastAPI app won't know about the original request's protocol, host, or path.
</Info>

## Root Path

When your app is mounted at a path prefix, use the `root_path` parameter:

### Reading Root Path from Request

```python theme={null}
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/app")
def read_main(request: Request):
    return {
        "message": "Hello World",
        "root_path": request.scope.get("root_path")
    }
```

### Setting Root Path in Application

```python theme={null}
from fastapi import FastAPI, Request

app = FastAPI(root_path="/api/v1")

@app.get("/app")
def read_main(request: Request):
    return {
        "message": "Hello World",
        "root_path": request.scope.get("root_path")
    }
```

Now the app expects to be accessed at `/api/v1/app` instead of just `/app`.

<Tip>
  The `root_path` affects the OpenAPI schema URL. Your docs will be at `/api/v1/docs` instead of `/docs`.
</Tip>

## Configuring with Servers

Define alternative server URLs in the OpenAPI schema:

```python theme={null}
from fastapi import FastAPI, Request

app = FastAPI(
    servers=[
        {"url": "https://stag.example.com", "description": "Staging environment"},
        {"url": "https://prod.example.com", "description": "Production environment"},
    ],
    root_path="/api/v1",
)

@app.get("/app")
def read_main(request: Request):
    return {
        "message": "Hello World",
        "root_path": request.scope.get("root_path")
    }
```

This configuration:

* Shows multiple server options in the docs
* Sets the path prefix to `/api/v1`
* Allows users to test against different environments

### Controlling Root Path in Servers

By default, `root_path` is included in server URLs. To disable this:

```python theme={null}
from fastapi import FastAPI, Request

app = FastAPI(
    servers=[
        {"url": "https://stag.example.com", "description": "Staging environment"},
        {"url": "https://prod.example.com", "description": "Production environment"},
    ],
    root_path="/api/v1",
    root_path_in_servers=False,  # Don't add root_path to server URLs
)

@app.get("/app")
def read_main(request: Request):
    return {
        "message": "Hello World",
        "root_path": request.scope.get("root_path")
    }
```

## Nginx Configuration

### Basic Proxy Setup

```nginx theme={null}
server {
    listen 80;
    server_name example.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Prefix /;
    }
}
```

### Proxy with Path Prefix

```nginx theme={null}
server {
    listen 80;
    server_name example.com;

    location /api/v1/ {
        proxy_pass http://127.0.0.1:8000/;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Prefix /api/v1;
    }
}
```

Configure your FastAPI app:

```python theme={null}
app = FastAPI(root_path="/api/v1")
```

### SSL Termination

```nginx theme={null}
server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;  # Important!
        proxy_set_header X-Forwarded-Host $host;
    }
}
```

## Traefik Configuration

```yaml theme={null}
http:
  routers:
    fastapi-router:
      rule: "Host(`example.com`) && PathPrefix(`/api`)"
      service: fastapi-service
      middlewares:
        - fastapi-stripprefix
      tls:
        certResolver: myresolver

  middlewares:
    fastapi-stripprefix:
      stripPrefix:
        prefixes:
          - "/api"

  services:
    fastapi-service:
      loadBalancer:
        servers:
          - url: "http://fastapi:8000"
```

Configure your FastAPI app:

```python theme={null}
app = FastAPI(root_path="/api")
```

## Environment-Based Configuration

Set `root_path` from environment variables:

```python theme={null}
import os
from fastapi import FastAPI

app = FastAPI(
    root_path=os.getenv("ROOT_PATH", ""),
    servers=[
        {
            "url": os.getenv("SERVER_URL", "http://localhost:8000"),
            "description": "Current environment"
        },
    ] if os.getenv("SERVER_URL") else None,
)
```

Run with environment variables:

```bash theme={null}
ROOT_PATH=/api/v1 SERVER_URL=https://api.example.com uvicorn main:app
```

## Docker and Kubernetes

### Docker Compose with Nginx

```yaml theme={null}
version: '3.8'

services:
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - fastapi

  fastapi:
    build: .
    environment:
      - ROOT_PATH=/api/v1
    expose:
      - "8000"
```

### Kubernetes Ingress

```yaml theme={null}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: fastapi-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  rules:
  - host: example.com
    http:
      paths:
      - path: /api(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: fastapi-service
            port:
              number: 8000
```

FastAPI deployment with root path:

```yaml theme={null}
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi
spec:
  replicas: 3
  template:
    spec:
      containers:
      - name: fastapi
        image: myapp:latest
        env:
        - name: ROOT_PATH
          value: "/api"
        ports:
        - containerPort: 8000
```

## Forwarded Headers

Access proxy forwarded headers in your application:

```python theme={null}
from fastapi import FastAPI, Request

app = FastAPI()

@app.get("/headers")
async def get_headers(request: Request):
    return {
        "host": request.headers.get("host"),
        "x-forwarded-for": request.headers.get("x-forwarded-for"),
        "x-forwarded-proto": request.headers.get("x-forwarded-proto"),
        "x-forwarded-host": request.headers.get("x-forwarded-host"),
        "x-real-ip": request.headers.get("x-real-ip"),
        "client_ip": request.client.host,
    }
```

<Warning>
  Be cautious with forwarded headers in security-sensitive applications. Validate that they're coming from trusted proxies to prevent header injection attacks.
</Warning>

## Testing Proxy Configuration

Test your configuration locally:

```python theme={null}
from fastapi import FastAPI, Request
from fastapi.testclient import TestClient

app = FastAPI(root_path="/api/v1")

@app.get("/app")
def read_main(request: Request):
    return {"root_path": request.scope.get("root_path")}

def test_root_path():
    client = TestClient(app, root_path="/api/v1")
    response = client.get("/app")
    assert response.json() == {"root_path": "/api/v1"}
```

## Common Pitfalls

### Incorrect OpenAPI Schema URLs

If docs aren't loading, check the `root_path`:

```python theme={null}
# Wrong: Docs won't work behind /api/v1 proxy
app = FastAPI()

# Correct: Docs work at /api/v1/docs
app = FastAPI(root_path="/api/v1")
```

### Mixed HTTP/HTTPS

Ensure proxies set `X-Forwarded-Proto` correctly:

```nginx theme={null}
# In Nginx config
proxy_set_header X-Forwarded-Proto $scheme;
```

### Missing Host Headers

```nginx theme={null}
# Always set the Host header
proxy_set_header Host $host;
```

## Best Practices

<Note>
  * Always set `root_path` when behind a proxy with a path prefix
  * Configure proxies to forward `X-Forwarded-*` headers
  * Use environment variables for deployment-specific configuration
  * Test OpenAPI docs to verify proxy configuration
  * Implement proper logging to track the original client IP
  * Use SSL/TLS termination at the proxy for better performance
  * Validate forwarded headers come from trusted sources
</Note>

## Health Checks

Configure health check endpoints for load balancers:

```python theme={null}
from fastapi import FastAPI

app = FastAPI(root_path="/api/v1")

@app.get("/health")
async def health_check():
    return {"status": "healthy"}

@app.get("/ready")
async def readiness_check():
    # Check database, cache, etc.
    return {"status": "ready"}
```

## See Also

* [Custom Middleware](/advanced/middleware) - Create custom middleware
* [CORS](/advanced/cors) - Configure cross-origin requests
* [Deployment](/deployment) - Deploy FastAPI applications
* [Security](/security) - Security best practices
