Reverse Proxy and Load Balancing

Level: Advanced Module: Web Services 12 min read Lesson 26 of 66

Overview

  • What you’ll learn: Reverse proxy concepts, configuring Nginx as a reverse proxy, upstream directives, load balancing algorithms (round-robin, least_conn, ip_hash), health checks, and proxy headers (X-Forwarded-For, X-Real-IP).
  • Prerequisites: Module 3 — Lessons 21–25 (HTTP Fundamentals, Apache2, Nginx, TLS/HTTPS, PHP Deployment)
  • Estimated reading time: 18 minutes

Introduction

A reverse proxy is a server that sits between client devices and one or more backend servers, forwarding client requests to the appropriate backend and returning the backend’s response to the client. Unlike a forward proxy (which acts on behalf of clients), a reverse proxy acts on behalf of servers. This architecture is fundamental to modern web infrastructure, enabling load distribution, SSL termination, caching, and security isolation.

Load balancing extends the reverse proxy concept by distributing incoming requests across multiple backend servers. This ensures no single server becomes a bottleneck, improves fault tolerance, and enables horizontal scaling. When one backend server fails, the load balancer automatically routes traffic to the remaining healthy servers, providing high availability without client-side intervention.

In this lesson, you will learn the theory behind reverse proxies and load balancing, then implement these patterns using Nginx on Ubuntu Server. You will configure upstream groups, explore different load balancing algorithms, set up health checks, and properly forward client information through proxy headers.

Reverse Proxy Concepts

In a traditional web architecture, clients connect directly to a web server that processes requests and returns responses. A reverse proxy introduces an intermediary layer: clients connect to the proxy, which then forwards the request to one or more backend servers. The client is unaware of the backend servers — it only communicates with the proxy.

This architecture provides several benefits:

  • Security: Backend servers are hidden from the public Internet. Only the reverse proxy needs a public IP address, reducing the attack surface.
  • SSL Termination: The proxy handles TLS encryption and decryption, offloading this CPU-intensive task from backend servers.
  • Caching: The proxy can cache responses from backends, reducing load and improving response times for repeated requests.
  • Compression: The proxy can compress responses before sending them to clients, reducing bandwidth usage.
  • Centralized Logging: All access logs are consolidated at the proxy, simplifying monitoring and analysis.

The basic Nginx configuration for a reverse proxy uses the proxy_pass directive within a location block:

# /etc/nginx/sites-available/reverse-proxy.conf
server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

# Enable the site
$ sudo ln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl reload nginx

The proxy_pass directive tells Nginx to forward all requests matching the location to the specified backend address. The proxy_set_header directives ensure the backend receives the original client information rather than the proxy’s own address.

Upstream Directive and Load Balancing Algorithms

When you have multiple backend servers, Nginx’s upstream directive groups them into a named pool. The proxy_pass directive then references this pool instead of a single backend address. This is the foundation of load balancing in Nginx.

# /etc/nginx/conf.d/upstream-app.conf
upstream app_backends {
    # Default: round-robin (requests distributed sequentially)
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_backends;
        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;
    }
}

Nginx supports several load balancing algorithms, each suited to different use cases:

  • Round-Robin (default): Requests are distributed sequentially across the backend servers. Server 1 gets the first request, server 2 the second, server 3 the third, then back to server 1. This is the simplest and most commonly used method.
  • Least Connections (least_conn): Requests are sent to the server with the fewest active connections. This is ideal when request processing times vary significantly — slower requests won’t cause one server to become overloaded.
  • IP Hash (ip_hash): The client’s IP address is used to determine which server receives the request. The same client always reaches the same backend, providing session persistence (sticky sessions). This is useful for applications that store session data locally.
  • Weighted: Servers can be assigned different weights to receive a proportional share of traffic. Higher-capacity servers receive more requests.
