バックエンド開発の経験があれば、「フォワードプロキシ」と「リバースプロキシ」という用語をどこかで聞いたことがあるかもしれません。
そのため、今日はそれらについて「概要と用途」を詳しく説明させていただきます。
フォワードプロキシ (Forward Proxy)
フォワードプロキシまたは単純なプロキシは、クライアントとインターネットの間にある仲介者です。
ざっくりにはこんな感じです。
サーバーがある場合
そして、サーバーに直接接続する代わりに、クライアントはプロキシ経由でサーバーに接続し、クライアントに代わってプロキシがサーバーとやりとりするということになります。
さて、「プロキシの目的は何ですか?」と自問があるでしょうか。
簡単に言うと、それらは次となります。
① facebook.com や 18+ サイトなどの特定のサイトへのアクセスを制限する。
② クライアントがサイト全体ではなく、一部のみにアクセスできるようにする (リソースアクセスを制限する)。
③ インターネットでの活動を記録する。
...
リバースプロキシ (Reverse Proxy)
リバースプロキシは、インターネットとサーバーの間にある仲介者です。
一旦こんな感じです。
では、リバースプロキシの目的は何でしょうか。
これはサーバーを表します。つまり、「リバースプロキシ」はクライアントからのリクエストを受け取り、それをサーバーに送信し、サーバーからのレスポンスを受け取り、それをクライアントに送信します。下記の画像はイメージです。
「リバースプロキシ」はサーバーの代表であるため、クライアントはサーバーと通信していることを認識せず、リバースプロキシと通信していることを認識しているだけです。
じゃ、リバースプロキシの目的とはどのようなものでしょうか。
まあ、それは次のようにリストすることができます。
① サーバーを公開したくない場合、「リバースプロキシ」は、クライアントからサーバーを非表示にするための最良の選択です。
② 「リバースプロキシ」はサーバーの前にあるため、ロードバランシングとして機能して、システムに複数のサーバーがある場合クライアントからサーバーにリクエストを均等に分散できます。
...
コンセプトは十分なので、デモを見てみましょう。 まず、フォワードプロキシで確認します。 ここでは、次のように「フォワードプロキシ」経由でhttp://google.com
に接続するクライアントを作成します。
JavaScriptライブラリrequest
を使用してプロキシ経由でhttp://google.com
にリクエストを送信するクライアントをセットアップします。
※ ライブラリのリンク先: https://www.npmjs.com/package/request
// index.js
const request = require('request');
request({
url: 'http://www.google.com/',
method: 'GET',
proxy: 'http://127.0.0.1:8888',
}, (err, response, body) => {
if (!err && response.statusCode === 200) {
console.log(body);
}
});
nginx を次のように設定します。
events {}
http {
server {
listen 8888 default_server;
access_log log/access.log; #アクセスログ
error_log log/error.log debug; #エラーログ
location / {
resolver 8.8.8.8;
proxy_pass https://$host$request_uri;
}
}
}
上のnginx設定の意味はnginxがローカルホストのポート8888でリッスンして、リクエストがhttp://localhost:8888/
に来るたびに、リクエストはhttps://$host$request_uri
に転送されます。ここでは
-
$host
は、リクエストヘッダー内のホストの名前です (今回はgoole.com
です)。 -
$request_uri
はホスト名の後のURIです。(例:google.com/status
の場合、$request_uri
は/status
です)
まず、クライアントを起動する
node index.js
次にnginxのログを確認してみましょう。
プロキシがクライアントに代わってリクエストをgoogle.com
に送信することがわかります。 プロキシはgoogle.com
からの応答を受け取り、それをクライアントに送り返します。
フォワードプロキシについてはここまで以上です。
リバースプロキシなんですが、次のように、それぞれexpressJS
によってポート1111
、2222
、および3333
でリッスンする3つのサーバーを作っておきます。
サーバー1 (ポート1111でリッスンする)
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Server 1\n');
});
app.listen(1111, () => {
console.log('Listening on port 1111');
});
サーバー2 (ポート2222でリッスンする)
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Server 2\n');
});
app.listen(2222, () => {
console.log('Listening on port 2222');
});
サーバー3 (ポート3333でリッスンする)
const express = require('express');
const app = express();
app.get('/', (req, res) => {
res.send('Server 3\n');
});
app.listen(3333, () => {
console.log('Listening on port 3333');
});
そして、nginxの設定は次のとおりです。
events {}
http {
upstream express_servers {
server localhost:1111;
server localhost:2222;
server localhost:3333;
}
server {
listen 8888;
location / {
proxy_pass http://express_servers;
}
}
}
nginxの設定について説明します。ここで、nginxはローカルホストのポート8888でリッスンし、http://localhost:8888/
へのすべてのリクエストは、express_servers
リスト (Server1、Server2、Server3)の3つのサーバーのいずれかに転送されます。
ここで使用されるデフォルトのリクエストローテーションアルゴリズムはラウンドロビンです。
これは、各サーバーに対応するサーバーの重みに基づいて、サーバーへのリクエストをローテーションするアルゴリズムです。 重みが高いほど、リクエストを受信する頻度が高くなり、その逆も同様です。 デフォルトでは、全サーバーの重みは同じです。
「リバースプロキシ」が意図したとおりに動作するかどうかを確認するには、下記のコマンドを使ってみてください。
while sleep1; do curl http://localhost:8888; done
上記のコマンドは定期的にcurl http://localhost:8888
コマンドをリバースプロキシに対して毎秒実行します。下は我々の結果なんです。
リクエストはそれぞれ Server1、Server2、および Server3にルーティングされています。
リバースプロキシについては以上です。
読んでくれてありがとうございます。次のブログにお会いしましょう。