Lecture 02. Proxies in Distributed Systems
Overview
In this lecture, we explore the critical role of proxies in distributed systems architecture. Proxies serve as intermediaries that facilitate communication between different components, enabling scalability, security, and efficient resource management.
Learning Objectives
- Understand the fundamental concepts of proxies in distributed systems
- Differentiate between forward and reverse proxies
- Master the implementation of Nginx as a reverse proxy for microservices
- Apply proxy patterns to solve real-world distributed systems challenges
Topics Covered
Proxy Fundamentals
- Definition and types of proxies
- Use cases in modern distributed architectures
Reverse Proxies with Nginx
- Configuration and implementation
- Load balancing and routing strategies
- Security enhancements
Practical Applications
The concepts covered in this lecture are essential for:
- Microservice architecture implementation
- API gateway design
- Service mesh infrastructure
- Cloud-native application development
Proxy Fundamentals
🧭 Introduction
Modern distributed systems rely on proxies to manage complexity, enhance security, and improve performance. In microservice architectures, proxies play a crucial role in service discovery, load balancing, and API gateway functionality.
A proxy serves as an intermediary that sits between clients and servers, intercepting and potentially modifying the communication between them. This pattern enables numerous architectural benefits that we'll explore in this lecture.
🛡️ What is a Proxy?
A proxy is an intermediary server that acts on behalf of another entity in a network communication. It intercepts requests, may transform them, and forwards them to the appropriate destination.
Proxies serve several key purposes in distributed systems:
- Abstraction: Hide implementation details of backend services
- Security: Filter traffic and protect backend services
- Performance: Cache responses and optimize data transfer
- Routing: Direct traffic based on content or request patterns
- Monitoring: Log and analyze traffic patterns
🔄 Forward Proxy
A forward proxy acts on behalf of the client. It sits between clients and the wider internet, forwarding client requests to external servers.
Characteristics:
- The client is aware of the proxy and must be configured to use it
- Commonly used for access control, content filtering, and anonymity
- Hides the client's identity from the server
- Often deployed in corporate or educational networks
Key Use Cases:
- Internet access control in organizations
- Content filtering for compliance or security
- Anonymizing client traffic for privacy
- Caching frequently accessed content to improve performance
- Bypassing geo-restrictions on content
🌐 Diagram
INTERNET
|
|
+------------------+ +---------------+ +------------------+
| | | | | |
| Client 1 ----+------->| |------->| Web Server 1 |
| | | | | |
+------------------+ | | +------------------+
| |
+------------------+ | FORWARD | +------------------+
| | | PROXY | | |
| Client 2 ----+------->| |------->| Web Server 2 |
| | | | | |
+------------------+ | | +------------------+
| |
+------------------+ | |
| | | |
| Client 3 ----+------->| |
| | | |
+------------------+ +---------------+
^
|
PRIVATE NETWORK🔍 How Forward Proxies Work
- Client Configuration: The client is explicitly configured to send requests through the proxy
- Request Interception: The proxy receives the client's request
- Policy Enforcement: The proxy applies access control and filtering policies
- Request Forwarding: If allowed, the proxy forwards the request to the destination server
- Response Processing: The proxy receives the server's response, potentially caches it
- Client Delivery: The proxy returns the response to the client
🧠 Key Concepts to Remember
- Forward proxies are client-facing intermediaries
- They require explicit client configuration
- They're excellent for access control and content filtering
- They hide client identity from destination servers
- Common implementations include Squid, TinyProxy, and NGINX (when configured as a forward proxy)
In the next section, we'll explore Reverse Proxies and their critical role in modern microservice architectures.
Reverse Proxy Implementation
🔍 Forward Proxy vs Reverse Proxy
| Feature | Forward Proxy | Reverse Proxy |
|---|---|---|
| Position | Between client and internet | Between internet and backend servers |
| Client Awareness | Configured in client | Transparent to client |
| Used For | Anonymity, content filtering, caching | Load balancing, SSL, routing, caching |
| Hides | Client | Server |
| Example Tools | Squid, TinyProxy | Nginx, HAProxy, Apache HTTPD |
🔄 What is a Reverse Proxy?
A reverse proxy sits in front of one or more backend servers, intercepting requests from clients before they reach the servers. Unlike a forward proxy that acts on behalf of clients, a reverse proxy acts on behalf of servers.
Key Characteristics:
- Transparent to clients: Clients don't need special configuration
- Server-side deployment: Managed by server/infrastructure administrators
- Centralized control: Provides a single entry point to multiple backend services
- Enhanced security: Shields backend servers from direct exposure
Primary Benefits:
- Load Balancing: Distribute traffic across multiple servers
- Security: Hide backend infrastructure and provide WAF capabilities
- SSL Termination: Handle HTTPS encryption/decryption
- Caching: Improve performance by storing common responses
- Compression: Reduce bandwidth usage
- Authentication: Centralize access control
- Monitoring: Unified logging and metrics collection
⚙️ Why Use Nginx in Microservices?
In a microservice architecture, each service runs on a different port or container. Nginx serves as an ideal reverse proxy because it:
- Routes requests to appropriate services based on URL paths
- Centralizes access through a single domain/IP
- Provides caching and compression for improved performance
- Enhances security via rate limiting, SSL, and request filtering
- Offers high performance with low resource consumption
- Supports WebSockets for real-time communication
- Enables blue-green deployments and A/B testing
🌐 Microservices Architecture with Nginx
INTERNET
|
|
▼
+-------------+
| |
| NGINX |
| REVERSE |
| PROXY |
| |
+------+------+
|
+--------------------+--+--+--------------------+
| | | |
▼ ▼ ▼ ▼
+----------------+ +----------------+ +----------------+ +----------------+
| | | | | | | |
| USERS SERVICE | | BOOKS SERVICE | | LOANS SERVICE | | STATIC CONTENT |
| :5001 | | :5002 | | :5003 | | |
| | | | | | | |
+-------+--------+ +-------+--------+ +-------+--------+ +----------------+
| | |
▼ ▼ ▼
+----------------+ +----------------+ +----------------+
| | | | | |
| USERS DB | | BOOKS DB | | LOANS DB |
| | | | | |
+----------------+ +----------------+ +----------------+📦 Example Nginx Configuration
Let's implement a reverse proxy for a microservice architecture with three services:
- Users API at
http://localhost:5001 - Books API at
http://localhost:5002 - Loans API at
http://localhost:5003
Basic Configuration:
# /etc/nginx/nginx.conf or /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name library-app.example.com;
# Access logging
access_log /var/log/nginx/library-app.access.log;
error_log /var/log/nginx/library-app.error.log;
# Users Service
location /api/users/ {
proxy_pass http://localhost:5001/;
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;
}
# Books Service
location /api/books/ {
proxy_pass http://localhost:5002/;
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;
}
# Loans Service
location /api/loans/ {
proxy_pass http://localhost:5003/;
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;
}
# Static content
location / {
root /var/www/html;
try_files $uri $uri/ /index.html;
}
}Understanding the Configuration:
listen 80: Accept HTTP connections on port 80server_name: Domain name for this virtual hostlocation: Route requests based on URL pathproxy_pass: Forward requests to backend servicesproxy_set_header: Pass important headers to backends
🖼️ Architecture Diagram
┌────────────┐
│ Client │
└────┬───────┘
│
▼
┌─────────────┐
│ NGINX │
│ ReverseProxy│
└────┬────────┘
┌────────────┼────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Users API │ │ Books API │ │ Loans API │
│ :5001 │ │ :5002 │ │ :5003 │
└────────────┘ └────────────┘ └────────────┘🔐 Advanced Nginx Capabilities
✅ SSL Termination
Let Nginx handle HTTPS so backend services don't have to:
server {
listen 443 ssl;
server_name library-app.example.com;
ssl_certificate /etc/ssl/certs/library-app.crt;
ssl_certificate_key /etc/ssl/private/library-app.key;
# Modern SSL configuration
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384;
# HSTS (optional)
add_header Strict-Transport-Security "max-age=63072000" always;
location /api/ {
proxy_pass http://localhost:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}✅ Load Balancing
Distribute traffic across multiple instances of the same service:
# Define upstream server groups
upstream users_service {
server 10.0.0.1:5001 weight=3;
server 10.0.0.2:5001 weight=1;
server 10.0.0.3:5001 backup;
}
server {
location /api/users/ {
proxy_pass http://users_service/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}✅ Rate Limiting
Control excessive requests to sensitive routes:
# Define rate limiting zone
limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
server {
# Apply rate limiting to specific endpoints
location /api/loans/checkout {
limit_req zone=api_limit burst=20 nodelay;
proxy_pass http://localhost:5003/checkout;
}
}✅ Caching
Improve performance for static or repeated content:
# Define cache location and settings
proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=api_cache:10m max_size=1g inactive=60m;
server {
# Apply caching to book catalog (read-heavy, change-infrequent)
location /api/books/catalog {
proxy_cache api_cache;
proxy_cache_valid 200 10m;
proxy_cache_key $scheme$host$request_uri;
proxy_pass http://localhost:5002/catalog;
# Add cache status header
add_header X-Cache-Status $upstream_cache_status;
}
}💻 Practical Implementation Steps
Install Nginx:
bashsudo apt update sudo apt install nginxCreate Configuration:
bashsudo nano /etc/nginx/conf.d/library-app.conf # Paste your configuration hereTest Configuration:
bashsudo nginx -tApply Configuration:
bashsudo systemctl reload nginxMonitor Logs:
bashsudo tail -f /var/log/nginx/error.log
🛠️ Troubleshooting Common Issues
| Symptom | Possible Cause | Fix |
|---|---|---|
| 502 Bad Gateway | Backend service not running | Ensure backend is running and port is correct |
| 504 Gateway Timeout | Backend service too slow to respond | Increase proxy_read_timeout value |
| Missing Client IP | Headers not forwarded properly | Add proper proxy_set_header directives |
| Incorrect Routing | Path mismatch in proxy_pass | Check path handling in location blocks |
| SSL Certificate Issues | Certificate misconfiguration | Verify certificate paths and permissions |
| Caching Not Working | Cache configuration incorrect | Check cache keys and paths |
Debugging Commands:
# Check if Nginx is running
systemctl status nginx
# Test configuration syntax
nginx -t
# Check open ports
netstat -tulpn | grep nginx
# Test backend connectivity
curl -v http://localhost:5001/
# Check logs
tail -f /var/log/nginx/error.log🧠 Key Concepts to Remember
- Reverse proxies are server-side intermediaries that clients connect to directly
- They hide backend infrastructure from clients
- They provide centralized control for distributed services
- Nginx excels as a reverse proxy due to its performance and flexibility
- Key capabilities include routing, load balancing, SSL termination, and caching
- Proper header forwarding is essential for microservices to function correctly