# Least connections algorithm
upstream app_least {
    least_conn;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

# IP hash algorithm (sticky sessions)
upstream app_sticky {
    ip_hash;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

# Weighted round-robin
upstream app_weighted {
    server 10.0.1.10:8080 weight=5;   # receives 5x more traffic
    server 10.0.1.11:8080 weight=3;   # receives 3x more traffic
    server 10.0.1.12:8080 weight=1;   # baseline
}

Health Checks and Server Parameters

In a production load balancing environment, backend servers may fail or become unresponsive. Nginx provides passive health checking by default: if a connection to a backend fails, Nginx marks it as unavailable and temporarily stops sending requests to it. You can control this behavior with server parameters.

upstream app_backends {
    least_conn;

    # max_fails: number of failed attempts before marking unavailable
    # fail_timeout: time period for max_fails AND how long to wait before retrying
    server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;

    # Backup server — only receives traffic when all primary servers are down
    server 10.0.1.99:8080 backup;

    # Mark a server as permanently offline for maintenance
    # server 10.0.1.10:8080 down;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_backends;

        # Timeout settings for proxied requests
        proxy_connect_timeout 5s;
        proxy_send_timeout 10s;
        proxy_read_timeout 30s;

        # Retry on specific error conditions
        proxy_next_upstream error timeout http_502 http_503 http_504;
        proxy_next_upstream_tries 3;

        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;
    }
}

The max_fails parameter sets how many consecutive failures are allowed before a server is marked as unavailable. The fail_timeout parameter serves a dual purpose: it defines the time window in which max_fails must occur, and also how long the server stays unavailable before Nginx tries it again. The proxy_next_upstream directive defines which error conditions trigger a retry on the next server.

Proxy Headers: X-Forwarded-For and X-Real-IP

When a reverse proxy forwards requests, the backend server sees the proxy’s IP address as the client address, not the original client’s IP. This is problematic for logging, access control, and geolocation. Proxy headers solve this by passing the original client information through the proxy chain.

  • X-Real-IP: Contains the IP address of the original client. Set by the first proxy in the chain.
  • X-Forwarded-For: A comma-separated list of IP addresses showing the full proxy chain. Each proxy appends the address of the previous hop.
  • X-Forwarded-Proto: Indicates the original protocol (http or https) used by the client, essential when TLS is terminated at the proxy.
  • X-Forwarded-Host: The original Host header sent by the client.
# Complete reverse proxy configuration with headers
server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

    location / {
        proxy_pass http://app_backends;

        # Forward original client information
        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;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;

        # WebSocket support (if needed)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";

        # Buffering settings
        proxy_buffering on;
        proxy_buffer_size 4k;
        proxy_buffers 8 4k;
    }
}

# Backend application: configure to trust proxy headers
# Example for Apache backend — enable remoteip module
$ sudo a2enmod remoteip
# In Apache config:
# RemoteIPHeader X-Forwarded-For
# RemoteIPTrustedProxy 10.0.1.0/24

The $proxy_add_x_forwarded_for variable automatically appends the client’s IP to any existing X-Forwarded-For header, correctly handling multi-proxy chains. Backend applications must be configured to trust and read these headers for accurate client identification.

Key Takeaways

  • A reverse proxy sits between clients and backend servers, providing security, SSL termination, caching, and centralized logging.
  • Nginx’s upstream directive groups backend servers into a pool, and proxy_pass distributes requests across them.
  • Load balancing algorithms — round-robin, least_conn, ip_hash, and weighted — suit different workload patterns and session requirements.
  • Passive health checks with max_fails and fail_timeout automatically remove failed backends from the pool and retry after a cooldown period.
  • Proxy headers (X-Real-IP, X-Forwarded-For, X-Forwarded-Proto) preserve original client information through the proxy chain and must be trusted by backend applications.

What’s Next

In Lesson 27, you will learn about Squid Proxy Server, covering forward proxy concepts, installation and configuration of Squid on Ubuntu, access control lists (ACLs), cache management, and proxy authentication.

