Nginxについて調べたことをまとめました

2022/07/17に公開

業務で nginx を扱う機会があったので、思考整理のためにまとめてみます。

nginxを扱った背景

本業の方で、旧ドメインからのリダイレクト処理を AWS の LoadBalancer を用いてリダイレクト処理をしていました。

しかし、旧ドメインのパスパラメータを一部削除したり、一部を連結したりと柔軟なリダイレクト対応が必要となったことから、LoadBalancer では対応が厳しくなりました。

そこで、リダイレクト処理を実現するため、EC2 を新たに立て、nginx の web サーバーを用い、そこからリダイレクト処理をできるように設計を見直したということです。

nginxとは

Web サーバーといえば、Apache と nginx が有名ですが、その違いは駆動方式にあります。

Apache→マルチプロセスのプロセス駆動アーキテクチャを採用しています。このアーキテクチャでは、各リクエストをプロセスに割り当てて処理を行います。

そのため、リクエストが一度に大量に来てしまうと、プロセスの起動が不可に耐えることができない状態になり、複数処理にあまり向いておりません。

しかし、簡易的なセットアップが可能で、導入をしやすいメリットもあります。

nginx→シングルスレッドモデルのイベント駆動アーキテクチャを採用しています。これにより、シングルスレッドでのループ処理を実行するため、少量のプロセスだけで大量のリクエストを処理することが可能となります。

導入方法

ここからは Ubuntu に nginx を導入する手順について説明していきます。

まずは、パッケージ情報を更新し、nginx をインストールします。

$ sudo apt update
$ sudo apt install nginx

インストールにより、nginx が起動するため、起動されていることを確認します。

$ systemctl status nginx

下記で有効にしておくことで、常に起動した状態にしておけます。

$ sudo systemctl enable nginx

nginx.confについて

リダイレクトを設定するにあたり、nginx.conf の設定を理解する必要があります。

nginx.conf は、 /etc/nginx/nginx.confにあります。

基本系は下記のようになってます。

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }
}

まず、http{} や server{}や location{}などは、ディレクティブと呼ばれる基本的な構成要素となります。

ブロック{}内の記述はそのブロック内でのみ有効となります。その範囲をコンテキストと呼びます。

ディレクティブによってどのコンテキストが使えるかが決まっています。

幾つかピックアップしてご紹介いたします。

mainコンテキスト

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

主に nginx 全体に関わる設定を記載しています。

まず、実行ユーザーを nginx としています。(Debian 系列だと www-data にするのが慣習としてあるそう...)

その他エラーログの格納ファイルの表示や PID を出力する PID ファイルのパスを指定します。

serverコンテキスト

ここでサーバーとしての設定がいろいろ書かれております。

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  _;
        root         /usr/share/nginx/html;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }

listen ディレクティブは、使用する IP アドレスやポートを指定しています。

default_server とすると、それがデフォルトサーバーとして認識されます。

server_name ディレクティブは、ホスト名を指定します。server_name _;とすることで、catch_all を意味しています。

ちなみに、server は複数記述が可能で、仮想サーバーとして動作します。

http{
    server{
        server_name alpha.example.com;
    }
    server{
        server_name bravo.example.com;
    }
}

root ディレクティブは、ドキュメントルートを指定します。つまり、その Web サーバーにおけるツリー構造の最上部となるディレクトリですね。

include ディレクティブは、nginx.conf を別ファイルに分け、そこに設定を記述することが可能となります。

location はリダイレクトの説明で使用するため、一旦飛ばします。

error_page ディレクティブは、エラーが起きた際のページを指定しています。

この場合、404 エラーが発生した場合、40.html を表示するようにしています。

リダイレクトの設定

今回、リダイレクトの設定を server コンテキスト内の location ディレクティブで実施します。

locationの記述例

まず前提知識として、location は並列して書かれている場合、どれかひとつだけヒットするような仕組みになっております。

どれが適用されるかについては演算子によります。

演算子 内容
= 完全一致
^~ 前方一致(正規表現より優先度が上)
~ 正規表現(大文字と小文字区別あり)
~* 正規表現(大文字と小文字区別なし)
なし 前方一致(正規表現より優先度が下)

^~と「演算子なし」は正規表現に対する優先順位が異なります。

前方一致が2種類ありますが、これは「^~ は省略可能」という意味ではありません。

location の難しいポイントは、書かれた順に評価される設定と、最長一致で評価される設定が混在していることです。

特に、優先順位をややこしくしているのが ^~ の存在です。

location はいろいろな記述が可能ですので、下記に例を示しました。

server {
    index index.html index.htm;
    location = /  {   # config A
        root  /usr/local/www/nginx;
    }
    location / {      # config B
        root  /usr/local/www/nginx/root;
    }
}

完全一致の「/」であれば configA にヒットしますが、index によって、内部で「/index.html」にリダイレクトします。

そうなると、2 つ目の configB にヒットします。

server {
    # ルートへの完全一致
    location = / {
        [ configuration A ]
    }

    # /images/ 以下の画像
    location ~ ^/images/ {
        [ configuration D ]
    }

    # /images/ 以外に置かれた画像
    location ~* \.(gif|jpg|jpeg)$ {
        [ configuration E ]
    }

    # /documents/ 以下のページ
    location /documents/ {
        [ configuration C ]
    }

    # その他すべてのページ
    location / {
        [ configuration B ]
    }
}

マッチによる優先順位

先ほどから記載しておりますが、表現方法で優先順位が異なります。

location = / {
  # conf A
}

この時は「/」のみが条件に一致し、以降のチェックは無視されるようになります。

location / {
  # conf B
}

これは「/」で始まる全ての URL に一致します。

しかしながら、正規表現や文字列が長いものは優先で処理されます。

location /documentes/ {
  # conf C
}

この時は、「/documentes/」で始まる全ての URL に一致します。

しかし、注意なのはこの後も正規表現のチェックは処理されます。

つまり、正規表現のチェックで一致しなかった時だけ一致したと判断されます。

location ^~ /images/ {
  # conf D
}

これは、「/images/」で始まる全ての URL に一致したらそこで検索終了となります。

ここで一致したら以降のチェックは実行されません。

まとめ

まだまだ使いこなすのには時間がかかりそうです...。

GitHubで編集を提案

Discussion