CDN経由のnginxでLBサーバーを構築し、ユーザーIPを参照して振り分けを行った話

Tech

2023.2.3

Topics

はじめに

こんにちは、マイグレーションチームのwakaです。

nginxを使ってLBサーバーを構築する機会があったのですが、前段にLBやCDNを挟んだ状態でユーザーのIPを参照する要件がやや曲者だったので、備忘録的な感じで残したいと思います。

今回動作確認を行う構成

X-Forwarded-Forの値にいくつかのIPが入った状態をAWSで再現したいため、前段にCloudFrontなどのCDN系のサービスとALBを置いて、一台のEC2をLBサーバーとして設定します。
また、今回の検証ではCloudFrontのキャッシュの設定は無効にしております。

LBサーバーのnginx.confについて

ユーザーIPを変数に格納する処理の追加

http {…} 内にmap {…}を追加します。
以下のように記載すれば$http_x_forwarded_forに入っているIPの中で、1つ目の要素を$clientRealIpに格納させることができます。

map $http_x_forwarded_for $clientRealIp {
    ~^(?P[0-9\.]+),?.*$ $firstAddr;
}

LBサーバーとしての分散処理の追加

http {…} 内にupstream {…} を追加します
hashの値として$clientRealIpを指定します。
これにより、同じIPからのアクセスの場合は同じサーバーに振り分けられます。

upstream backend_server {
    hash $clientRealIp;
    server xx.xxx.xxx.xx;
    server xx.xxx.xx.xxx;
}

後段のサーバーにリクエストを渡す設定の追加

location {…} 内にproxy_pass {…} を追加します

location / {
    proxy_pass http://backend_server;
    proxy_set_header Host $http_host;
    add_header X-Forwarded-For $http_x_forwarded_for;
    add_header clientRealIp $clientRealIp;
}

add_header系を入れておくことで、レスポンスヘッダーに各情報が表示されるようになるため、テストの際に確認しやすくなるかと思います。

動作検証

それぞれのindex.htmlにそれぞれServer1, Server2という文字を入れておき、どちらが表示されたかがわかる形にして検証を行います。
サンプルではpyhtonでGETする際のヘッダーにX-Forwarded-Forの値を指定する/しない場合の分散状況を集計しておりますが、curlなどでも確認可能です。

X-Forwarded-Forに毎回別の値を指定した場合

[waka]% python curl.py
接続先は http://xxxxxxxxxxxxxx.cloudfront.net/ です。
Server1が呼び出された回数は15回です。
Server2が呼び出された回数は15回です。

headerにX-Forwarded-Forの値を設定した場合、$clientRealIpに入るのはX-Forwarded-Forで指定した値となります。
毎回別の新規IPからアクセスが来るという状態になりますので、両方のサーバーへのアクセスが分散されるという形になります。

X-Forwarded-Forの値を設定しない場合

[waka]% python curl.py
接続先は http://xxxxxxxxxxxxxx.cloudfront.net/ です。
Server1が呼び出された回数は0回です。
Server2が呼び出された回数は30回です。

通常のブラウザからのアクセスなど、X-Forwarded-Forの値を設定しなかった場合$clientRealIpに入るのはユーザーIPとなります。
毎回同じIPからアクセスが来るという状態になりますので、今回の設定では片方のサーバーにのみ流れるという形となります。

最後に

間にサーバーが挟まっている状態でもユーザーIPが取得できますので、upstreamに利用するだけでなく、特定のIPのみ表示を変更するといった使い方にも利用できそうです。

waka

2022年に中途入社した人です。好きなAWSサービスはLambdaです。

Recommends

こちらもおすすめ

Special Topics

注目記事はこちら