繁體中文

概述

  • 學習目標:反向代理概念、將 Nginx 設定為反向代理、upstream 指令、負載平衡演算法(round-robin、least_conn、ip_hash)、健康檢查及代理標頭(X-Forwarded-For、X-Real-IP)。
  • 先決條件:模組 3 — 第 21–25 課(HTTP 基礎、Apache2、Nginx、TLS/HTTPS、PHP 部署)
  • 預計閱讀時間:18 分鐘

簡介

反向代理是位於用戶端裝置和一個或多個後端伺服器之間的伺服器,它將用戶端請求轉發到適當的後端,並將後端的回應返回給用戶端。與正向代理(代表用戶端行動)不同,反向代理代表伺服器行動。這種架構是現代 Web 基礎設施的基礎,可實現負載分配、SSL 終止、快取和安全隔離。

負載平衡擴展了反向代理的概念,將傳入的請求分配到多個後端伺服器。這確保沒有單一伺服器成為瓶頸,提高容錯能力,並實現水平擴展。當一個後端伺服器故障時,負載平衡器會自動將流量路由到其餘健康的伺服器,在無需用戶端介入的情況下提供高可用性。

在本課程中,您將學習反向代理和負載平衡背後的理論,然後在 Ubuntu Server 上使用 Nginx 實作這些模式。您將設定 upstream 群組、探索不同的負載平衡演算法、設定健康檢查,並透過代理標頭正確轉發用戶端資訊。

反向代理概念

在傳統的 Web 架構中,用戶端直接連接到處理請求並返回回應的 Web 伺服器。反向代理引入了一個中介層:用戶端連接到代理,代理再將請求轉發到一個或多個後端伺服器。用戶端不知道後端伺服器的存在——它只與代理通訊。

這種架構提供了多項優勢:

  • 安全性:後端伺服器對公共網際網路隱藏。只有反向代理需要公共 IP 位址,減少了攻擊面。
  • SSL 終止:代理處理 TLS 加密和解密,將此 CPU 密集型任務從後端伺服器卸載。
  • 快取:代理可以快取後端的回應,減少負載並改善重複請求的回應時間。
  • 壓縮:代理可以在發送給用戶端之前壓縮回應,減少頻寬使用。
  • 集中化日誌:所有存取日誌集中在代理處,簡化監控和分析。
# /etc/nginx/sites-available/reverse-proxy.conf
server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

# 啟用站點
$ sudo ln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl reload nginx

Upstream 指令與負載平衡演算法

當您有多個後端伺服器時,Nginx 的 upstream 指令將它們分組到一個命名池中。然後 proxy_pass 指令引用此池而不是單一後端位址。這是 Nginx 中負載平衡的基礎。

# /etc/nginx/conf.d/upstream-app.conf
upstream app_backends {
    # 預設:round-robin(請求按順序分配)
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_backends;
        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;
    }
}

Nginx 支援多種負載平衡演算法,每種都適合不同的使用場景:

  • Round-Robin(預設):請求按順序分配到後端伺服器。這是最簡單且最常用的方法。
  • 最少連線(least_conn):請求發送到活動連線最少的伺服器。當請求處理時間差異很大時非常理想。
  • IP 雜湊(ip_hash):使用用戶端的 IP 位址來決定哪個伺服器接收請求。同一用戶端始終到達同一後端,提供會話持久性(黏性會話)。
  • 加權:可以為伺服器分配不同的權重以接收成比例的流量份額。
