こんにちは、キクです。
先日、初めてリバースプロキシの構築を行いました。
本記事では、その復習も兼ねて「Nginxを用いたリバースプロキシの構築方法」について整理していこうと思います。
それでは、よろしくお願いします。
リバースプロキシとは
リバースプロキシは、クライアント(ユーザー)からのリクエストを受け取り、適切なバックエンドサーバーに転送する役割を持つサーバーです。
主な特徴としては以下のようなものが挙げられます。
1. リクエストの仲介
クライアントは直接バックエンドサーバーにアクセスせず、リバースプロキシを介してアクセスする
2. セキュリティ向上
バックエンドサーバーを外部から隠し、不正アクセスや攻撃を防ぐ
3. 負荷分散
複数のバックエンドサーバーへのリクエストを均等に分配して、負荷を分散する
4. キャッシュ機能
静的コンテンツ(画像やCSSファイルなど)をキャッシュすることで、バックエンドの負担を軽減し、レスポンス速度を向上させる
5. SSLオフロード
SSL/TLS通信をリバースプロキシで終了させることで、バックエンドの負荷を減らす
今回の構成
今回は「リバースプロキシ」ということで、接続元クライアントとWebサーバとの間にリバースプロキシを挟んだ以下のような構成になります。
本記事では「test.example.com」というFQDNを用いて接続を行いますが、DNS設定については触れませんのでご了承ください。
また、通常バックエンドサーバは複数台で構成されることから、今回の作業でも一応は2台構成にしています。
ただし、本記事としては複数台での設定方法を明記できればOKなので、動作確認等では2台目は停止しているものとして扱います。
作業1. Nginx導入
本項では、本記事のテーマである「リバースプロキシ」を動作させるためのNginxを導入していきます。
1. Nginxをインストール
root@rp-host:~# apt install nginx
2. Nginxの起動/自動起動設定
root@rp-host:~# systemctl start nginx
root@rp-host:~# systemctl enabled nginx
作業2. リバースプロキシとしての設定追加
本項では、先ほどインストールしたNginxサーバをリバースプロキシとして稼働させるための設定を行っていきます。
1. デフォルトのバーチャルホスト設定ファイルへのシンボリックリンクを削除
root@rp-host:~# ls /etc/nginx/sites-enabled/
total 8
drwxr-xr-x 2 root root 4096 Dec 20 11:11 .
drwxr-xr-x 8 root root 4096 Dec 20 11:11 ..
lrwxrwxrwx 1 root root 34 Dec 20 11:11 default -> /etc/nginx/sites-available/default
root@rp-host:~# rm /etc/nginx/sites-enabled/default
補足
Nginxのメイン設定ファイル「nginx.conf」には次のようにバーチャルホストの設定として読み込まれるファイル情報が記されています。
http {
~中略~
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
本手順で削除したシンボリックリンクの親ディレクトリ「sites-enabled」配下のファイルもその一部であることが分かります。
先ほどの作業では、これを削除して後続の手順で新たにバーチャルホストの設定ファイルをシンボリックリンクとして追加していきます。
2. 新規バーチャルホスト設定ファイルの作成
root@rp-host:~# vi /etc/nginx/sites-available/test.example.com
# Reverse proxy configuration
upstream backend_servers {
server 192.168.1.21;
server 192.168.1.22;
}
server {
listen 80;
server_name test.example.com;
location / {
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
3. 上記ファイルへの有効なシンボリックリンクを作成
root@rp-host:~# ln -s /etc/nginx/sites-available/test.example.com /etc/nginx/sites-enabled/
補足
先ほど、nginx.confにて「/etc/nginx/sites-enabled/*」という記載があることは確認しましたが、「/etc/nginx/sites-available」は含まれていませんでした。
従って、本手順にもある通り「/etc/nginx/sites-enabled」へのシンボリックリンクを作成することではじめて設定として有効化されます。
4. 構文チェック
root@rp-host:~# nginx -t
[出力例]
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
5. サービス再起動
root@rp-host:~# systemctl restart nginx.service
6. 動作確認
6-1. クライアント#1(192.168.1.51)からcurlコマンドで以下のURLに接続できることを確認
root@client01:~# curl http://test.example.com
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Test Page</title>
</head>
<body>
<h1>Test Page</h1>
<pre style="font-family: monospace;">
######## ####### ####### ########
## ## ## ##
## ## ## ##
## ###### ###### ##
## ## ## ##
## ## ## ##
## ####### ####### ##
</pre>
</body>
</html>
想定通り、Webサーバで公開しているindex.htmlの情報を取得できました。
6-2. アクセスログ確認
リバプロ側(192.168.1.10)
192.168.1.51 - - [27/Dec/2024:10:58:16 +0900] "GET / HTTP/1.1" 200 537 "-" "curl/7.81.0"
接続元がクライアント#1(192.168.1.51)であり、ステータスコード200(正常)が返されていることが分かります。
備忘録
項目 | 説明 |
---|---|
192.168.1.51 | 接続元クライアントのIPアドレス |
-(1個目) | 認証ユーザ名(認証が必要な場合に記載される) |
-(2個目) | 識別子(通常は記録されない) |
[27/Dec/2024:10:58:16 +0900] | リクエストの受信日時 |
"GET / HTTP/1.1" | GET:使用されたHTTPメソッド / :リクエストされたリソース(ルートパス、ホームページなど) HTTP/1.1:使用されたHTTPプロトコルのバージョン |
200 | HTTPステータスコード |
537 | サーバがクライアントに返したレスポンスのサイズ(バイト単位) |
“-” | 参照元URL(リファラー) |
“curl/7.81.0” | クライアントのソフトウェア情報 今回はcurl(バージョン7.81.0)が使用されてリクエストが送信されたことを示す |
バックエンド側(192.168.1.21)
192.168.1.10 - - [27/Dec/2024:10:58:16 +0900] "GET / HTTP/1.0" 200 537 "-" "curl/7.81.0"
バックエンド側は接続元がリバースプロキシ(192.168.1.10)になっており、ステータスコードは同様に200(正常)が返されていることが分かります。
「リバースプロキシで受けてバックエンドに流す」という想定通りの挙動を確認できました。
作業3. アクセス制御(ACL)の設定追加
本項では、アクセス制御を行うためにACLの設定を実施していきます。
具体的には、クライアント#2(192.168.1.52)からの接続は拒否し、その他の接続は許可するようにしていきます。
1. バーチャルホスト設定ファイルにACL情報を追記
root@rp-host:~# vi /etc/nginx/sites-available/test.example.com
# Reverse proxy configuration
upstream backend_servers {
server 192.168.1.21;
server 192.168.1.22;
}
server {
listen 80;
server_name test.example.com;
location / {
deny 192.168.1.52;
allow all;
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
2. 構文チェック
root@rp-host:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
3. サービス再起動
root@rp-host:~# systemctl restart nginx.service
4. 動作確認
4-1. クライアント#1(192.168.1.51)からの接続
root@client01:~# curl http://test.example.com
リバプロ側(192.168.1.10)
192.168.1.51 - - [27/Dec/2024:11:08:22 +0900] "GET / HTTP/1.1" 200 537 "-" "curl/7.81.0"
バックエンド側(192.168.1.21)
192.168.1.10 - - [27/Dec/2024:11:08:22 +0900] "GET / HTTP/1.0" 200 537 "-" "curl/7.81.0"
4-2. クライアント#2(192.168.1.52)からの接続
root@client02:~# curl https://test.example.com
<html>
<head><title>403 Forbidden</title></head>
<body>
<center><h1>403 Forbidden</h1></center>
<hr><center>nginx/1.24.0 (Ubuntu)</center>
</body>
</html>
-> アクセス拒否に成功(403)
リバプロ側(192.168.1.10)
192.168.1.52 - - [27/Dec/2024:11:09:34 +0900] "GET / HTTP/1.1" 403 162 "-" "curl/7.81.0"
バックエンド側(192.168.1.21)
未到達のためアクセスログなし
作業4. SSLオフロード設定
1. SSL証明書(.crt)および鍵ファイル(.key)の設置
root@rp-host:~# mkdir /etc/nginx/ssl
以下のファイルを上記ディレクトリにアップロード
補足
中間証明書(例:intermediate.crt)が存在する場合は、以下のようなコマンドで結合する
root@rp-host:/etc/nginx/ssl# cat server.crt intermediate.crt > /etc/nginx/ssl/fullchain.crt
備忘録
上記コマンドで結合されたファイルにおいて、結合部分が以下のように1行になっていたので別途改行した
改行前
-----BEGIN CERTIFICATE-----
~SSL証明書~
-----END CERTIFICATE----------BEGIN CERTIFICATE-----
~中間証明書~
-----END CERTIFICATE-----
改行後
-----BEGIN CERTIFICATE-----
~SSL証明書~
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
~中間証明書~
-----END CERTIFICATE-----
2. バーチャルホスト設定ファイルの修正
root@rp-host:~# vi /etc/nginx/sites-available/test.example.com
# Reverse proxy configuration
upstream backend_servers {
server 192.168.1.21;
server 192.168.1.22;
}
server {
listen 443 ssl;
server_name test.example.com;
# SSL証明書ファイルを指定
ssl_certificate /etc/nginx/ssl/server.crt;
# 秘密鍵を指定
ssl_certificate_key /etc/nginx/ssl/server.key;
# SSL詳細設定(適宜)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
location / {
deny 192.168.1.52;
allow all;
proxy_pass http://backend_servers;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
# HTTPリクエストを受けた場合にHTTPSにリダイレクトする設定
server {
listen 80;
server_name test.example.com;
return 301 https://$host$request_uri;
}
3. 構文チェック
root@rp-host:~# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
4. サービス再起動
root@rp-host:~# systemctl restart nginx.service
5. 動作確認
5-1. HTTPS接続
root@client01:~# curl https://test.example.com
リバプロ側(192.168.1.10)
192.168.1.51 - - [27/Dec/2024:11:16:52 +0900] "GET / HTTP/1.1" 200 537 "-" "curl/7.81.0"
バックエンド側(192.168.1.21)
192.168.1.10 - - [27/Dec/2024:11:16:52 +0900] "GET / HTTP/1.0" 200 537 "-" "curl/7.81.0"
5-2. HTTP接続
root@client01:~# curl http://test.example.com
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.24.0 (Ubuntu)</center>
</body>
</html>
備忘録
301 Moved Permenently
リクエストされたリソースの URL が永遠に変更されたことを示す。
レスポンスで新しい URL が与えられる。
ちなみに、「新しいURL」はオプションとして「-v」を入れることで「Location: 」として見れる模様。
root@client01:~# curl -v http://test.example.com
* Trying 192.168.1.10:80...
* Connected to test.example.com (192.168.1.10) port 80 (#0)
> GET / HTTP/1.1
~中略~
< Content-Length: 178
< Connection: keep-alive
< Location: https://test.example.com/
~省略~
リバプロ側(192.168.1.10)
192.168.1.51 - - [27/Dec/2024:11:24:43 +0900] "GET / HTTP/1.1" 301 178 "-" "curl/7.81.0"
バックエンド側(192.168.1.21)
ログなし
メモ
curlでリダイレクトとなった場合、バックエンド側までは通信しない模様?
オプション「-L」を付けるとリダイレクト先まで接続しに行く模様
HTTP接続(オプション-L あり)
root@client01:~# curl -L http://test.example.com
リバプロ側(192.168.1.10)
192.168.1.51 - - [27/Dec/2024:11:27:13 +0900] "GET / HTTP/1.1" 301 178 "-" "curl/7.81.0"
バックエンド側(192.168.1.21)
192.168.1.10 - - [27/Dec/2024:11:27:13 +0900] "GET / HTTP/1.0" 200 537 "-" "curl/7.81.0"
6. 追加確認
6-1. バックエンドへの直接接続(HTTP)
root@client01:~# curl http://192.168.1.11
バックエンド(192.168.1.21)
192.168.1.51 - - [27/Dec/2024:20:05:45 +0900] "GET / HTTP/1.1" 200 537 "-" "curl/7.81.0"
6-2. バックエンドへの直接接続(HTTPS)
root@client01:~# curl <https://192.168.1.11>
curl: (7) Failed to connect to 192.168.1.11 port 443 after 12 ms: Connection refused
バックエンド(192.168.1.21)
未到達のためログなし
まとめ
今回はNginxを用いたリバースプロキシの構築方法について整理しました。
改めて、本記事では以下の内容に取り組みました。
本記事を最後まで読んでいただき、ありがとうございました。
ではでは!