Reverse Proxy

Intermediate
Infrastructure

A reverse proxy sits in front of backend servers and forwards client requests to them — providing SSL termination, caching, compression, rate limiting, and shielding internal server topology from external clients.

Overview

A forward proxy acts on behalf of clients (VPN, corporate internet filtering). A reverse proxy acts on behalf of servers — clients send requests to the proxy's IP/domain, and the proxy decides which backend to contact. Nginx and HAProxy are the dominant open-source reverse proxies. In cloud architectures, reverse proxies appear as API Gateways, CDN edge nodes, and Ingress Controllers in Kubernetes. A reverse proxy decouples the client from backend topology: you can add, remove, or replace backends without clients noticing.

Forward Proxy vs Reverse Proxy

The key distinction is whose behalf the proxy acts on. A forward proxy is configured by clients — often transparent to servers. A reverse proxy is configured by server operators — often transparent to clients.

Forward proxy vs reverse proxy
// Forward Proxy (client-side):
// Client ──▶ [Forward Proxy] ──▶ Internet
// Use cases:
//   - Corporate internet filtering (block social media, log traffic)
//   - Anonymisation (hide client IP from servers)
//   - VPN/tunnelling (bypass geo-restrictions)
// Server sees: proxy's IP, not client's IP

// Reverse Proxy (server-side):
// Client ──▶ [Reverse Proxy] ──▶ Backend Server(s)
// Use cases:
//   - SSL termination
//   - Load balancing (Nginx upstream)
//   - Caching static content
//   - Rate limiting and security
//   - Serve multiple apps on one IP (virtual hosts)
// Client sees: proxy's domain (aicancode.org), not backend's internal IP (10.0.1.5)

// Virtual hosting (multiple apps, one IP/port):
// nginx:
server { server_name api.aicancode.org;  proxy_pass http://api_backend; }
server { server_name www.aicancode.org;  proxy_pass http://nextjs_backend; }

Nginx as Reverse Proxy

Nginx is event-driven and handles tens of thousands of concurrent connections with minimal memory. Its reverse proxy configuration proxies requests to upstream backends while adding headers, enabling caching, and buffering responses.

Nginx production reverse proxy configuration
# Nginx reverse proxy — full production config
upstream nextjs_app {
  server 127.0.0.1:3000;
  keepalive 32;             # keep connections to backend alive
}

server {
  listen 443 ssl http2;
  server_name aicancode.org www.aicancode.org;

  ssl_certificate     /etc/letsencrypt/live/aicancode.org/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/aicancode.org/privkey.pem;

  # Security headers
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;

  # Compression
  gzip on;
  gzip_types text/plain application/json application/javascript text/css;

  location / {
    proxy_pass http://nextjs_app;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;         # pass real client IP
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_read_timeout 60s;
    proxy_buffering on;
  }

  # Cache static assets at edge
  location ~* \.(js|css|png|jpg|woff2)$ {
    proxy_pass http://nextjs_app;
    proxy_cache_valid 200 30d;
    add_header Cache-Control "public, max-age=2592000, immutable";
  }
}

# HTTP → HTTPS redirect
server { listen 80; return 301 https://$host$request_uri; }

Caching at the Reverse Proxy

A reverse proxy can cache backend responses — serving subsequent identical requests directly without hitting the backend. This dramatically reduces origin load for read-heavy endpoints. Cache keys are typically based on URL + selected headers. Cache invalidation must be considered: either TTL-based or explicit purge.

Nginx proxy cache configuration
# Nginx proxy cache config:
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m
                 max_size=1g inactive=60m use_temp_path=off;

server {
  location /api/v1/courses {
    proxy_cache api_cache;
    proxy_cache_key "$scheme$request_method$host$request_uri";
    proxy_cache_valid 200 5m;            # cache 200 responses for 5 minutes
    proxy_cache_valid 404 1m;
    proxy_cache_bypass $http_x_no_cache; # bypass cache if header set
    add_header X-Cache-Status $upstream_cache_status;  # HIT / MISS / BYPASS
    proxy_pass http://api_backend;
  }

  # Purge cache on deploy (nginx-cache-purge module):
  location ~ /purge(/.*) {
    allow 127.0.0.1;
    deny all;
    proxy_cache_purge api_cache "$scheme$request_method$host$1";
  }
}

Key Points to Remember

  • 1A reverse proxy decouples client-facing endpoints from internal backend topology — backends can change without affecting clients.
  • 2Nginx handles tens of thousands of concurrent connections with minimal memory using an event-driven, non-blocking architecture.
  • 3Always pass X-Forwarded-For and X-Real-IP headers so backends know the actual client IP, not the proxy's IP.
  • 4Proxy-level caching reduces backend load for read-heavy endpoints — combine with immutable Cache-Control headers for static assets.
  • 5Kubernetes Ingress Controllers (nginx-ingress, Traefik) are reverse proxies that route cluster-external traffic to services.

Interview Questions

Sign in to ask Aria
1

What is the difference between a forward proxy and a reverse proxy?

EasyTCS
2

Why do you need to pass X-Forwarded-For when using a reverse proxy?

MediumThoughtWorks
3

How does Nginx serve multiple domains/apps from a single IP and port?

MediumInfosys
4

How would you implement caching at the reverse proxy level and when should you invalidate it?

MediumRazorpay
5

What is a Kubernetes Ingress Controller and how does it relate to a reverse proxy?

MediumAmazon

Ask Aria about Reverse Proxy

Your personal AI tutor — ask anything about this concept

Revision Status

Personal Notes

Sign in to save personal notes for this topic.

Discussion

Sign in to join the discussion.

Loading discussion…