# 最少連線演算法
upstream app_least {
    least_conn;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

# IP 雜湊演算法(黏性會話)
upstream app_sticky {
    ip_hash;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

# 加權 round-robin
upstream app_weighted {
    server 10.0.1.10:8080 weight=5;   # 接收 5 倍流量
    server 10.0.1.11:8080 weight=3;   # 接收 3 倍流量
    server 10.0.1.12:8080 weight=1;   # 基準
}

健康檢查與伺服器參數

在生產負載平衡環境中,後端伺服器可能會故障或變得無回應。Nginx 預設提供被動健康檢查:如果與後端的連線失敗,Nginx 會將其標記為不可用並暫時停止向其發送請求。

upstream app_backends {
    least_conn;

    # max_fails:標記為不可用之前允許的失敗次數
    # fail_timeout:max_fails 的時間段以及重試前的等待時間
    server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;

    # 備用伺服器——僅在所有主要伺服器都停機時接收流量
    server 10.0.1.99:8080 backup;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_backends;

        # 代理請求的逾時設定
        proxy_connect_timeout 5s;
        proxy_send_timeout 10s;
        proxy_read_timeout 30s;

        # 在特定錯誤條件下重試
        proxy_next_upstream error timeout http_502 http_503 http_504;
        proxy_next_upstream_tries 3;

        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;
    }
}

代理標頭:X-Forwarded-For 與 X-Real-IP

當反向代理轉發請求時,後端伺服器看到的是代理的 IP 位址而非原始用戶端的 IP。這對於日誌記錄、存取控制和地理定位是有問題的。代理標頭透過在代理鏈中傳遞原始用戶端資訊來解決此問題。

  • X-Real-IP:包含原始用戶端的 IP 位址。由鏈中的第一個代理設定。
  • X-Forwarded-For:以逗號分隔的 IP 位址列表,顯示完整的代理鏈。
  • X-Forwarded-Proto:指示用戶端使用的原始協定(http 或 https)。
  • X-Forwarded-Host:用戶端發送的原始 Host 標頭。
# 具有完整標頭的反向代理設定
server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

    location / {
        proxy_pass http://app_backends;

        # 轉發原始用戶端資訊
        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;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;

        # WebSocket 支援(如需要)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

# 後端應用程式:設定信任代理標頭
$ sudo a2enmod remoteip

重點摘要

  • 反向代理位於用戶端和後端伺服器之間,提供安全性、SSL 終止、快取和集中化日誌。
  • Nginx 的 upstream 指令將後端伺服器分組為池,proxy_pass 在它們之間分配請求。
  • 負載平衡演算法——round-robin、least_conn、ip_hash 和加權——適合不同的工作負載模式和會話需求。
  • 透過 max_failsfail_timeout 的被動健康檢查會自動從池中移除故障後端並在冷卻期後重試。
  • 代理標頭(X-Real-IP、X-Forwarded-For、X-Forwarded-Proto)透過代理鏈保留原始用戶端資訊,後端應用程式必須信任這些標頭。

下一步

在第 27 課中,您將學習 Squid 代理伺服器,涵蓋正向代理概念、在 Ubuntu 上安裝和設定 Squid、存取控制清單(ACL)、快取管理和代理認證。

日本語

概要

  • 学習内容:リバースプロキシの概念、Nginx をリバースプロキシとして設定する方法、upstream ディレクティブ、ロードバランシングアルゴリズム(round-robin、least_conn、ip_hash)、ヘルスチェック、プロキシヘッダー(X-Forwarded-For、X-Real-IP)。
  • 前提条件:モジュール 3 — レッスン 21–25(HTTP 基礎、Apache2、Nginx、TLS/HTTPS、PHP デプロイメント)
  • 推定読了時間:18分

はじめに

リバースプロキシは、クライアントデバイスと1つ以上のバックエンドサーバーの間に位置するサーバーで、クライアントのリクエストを適切なバックエンドに転送し、バックエンドのレスポンスをクライアントに返します。フォワードプロキシ(クライアントの代理として動作)とは異なり、リバースプロキシはサーバーの代理として動作します。このアーキテクチャは現代の Web インフラストラクチャの基盤であり、負荷分散、SSL ターミネーション、キャッシュ、セキュリティ分離を実現します。

ロードバランシングはリバースプロキシの概念を拡張し、受信リクエストを複数のバックエンドサーバーに分散します。これにより、単一のサーバーがボトルネックになることを防ぎ、耐障害性を向上させ、水平スケーリングを可能にします。1つのバックエンドサーバーが障害を起こした場合、ロードバランサーは自動的にトラフィックを残りの正常なサーバーにルーティングし、クライアント側の介入なしに高可用性を提供します。

このレッスンでは、リバースプロキシとロードバランシングの背後にある理論を学び、Ubuntu Server 上で Nginx を使用してこれらのパターンを実装します。upstream グループの設定、さまざまなロードバランシングアルゴリズムの探索、ヘルスチェックの設定、プロキシヘッダーによるクライアント情報の適切な転送を行います。

リバースプロキシの概念

従来の Web アーキテクチャでは、クライアントはリクエストを処理してレスポンスを返す Web サーバーに直接接続します。リバースプロキシは中間層を導入します:クライアントはプロキシに接続し、プロキシがリクエストを1つ以上のバックエンドサーバーに転送します。クライアントはバックエンドサーバーの存在を知りません——プロキシとのみ通信します。

このアーキテクチャには以下の利点があります:

  • セキュリティ:バックエンドサーバーは公開インターネットから隠されます。リバースプロキシだけがパブリック IP アドレスを必要とし、攻撃面を削減します。
  • SSL ターミネーション:プロキシが TLS の暗号化と復号を処理し、この CPU 集中型タスクをバックエンドサーバーからオフロードします。
  • キャッシュ:プロキシはバックエンドからのレスポンスをキャッシュし、負荷を軽減して繰り返しリクエストのレスポンス時間を改善できます。
  • 圧縮:プロキシはクライアントに送信する前にレスポンスを圧縮し、帯域幅使用量を削減できます。
  • 集中ログ:すべてのアクセスログがプロキシに集約され、モニタリングと分析が簡素化されます。
# /etc/nginx/sites-available/reverse-proxy.conf
server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://127.0.0.1:8080;
        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;
    }
}

