Topic Overview

Proxy vs Reverse Proxy

Understand the difference between forward proxies (client-side) and reverse proxies (server-side), their use cases, and when to use each.

Proxies act as intermediaries between clients and servers. Forward proxies represent clients, while reverse proxies represent servers. Understanding the difference is crucial for network architecture and security.


Forward Proxy (Client-Side Proxy)

Definition: A forward proxy sits between clients and the internet, representing clients to servers.

Direction: Client → Proxy → Internet

Client          Forward Proxy        Internet
  |                    |                  |
  |---Request--------->|                  |
  |                    |---Request------->|
  |                    |<--Response-------|
  |<--Response---------|                  |

Characteristics:

  • Client knows proxy: Client is configured to use proxy
  • Server doesn't know client: Server sees proxy's IP, not client's
  • Hides client identity: Client IP is hidden from servers
  • Client-side: Located near clients or in client network

Reverse Proxy (Server-Side Proxy)

Definition: A reverse proxy sits between the internet and servers, representing servers to clients.

Direction: Internet → Reverse Proxy → Servers

Internet        Reverse Proxy        Backend Servers
  |                    |                  |
  |---Request--------->|                  |
  |                    |---Request------->|
  |                    |<--Response-------|
  |<--Response---------|                  |

Characteristics:

  • Client doesn't know backend: Client thinks it's talking to reverse proxy
  • Server knows proxy: Backend servers see proxy's IP
  • Hides server identity: Backend server IPs are hidden from clients
  • Server-side: Located in front of servers

Key Differences

AspectForward ProxyReverse Proxy
LocationClient-sideServer-side
RepresentsClientsServers
Client awarenessClient knows proxyClient doesn't know backend
Server awarenessServer doesn't know clientServer knows proxy
HidesClient IP from serversServer IPs from clients
Use casePrivacy, filtering, cachingLoad balancing, SSL termination, security

Forward Proxy Use Cases

1. Privacy and Anonymity

Hide client IP addresses from servers.

Client (192.168.1.100) → Proxy (203.0.113.1) → Server
Server sees: 203.0.113.1 (proxy's IP)
Server doesn't see: 192.168.1.100 (client's IP)

2. Content Filtering

Block access to certain websites.

Client → Proxy → Internet
Proxy checks: Is website allowed?
If blocked: Return error
If allowed: Forward request

3. Caching

Cache frequently accessed content.

Client → Proxy → Internet
Proxy checks: Is content cached?
If cached: Return from cache
If not: Fetch from internet, cache, return

4. Bypass Restrictions

Access content restricted by location.

Client (Country A) → Proxy (Country B) → Server
Server sees: Proxy in Country B
Client can access: Content available in Country B

Reverse Proxy Use Cases

1. Load Balancing

Distribute requests across multiple backend servers.

Client → Reverse Proxy → Backend Servers
                      ├─ Server 1
                      ├─ Server 2
                      └─ Server 3

2. SSL Termination

Terminate SSL/TLS at reverse proxy.

Client (HTTPS) → Reverse Proxy (decrypts) → Backend (HTTP)

3. Caching

Cache responses from backend servers.

Client → Reverse Proxy → Backend
         (cached response)

4. Security

Hide backend server IPs, provide DDoS protection.

Client → Reverse Proxy (public IP) → Backend (private IP)

5. Request Routing

Route requests to different backend services.

Client → Reverse Proxy → /api/users → user-service
                      → /api/orders → order-service

Examples

Forward Proxy (Squid)

# Squid forward proxy configuration
http_port 3128

# Access control
acl local_net src 192.168.1.0/24
http_access allow local_net
http_access deny all

# Caching
cache_dir ufs /var/spool/squid 100 16 256
cache_mem 256 MB

# Logging
access_log /var/log/squid/access.log

Client configuration:

# Set proxy in browser or environment
export http_proxy=http://proxy.example.com:3128
export https_proxy=http://proxy.example.com:3128

Reverse Proxy (Nginx)

# Nginx reverse proxy configuration
upstream backend {
    server 192.168.1.10:8080;
    server 192.168.1.11:8080;
    server 192.168.1.12:8080;
}

server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    # SSL termination
    listen 443 ssl;
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
}

Forward Proxy Implementation

from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.request

class ForwardProxyHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        # Get target URL from request
        target_url = self.path
        
        # Forward request to target
        try:
            response = urllib.request.urlopen(target_url)
            
            # Send response to client
            self.send_response(200)
            self.send_header('Content-Type', response.headers.get('Content-Type'))
            self.end_headers()
            self.wfile.write(response.read())
        except Exception as e:
            self.send_error(500, str(e))
    
    def log_message(self, format, *args):
        # Log client IP (hidden from target server)
        print(f"Client {self.client_address[0]} requested {args[0]}")

