KAHIBARO
Discord Login Register

22.4. Reverse Proxies

What Is a Reverse Proxy?

A reverse proxy is a server that sits in front of one or more backend applications and receives all incoming client requests first. It then decides where to send those requests and passes the responses back to the client.

From the browser’s point of view, there is only one server: the reverse proxy. Your FastAPI, Django, or Node app sits behind it and is invisible to the outside world.

A very common setup:

text
Client (Browser)
        |
        v
  Reverse Proxy (e.g. Nginx)
        |
        v
  Application Server (e.g. Uvicorn/Gunicorn)

You will almost always use a reverse proxy in production.

Key idea: A reverse proxy receives requests on behalf of your backend, forwards them to the right internal service, and returns the response. It is the public entry point to your backend.

Reverse Proxy vs Forward Proxy

A forward proxy (often just called "proxy") sits in front of clients. A reverse proxy sits in front of servers.

FeatureForward ProxyReverse Proxy
Sits in front ofClientsServers / backend apps
Typical usersCompany employees, home usersWebsites, APIs, production systems
Main purposeHide client, filter outbound trafficProtect and manage backend servers
Client configurationClients must be configured to use itClients do not know it exists
ExamplesCorporate proxy, VPN proxyNginx, Traefik, HAProxy as entry to backend

Example of forward proxy usage:

Example of reverse proxy usage:

Why Use a Reverse Proxy in Backend Development?

You could run your FastAPI app directly on port 80, but in production this is almost never recommended. A reverse proxy gives you many benefits.

Security Benefits

A reverse proxy acts as a shield for your application servers.

Some security-related advantages:

Performance and Scalability Benefits

A reverse proxy can optimize traffic and reduce load on your backend.

Common features:

Operational Benefits

Managing production systems is easier with a reverse proxy.

In practice: In production, always place your Python application server (Uvicorn, Gunicorn) behind a reverse proxy such as Nginx or Traefik.

Typical Reverse Proxy Architecture

Let us see a usual small production setup for a FastAPI app:

text
Internet
   |
   v
[Firewall]
   |
   v
[Reverse Proxy: Nginx]  <– listens on :80 and :443
   |
   v
[App Server: Uvicorn / Gunicorn]  <– listens on 127.0.0.1:8000

Flow of a request:

  1. Browser sends GET https://api.example.com/items.
  2. DNS points api.example.com to the IP of the server running Nginx.
  3. Nginx terminates TLS and sees the HTTP request.
  4. Nginx has a rule like “for /api/ send to http://127.0.0.1:8000”.
  5. Uvicorn receives GET /items and returns a JSON response.
  6. Nginx forwards that response back to the client.

Example: Basic Nginx Reverse Proxy Configuration

Imagine you have a FastAPI app running with Uvicorn on localhost:8000. You want to expose it on https://api.example.com.

A minimal Nginx configuration snippet could look like:

nginx
server {
    listen 80;
    server_name api.example.com;
    # Redirect HTTP to HTTPS
    return 301 https://$host$request_uri;
}
server {
    listen 443 ssl;
    server_name api.example.com;
    # TLS configuration (simplified)
    ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;
    location / {
        proxy_pass         http://127.0.0.1:8000;
        proxy_http_version 1.1;
        # Important headers for WebSockets and many app servers
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        # Preserve original client info
        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 $scheme;
    }
}

What this does:

Preserving Client Information

By default, if Nginx listens publicly and your app runs on localhost, your app sees every request as coming from 127.0.0.1. To fix that, you rely on forwarded headers.

Common headers to set:

HeaderMeaning
X-Real-IPClient IP address
X-Forwarded-ForChain of IPs the request passed through
X-Forwarded-ProtoOriginal protocol, http or https
HostOriginal host the client requested

In application code, many frameworks know how to interpret these headers if configured properly.

Path-Based and Host-Based Routing

A reverse proxy can decide where to send a request based on:

  1. Host name
    Route api.example.com to one backend and admin.example.com to another.
  2. Path prefix
    Route /api/ to the API, /static/ to static files.