# サイトを有効化
$ sudo ln -s /etc/nginx/sites-available/reverse-proxy.conf /etc/nginx/sites-enabled/
$ sudo nginx -t
$ sudo systemctl reload nginx

Upstream ディレクティブとロードバランシングアルゴリズム

複数のバックエンドサーバーがある場合、Nginx の upstream ディレクティブはそれらを名前付きプールにグループ化します。proxy_pass ディレクティブは単一のバックエンドアドレスの代わりにこのプールを参照します。

# /etc/nginx/conf.d/upstream-app.conf
upstream app_backends {
    # デフォルト:round-robin(リクエストを順番に分配)
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_backends;
        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;
    }
}

Nginx は複数のロードバランシングアルゴリズムをサポートしています:

  • Round-Robin(デフォルト):リクエストはバックエンドサーバーに順番に分配されます。最もシンプルで一般的に使用される方法です。
  • 最少接続数(least_conn):アクティブな接続数が最も少ないサーバーにリクエストが送信されます。リクエスト処理時間が大きく異なる場合に最適です。
  • IP ハッシュ(ip_hash):クライアントの IP アドレスを使用してどのサーバーがリクエストを受け取るかを決定します。同じクライアントは常に同じバックエンドに到達し、セッション永続性(スティッキーセッション)を提供します。
  • 重み付け:サーバーに異なる重みを割り当てて、トラフィックの比例配分を受け取ることができます。