# Start forward proxy server
server = HTTPServer(('0.0.0.0', 8080), ForwardProxyHandler)
server.serve_forever()

Reverse Proxy Implementation

from http.server import HTTPServer, BaseHTTPRequestHandler
import requests
from urllib.parse import urlparse

class ReverseProxyHandler(BaseHTTPRequestHandler):
    backend_servers = [
        'http://192.168.1.10:8080',
        'http://192.168.1.11:8080',
        'http://192.168.1.12:8080'
    ]
    current_server = 0
    
    def do_GET(self):
        # Select backend server (round robin)
        backend = self.backend_servers[self.current_server]
        self.current_server = (self.current_server + 1) % len(self.backend_servers)
        
        # Forward request to backend
        try:
            target_url = f"{backend}{self.path}"
            response = requests.get(target_url, headers=dict(self.headers))
            
            # Send response to client
            self.send_response(response.status_code)
            for header, value in response.headers.items():
                self.send_header(header, value)
            self.end_headers()
            self.wfile.write(response.content)
        except Exception as e:
            self.send_error(502, str(e))

# Start reverse proxy server
server = HTTPServer(('0.0.0.0', 80), ReverseProxyHandler)
server.serve_forever()

Common Pitfalls

  • Confusing forward and reverse: Not understanding which represents what. Fix: Forward = client-side, Reverse = server-side
  • Not handling X-Forwarded-For: Backend doesn't know real client IP. Fix: Set X-Forwarded-For header
  • SSL termination issues: Backend expects HTTPS but receives HTTP. Fix: Configure backend for HTTP when using SSL termination
  • Session affinity: Requests not routed to same backend. Fix: Use sticky sessions (cookie-based or IP-based)
  • Health checks: Not monitoring backend health. Fix: Implement health checks, remove unhealthy backends
  • Caching issues: Stale content served. Fix: Set appropriate cache headers, implement cache invalidation

Interview Questions

Beginner

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

A:

Forward Proxy (Client-Side):

  • Location: Between clients and internet
  • Represents: Clients to servers
  • Client awareness: Client knows proxy (configured to use it)
  • Server awareness: Server doesn't know real client (sees proxy's IP)
  • Hides: Client IP from servers
  • Use case: Privacy, content filtering, caching, bypass restrictions

Reverse Proxy (Server-Side):

  • Location: Between internet and servers
  • Represents: Servers to clients
  • Client awareness: Client doesn't know backend servers
  • Server awareness: Backend servers see proxy's IP
  • Hides: Backend server IPs from clients
  • Use case: Load balancing, SSL termination, security, caching

Example:

Forward Proxy:
  Client → Proxy → Internet
  (Client knows proxy, server doesn't know client)

Reverse Proxy:
  Internet → Proxy → Backend Servers
  (Client doesn't know backend, backend knows proxy)

Intermediate

Q: When would you use a forward proxy vs a reverse proxy? Explain with examples.

A:

Use Forward Proxy When:

  1. Privacy/Anonymity

    # Hide client IP from servers
    Client (192.168.1.100) → Proxy → Server
    Server sees: Proxy's IP, not client's IP
    
  2. Content Filtering

    # Corporate network: Block social media
    Client → Proxy → Internet
    Proxy checks: Is website allowed?
    If blocked: Deny access
    
  3. Caching

    # Cache frequently accessed content
    Client → Proxy → Internet
    If cached: Return from cache (fast)
    If not: Fetch, cache, return
    
  4. Bypass Geo-restrictions

    # Access content from different country
    Client (US) → Proxy (UK) → Server
    Server sees: UK IP, serves UK content
    

Use Reverse Proxy When:

  1. Load Balancing

    # Distribute requests across servers
    Client → Reverse Proxy → Backend Servers
                           ├─ Server 1
                           ├─ Server 2
                           └─ Server 3
    
  2. SSL Termination

    # Terminate SSL at proxy
    Client (HTTPS) → Reverse Proxy (decrypts) → Backend (HTTP)
    
  3. Security

    # Hide backend IPs, DDoS protection
    Client → Reverse Proxy (public) → Backend (private)
    
  4. Request Routing

    # Route to different services
    /api/users → user-service
    /api/orders → order-service
    

Key Difference:

  • Forward Proxy: Client-side, hides client from servers
  • Reverse Proxy: Server-side, hides servers from clients

Senior

Q: Design a proxy architecture for a large organization that needs both forward proxies for employee internet access and reverse proxies for internal services. How do you handle scaling, security, and monitoring?

A:

class EnterpriseProxyArchitecture {
  private forwardProxies: ForwardProxy[];
  private reverseProxies: ReverseProxy[];
  private securityLayer: SecurityLayer;
  private monitoring: MonitoringSystem;
  
  constructor() {
    // Forward proxies for employee internet access
    this.forwardProxies = [
      new ForwardProxy({ region: 'us-east' }),
      new ForwardProxy({ region: 'us-west' }),
      new ForwardProxy({ region: 'eu-west' })
    ];
    
    // Reverse proxies for internal services
    this.reverseProxies = [
      new ReverseProxy({ tier: 'web' }),
      new ReverseProxy({ tier: 'api' }),
      new ReverseProxy({ tier: 'internal' })
    ];
    
    this.securityLayer = new SecurityLayer();
    this.monitoring = new MonitoringSystem();
  }
  
  // Forward Proxy Architecture
  class ForwardProxy {
    private cache: Cache;
    private filter: ContentFilter;
    private auth: Authentication;
    
    async handleRequest(request: ClientRequest): Promise<Response> {
      // 1. Authentication
      const user = await this.auth.authenticate(request);
      if (!user) {
        return this.deny(401);
      }
      
      // 2. Content Filtering
      if (!this.filter.isAllowed(request.url, user)) {
        return this.deny(403, 'Content blocked');
      }
      
      // 3. Caching
      const cached = await this.cache.get(request.url);
      if (cached) {
        return cached;
      }
      
      // 4. Forward to internet
      const response = await this.forwardToInternet(request);
      
      // 5. Cache response
      if (this.cache.shouldCache(response)) {
        await this.cache.set(request.url, response);
      }
      
      return response;
    }
  }
  
  // Reverse Proxy Architecture
  class ReverseProxy {
    private loadBalancer: LoadBalancer;
    private sslTerminator: SSLTerminator;
    private healthMonitor: HealthMonitor;
    
    async handleRequest(request: InternetRequest): Promise<Response> {
      // 1. SSL Termination
      if (request.isHTTPS()) {
        request = await this.sslTerminator.terminate(request);
      }
      
      // 2. Security Checks
      if (!this.securityLayer.isAllowed(request)) {
        return this.deny(403);
      }
      
      // 3. Route to backend
      const backend = await this.loadBalancer.select(request);
      
      // 4. Health check
      if (!this.healthMonitor.isHealthy(backend)) {
        // Try next backend
        backend = await this.loadBalancer.selectNext(request);
      }
      
      // 5. Forward to backend
      const response = await backend.handle(request);
      
      // 6. Add headers
      response.setHeader('X-Proxy', 'reverse-proxy');
      
      return response;
    }
  }
  
  // Security Layer
  class SecurityLayer {
    async isAllowed(request: Request): Promise<boolean> {
      // DDoS protection
      if (await this.isDDoS(request)) {
        return false;
      }
      
      // Rate limiting
      if (await this.isRateLimited(request)) {
        return false;
      }
      
      // WAF (Web Application Firewall)
      if (await this.waf.isBlocked(request)) {
        return false;
      }
      
      return true;
    }
  }
  
  // Monitoring
  class MonitoringSystem {
    async monitor(): Promise<Metrics> {
      return {
        forwardProxy: {
          requests: await this.getForwardProxyMetrics(),
          cacheHitRate: await this.getCacheHitRate(),
          blockedRequests: await this.getBlockedRequests()
        },
        reverseProxy: {
          requests: await this.getReverseProxyMetrics(),
          backendHealth: await this.getBackendHealth(),
          latency: await this.getLatency()
        }
      };
    }
  }
}

Architecture:

Internet Access (Forward Proxy):
  Employees → Forward Proxies → Internet
            (Filtering, Caching, Privacy)

Internal Services (Reverse Proxy):
  Internet → Reverse Proxies → Internal Services
           (Load Balancing, SSL, Security)

Features:

  1. Forward proxies: Employee internet access with filtering and caching
  2. Reverse proxies: Internal service exposure with load balancing
  3. Security: DDoS protection, WAF, rate limiting
  4. Monitoring: Track metrics, health, performance
  5. Scaling: Multiple proxies per region/tier
  6. High availability: Redundancy, failover

Key Takeaways

  • Forward Proxy: Client-side, represents clients, hides client IP from servers
  • Reverse Proxy: Server-side, represents servers, hides server IPs from clients
  • Forward proxy use cases: Privacy, content filtering, caching, bypass restrictions
  • Reverse proxy use cases: Load balancing, SSL termination, security, request routing
  • Key difference: Forward = client knows proxy, Reverse = client doesn't know backend
  • Implementation: Use appropriate headers (X-Forwarded-For), handle SSL termination, implement health checks
  • Best practices: Monitor performance, implement security layers, use caching appropriately, ensure high availability

About the author

InterviewCrafted helps you master system design with patience. We believe in curiosity-led engineering, reflective writing, and designing systems that make future changes feel calm.