Examples:

Host-Based Routing

nginx
server {
    listen 80;
    server_name api.example.com;
    location / {
        proxy_pass http://127.0.0.1:8000; # FastAPI
    }
}
server {
    listen 80;
    server_name admin.example.com;
    location / {
        proxy_pass http://127.0.0.1:9000; # Admin app
    }
}

Path-Based Routing

nginx
server {
    listen 80;
    server_name example.com;
    location /api/ {
        proxy_pass http://127.0.0.1:8000/;
    }
    location /static/ {
        root /var/www/example;  # Serves /var/www/example/static/*
    }
    location / {
        proxy_pass http://127.0.0.1:9000/; # Frontend app
    }
}

This way, multiple services can share a single domain.

Load Balancing with a Reverse Proxy

A reverse proxy can distribute traffic across multiple backend instances. This improves reliability and sometimes performance.

Suppose you run three instances of your FastAPI app:

You can define an upstream in Nginx:

nginx
upstream fastapi_backend {
    server 127.0.0.1:8001;
    server 127.0.0.1:8002;
    server 127.0.0.1:8003;
}
server {
    listen 80;
    server_name api.example.com;
    location / {
        proxy_pass http://fastapi_backend;
    }
}

Nginx will send requests to each backend using a load balancing algorithm (default is round robin).

Benefits:

Reverse Proxy and HTTPS Termination

In production, your API should be served over HTTPS. Managing certificates in every service is painful. A reverse proxy simplifies this.

TLS termination flow:

  1. Client connects with HTTPS to the reverse proxy.
  2. Reverse proxy handles TLS handshake with the client.
  3. Decrypted HTTP request is forwarded to your app over the internal network, usually plain HTTP.
  4. Response returns the same path, and the proxy sends encrypted data back to the client.

This is called TLS termination or SSL termination.

Advantages:

Health Checks and Failover

A reverse proxy can monitor backend health.

Concepts:

In some reverse proxies, you can configure custom health-check endpoints and intervals. This is common in load balancers provided by cloud providers and in advanced reverse proxies.

Some systems combine:

Reverse Proxy vs Application Server

Your Python application server (for example Uvicorn, Gunicorn, Uvicorn workers behind Gunicorn) and your reverse proxy are different roles.

ComponentRole
Application serverRuns your Python app, executes code, handles business logic
Reverse proxyManages incoming HTTP(S) traffic, routing, TLS, caching, balancing

Why not expose Uvicorn directly?

This is why you typically use both:

text
Client -> Reverse Proxy (Nginx/Traefik) -> Application Server (Uvicorn/Gunicorn) -> App

Simple Reverse Proxy Example with Traefik (Conceptual)

Traefik is another popular reverse proxy, often used with Docker. A simple idea:

Example docker-compose fragment:

yaml
services:
  reverse-proxy:
    image: traefik:v2.10
    command:
      - "--providers.docker=true"
      - "--entrypoints.web.address=:80"
    ports:
      - "80:80"
    volumes:
      - "/var/run/docker.sock:/var/run/docker.sock:ro"
  fastapi:
    image: my-fastapi-image
    labels:
      - "traefik.enable=true"
      - "traefik.http.routers.fastapi.rule=Host(`api.example.com`)"
      - "traefik.http.services.fastapi.loadbalancer.server.port=8000"

Here, Traefik:

Common Pitfalls When Using Reverse Proxies

Beginners often run into similar problems.

1. Wrong Host or Scheme in the Application

Symptoms:

Cause:

Fix:

2. Large Request Bodies Rejected

Symptoms:

Cause:

Fix:

3. Missing WebSocket Support

Symptoms:

Cause:

Fix:

nginx
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

in the WebSocket location block.

Summary

A reverse proxy is a central building block of production backend systems. It:

As you move from development to production, learning how to configure and reason about reverse proxies like Nginx or Traefik is essential for running reliable, secure backend applications.

Views: 7

Comments

Please login to add a comment.

Don't have an account? Register now!