# 最少接続数アルゴリズム
upstream app_least {
    least_conn;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

# IP ハッシュアルゴリズム(スティッキーセッション)
upstream app_sticky {
    ip_hash;
    server 10.0.1.10:8080;
    server 10.0.1.11:8080;
    server 10.0.1.12:8080;
}

# 重み付き round-robin
upstream app_weighted {
    server 10.0.1.10:8080 weight=5;   # 5倍のトラフィックを受信
    server 10.0.1.11:8080 weight=3;   # 3倍のトラフィックを受信
    server 10.0.1.12:8080 weight=1;   # 基準
}

ヘルスチェックとサーバーパラメータ

本番のロードバランシング環境では、バックエンドサーバーが障害を起こしたり応答しなくなる場合があります。Nginx はデフォルトでパッシブヘルスチェックを提供します:バックエンドへの接続が失敗すると、Nginx はそれを使用不可としてマークし、一時的にリクエストの送信を停止します。

upstream app_backends {
    least_conn;

    # max_fails:使用不可にする前に許可される失敗回数
    # fail_timeout:max_fails の期間および再試行前の待機時間
    server 10.0.1.10:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.11:8080 max_fails=3 fail_timeout=30s;
    server 10.0.1.12:8080 max_fails=3 fail_timeout=30s;

    # バックアップサーバー——すべてのプライマリサーバーがダウンした時のみ使用
    server 10.0.1.99:8080 backup;
}

server {
    listen 80;
    server_name app.example.com;

    location / {
        proxy_pass http://app_backends;

        # プロキシリクエストのタイムアウト設定
        proxy_connect_timeout 5s;
        proxy_send_timeout 10s;
        proxy_read_timeout 30s;

        # 特定のエラー条件でリトライ
        proxy_next_upstream error timeout http_502 http_503 http_504;
        proxy_next_upstream_tries 3;

        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;
    }
}

プロキシヘッダー:X-Forwarded-For と X-Real-IP

リバースプロキシがリクエストを転送する際、バックエンドサーバーはオリジナルクライアントの IP ではなくプロキシの IP アドレスをクライアントアドレスとして認識します。これはロギング、アクセス制御、ジオロケーションにとって問題です。プロキシヘッダーは、プロキシチェーンを通じてオリジナルクライアント情報を渡すことでこの問題を解決します。

  • X-Real-IP:オリジナルクライアントの IP アドレスを含みます。チェーン内の最初のプロキシによって設定されます。
  • X-Forwarded-For:完全なプロキシチェーンを示す、カンマ区切りの IP アドレスリスト。
  • X-Forwarded-Proto:クライアントが使用した元のプロトコル(http または https)を示します。
  • X-Forwarded-Host:クライアントが送信した元の Host ヘッダー。
# ヘッダー付き完全なリバースプロキシ設定
server {
    listen 443 ssl;
    server_name app.example.com;

    ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

    location / {
        proxy_pass http://app_backends;

        # オリジナルクライアント情報を転送
        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;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Port $server_port;

        # WebSocket サポート(必要な場合)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

# バックエンドアプリケーション:プロキシヘッダーを信頼するよう設定
$ sudo a2enmod remoteip

重要ポイント

  • リバースプロキシはクライアントとバックエンドサーバーの間に位置し、セキュリティ、SSL ターミネーション、キャッシュ、集中ログを提供する。
  • Nginx の upstream ディレクティブはバックエンドサーバーをプールにグループ化し、proxy_pass がリクエストを分散する。
  • ロードバランシングアルゴリズム——round-robin、least_conn、ip_hash、重み付け——は異なるワークロードパターンとセッション要件に適する。
  • max_failsfail_timeout によるパッシブヘルスチェックは、障害のあるバックエンドをプールから自動的に削除し、クールダウン期間後にリトライする。
  • プロキシヘッダー(X-Real-IP、X-Forwarded-For、X-Forwarded-Proto)はプロキシチェーンを通じてオリジナルクライアント情報を保持し、バックエンドアプリケーションはこれらのヘッダーを信頼する必要がある。

次のステップ

レッスン 27 では、Squid プロキシサーバーについて学びます。フォワードプロキシの概念、Ubuntu での Squid のインストールと設定、アクセス制御リスト(ACL)、キャッシュ管理、プロキシ認証をカバーします。

You Missed