ちょっと前までnginxもapacheも意識したことがなかった人がまとめた Nginx入門

この記事はウェブクルー Advent Calendar 2018 の17日目の記事になります。
昨日は @wcsakuraiさんの「[恵比寿のおすすめランチスポットAPIをfinchで書く(scala/finch/circe/refined)](https://qiita.com/wcsakurai/items/b6f9f1b534a6675ddeca)」でした。

## この記事について  
[NGINX入門](http://www2.matsue-ct.ac.jp/home/kanayama/text/nginx/all.html)のまとめのようなもの。
説明はちょっと前の自分が頑張ればわかるくらいに書いてます。
情報が古かったので最近のドキュメントを参照しつつ不要そうなものや古い内容は飛ばしたり新しいものと置き換えたりしています。  
この記事を読めばNginxの概要と主要な機能はわかるかもしれません。  

#### 筆者のレベル感  
情報系の大学出てるけど業務でかかわるまでインフラ苦手だった人。在学中のレベルはこんな感じ↓
「apache? tomcatのやつでしょ、知ってる知ってる（震え声）。xamppとかspring bootとか使うと勝手に立つやつでしょ（震え声）」

リバースプロキシ、nginxもどんなものかは就職してからちゃんと理解しました。
現在は業務でかじり始めたところです。自分と同じくらいなレベルの人を想定してこの記事を書いています。

## 1. 概要  
Nginxとは
イベント駆動方式のサーバ
得意なこと：イベントの高速処理
苦手なこと：重い処理

フロントエンド（Nginx）+ バックエンド（Apache）+ ロードバランス
のように使われることもある。

基本思想
Apache：ファイルの共有可否・共有方法
Nginx ：URL（HTTP要求リクエスト）に対する処理方法  

Nginxはhttpサーバの機能以外に以下のような機能がある。  

```
・アクセス制御
・URI Rewrite
・gzip圧縮
・リバースプロキシ
・L４/L７ロードバランス
・コンテンツキャッシュ
・SSLターミネーション
・HTTP/2ゲートウェイ
・メールプロキシ
```

## 2. 構成  
Nginxはモジュールによって構成されている。モジュールの設定はインストール（コンパイル）時に指定する必要がある。  

- コアモジュール          ：プロセス周りの基本的な機能をもつ。単体では使われない。
  - Core（エラーログ、プロセス、許可、イベント処理など）

- 標準モジュール          ：デフォルトでコンパイルされるモジュール。configure スクリプト（後述）で特定の機能を除外設定できる。
  - HTTP Core（リダイレクト、エラーページ、タイムアウトなど）
  - Auth Basic（ベーシック認証）
  - Gzip（gzip を用いた応答の圧縮）
  - Headers（応答ヘッダの加工・制御）
  - Log（ログ形式、レベル、ファイルなどの制御）
  - Rewrite（正規表現によるリクエストの加工）
  - Proxy（プロキシの設定）
    etc...
- オプションモジュール    ：標準ではコンパイルされないモジュール。configure スクリプトに設定することで組み込める。
  - Auth Request（サブ応答によるクライアント認証）
  - Gunzip（gzip圧縮応答のon-the-fly解凍）
  - Image Filter（GIF, JPEG, PNG画像イメージ変換）
  - SSL（HTTPS/SSLサポート）
  - MP4（mp4ストリーミングサポート）
  - Mail Core（mailモジュールコアパラメータ）
    etc...
- サードパーティモジュール：第三者組織が開発したモジュール。configure スクリプトに設定することで組み込める。

### インストール  
NginxはOSによってインストール方法が異なる
https://www.nginx.com/resources/wiki/start/topics/tutorials/install/

Linux:[package](https://www.nginx.com/resources/wiki/start/topics/tutorials/install/#official-win32-binaries)を使ってインストール（設定ファイルを作成して記述する必要あり） 
FreeBSD：[ports](https://www.freebsd.org/doc/handbook/ports-using.html)を使ってインストール
その他：[source](https://www.nginx.com/resources/wiki/start/topics/tutorials/install/#official-win32-binaries)からインストール
  [参考1](http://nginx.org/en/download.html)
  [参考2](https://qiita.com/tatuno/items/44e8130d7544d1534f7)  


**Windows install 手順**
私の動作環境がWindowsだったので、自分のPCにインストールしたときの手順を書いておきます。
1. [ここ](http://nginx.org/en/download.html)から stable version の `nginx/Windows-*.*.*`をダウンロード
2. C直下（別の場所でもOK）に解凍  

コマンドラインツールを開き、解凍したディレクトリの中で↓のコマンド叩けば起動します。  


インストール後の起動・停止  
起動： `start nginx`  (exeファイルを実行する)
停止： `nginx [stop|quit]`  
[**windowsの場合**](http://nginx.org/en/docs/windows.html)
停止： `nginx -s [stop|quit]` 

※注意
bashなどでnginxを起動すると、nginxの実行ファイルがコンパイルされ、`nginx.exe*` となることがある。
その場合は `./nginx` とパス指定して実行する必要あり。

```sh
$ ls
conf/  contrib/  docs/  html/  logs/ nginx.exe*  temp/
```

起動後は `http://localhost/index.html` にアクセスするとnignxのデフォルトインデックスのページが表示される。  

モジュールなどの設定をするconfigure スクリプトについて
ソースからnginxをビルドするときに指定する。色々と指定できるが詳細は[公式ドキュメント](http://mogile.web.fc2.com/nginx/configure.html)をどうぞ。
上記のインストール方法だと指定できない。指定したい場合は[こちら](http://wpwewill.help/archives/605)のようにソースからビルドしないといけない模様。


## 3.構築の基本
### 3.1.基本構文  
nginxの設定ファイル

- default  
  `nginx.conf`
- win  
   `[インストールディレクトリ]/conf/nginx.conf`
- その他  
 [`/usr/local/etc/nginx/nginx.conf` | `/usr/local/nginx/conf/nginx.conf` | `/etc/nginx/nginx.conf`]


#### 設定ファイルの構成
**ディレクティブ**（設定項目）とその **ブロック**の集合。
ブロックは基本的に入れ子にすることができる。

```
listen 80;    # ※1

server {
    listen 80;
    server_name test.matsue-ct.ac.jp;
}                 # ※2
```

※1:ディレクティブの例。`[ディレクティブ名] [値]+ ;` の形式。値は複数指定することができる。
`listen 80` でサーバーが待ち受けるポート番号を 80 に指定。

※2:ブロック（詳しくは後述）の例。`[ブロック名] [値]`の形式で、基本的に値は`{}`で囲う。
 `server_name test.matsue-ct.ac.jp` でサーバー名（ドメインやホスト名とも呼ばれる）を「test.matsue-ct.ac.jp」に指定。

##### ブロックについて  
上から下の順で上位
- HTTPブロック      ：httpトラフィックの処理の設定。[公式の説明が短いので概要がよくわからない](https://nginx.org/en/docs/http/ngx_http_core_module.html#http)
- serverブロック    ：仮想サーバの設定。サーバが接続を受理するアドレスとポートなどを記述。[記述例](http://nginx.org/en/docs/http/request_processing.html)、[記述例2](https://www.nginx.com/resources/wiki/start/topics/examples/server_blocks/)
- locationブロック  ：特定のパスに対するリクエストへの処理について設定。webフレームワークでいうところのルート設定。
他にもあるが後述します。

ブロックは上位→下位の順で入れ子にすることができる。また、並列して同ブロックを複数記述することもできる。
記述例：server ブロックを並列させて仮想サーバを作る↓

```
http {
    server {
        listen 80;
        server_name test.matsue-ct.ac.jp;
        index index.html index.htm;
        location  /  {
            try_files $uri $uri/;
        }
        location /admin/ {
            index index.php;
        }
    }
}
```

**上記記述例の解説**
ブロックが入れ子になった例。httpブロックの下にserverブロックがあり、さらにその下にlocationブロックが２つ定義されている。
locationは指定されたURLの中のパス（とオプション）を指定し、指定されたものとマッチしたアクセスの設定を記述する。

`location /admin/ {}` は`http://test.matsue-ct.ac.jp/admin/`へのアクセスに対する処理の設定。
`location  /  {}`     は`http://test.matsue-ct.ac.jp/`      へのアクセス（↑を除く）に対する処理の設定。
locationの設定は、パスの指定が長い方が優先。  


親ブロック（上位ブロック）内の設定は、中に定義された子ブロック（下位ブロック）でのデフォルト値として引き継がれる（継承）。
例えば、上記の例だとserverブロックで指定されたindexの値を継承し、一つ目のlocationブロック内でのデフォルト値は`index.html index.htm`となっているが、
二つ目のlocationの設定により、URLが`/admin/`の場合のみ `index.php`に指定されている（他のURLは`index.html index.htm`のまま）。

#### 3.1.1. コンテキスト  
コンテキスト    ：ブロックの別名。[Nginxの公式doc](https://docs.nginx.com/nginx/admin-guide/basic-functionality/managing-configuration-files/#contexts)を見ると、特にトップレベルのディレクティブ※をそう呼ぶようである。  
※トップレベルのディレクティブ：それぞれに異なるトラフィックタイプが割り当てられているディレクティブ（http,general connection processing,mail,tcp and udp traffic）。

**コンテキストの種類**
[Nginx入門]によると6種類だが、公式をはじめとするほかの英語サイトを見るとそうとも限らない（というかサイトによって紹介されているコンテキストの数が違う）。
ざっと見た中でよく使われていそうなものを挙げる。

- global/main               ：一番上位のコンテクストで、唯一ブロックの形になっていないコンテクスト
  - events                  ：コネクションの処理に対する設定
  - HTTP                    :Httpトラフィック
    - server                ：サーバの設定
      - location            ：特定のリクエストへの処理についての設定  

おまけ
  - if                      ：[公式スタートガイドによると](https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/)なるべく使うのを避ける方がいい


基本的に、値の継承は上位から下位にされ、ブロックの値は同位のものや下位のものに影響されない。

```
server {
    server_name hoge;
    root /home/pub;
    location /app {
        root /usr/www;        # ※1
        location ~ \.php$ {   # ※2
            index index.php;
        }
    }
}
```
※1: rootディレクティブのオーバーライドの例。rootは与えられたURLに対して、サーバ内のどのディレクトリを探すかを指定する。
この場合は、
`http://hoge/app/index.html`にアクセスすると、サーバ内の`/usr/www/app/index.html`というファイルがヒットし、
`http://hoge/index.html`    にアクセスすると、サーバ内の`/home/pub/index.html`   というファイルがヒットする。

※2：入れ子になったlocationブロックの例。

**オーバーライドについて**  
基本的に、上記のように上位のブロックに記述されたものを下位のブロックで再度記述すると、設定はオーバライドするが、一部例外がある（actionディレクティブ）。


#### 3.1.2  変数、値、文字列  
Nginxでのコメント：頭に`#`をつける。
Nginxでの変数    ：状況に応じて変わる値を変数として設定に組み込むことができる。頭に`$`がおかれる。多数の種類が用意されている。

Nginxでの変数の例（Http core モジュール）

|              変数名     | 意味 |
|------------------------|------|
| $arg_name | リクエスト中のname変数 |
| $$args | GETリクエストにある全ての結合したパラメータ |
| $host | リクエストヘッダのHost行に等しい、なければ処理しているサーバー名<br/>$http_hostとは異なることもあるので注意 |
| $remote_addr | リクエスト中のname変数 |
| $is_args | $argsがセットされていれば `?` に、そうでなければ空の文字列 |
| $remote_addr | クライアントアドレス |
| $uri | パラメータなしの現在のリクエストURI |
| $server_name | サーバー名 |
| $request | オリジナルのリクエスト |
| $request_body | リクエストの本体 |
|  | etc... |

**変数の値**  
変数の値は数値と文字列がある。
- 文字列の記法：直接文字列を書くか、`'...'`,`"..."`の形式で表記する。  
  二種類の記号に対する区別はない。囲い文字は空白やセミコロンなどの特殊な文字列を含むものを表す場合に用いる。
- 数値の記法：デフォルトは単位。以下の略記号が使える。

|   |   |
|---|---|
| k,K | キロバイト (例：2k) |
| m,M | メガバイト |
| ms | ミリ秒 |
| s | 秒 |
| h | 時 |
| d | 日 |
| w | 週 |
| M | 月 |
| y | 年 |

<!-- todo 月とメガバイトの区別 -->

変数は豊富に用意されており、Http core モジュールで用意されている変数だけでも[これだけ](http://nginx.org/en/docs/http/ngx_http_core_module.html?&_ga=2.122695627.1504500516.1533259906-1165230848.1532054468#variables)ある。  
また、`set`,`map`などのディレクティブを使って新たに変数を設定することもできる。

### 3.2. 基本的な設定  
簡単なWebサーバをnginxを用いて立ち上げるために必要な設定について見ていく。  

```
worker_processes 1;

pid logs/nginx.pid;

events {}

http {
    include mime.types;
    access_log    /var/log/nginx_access.log;
    error_log     /var/log/nginx_error.log  info;

    server {
        listen 80;
        server_name net-0.matsue-ct.ac.jp;
        index index.html index.htm;
        location  /  {
            root    /usr/local/www/nginx;
        }
    }
}
```

- **worker_processes**  
実際にクライアント要求を処理するプロセス数を指定。  
auto指定で使用可能なCPUコア数を検出する。詳しくは [worker_processes](http://nginx.org/en/docs/ngx_core_module.html#worker_processes) を参照。

  ```
  構文：      worker_processes <number|auto>;
  デフォルト：worker_processes 1;
  ```

- **access_log**  
アクセスログの出力設定。ログの出力先パス、フォーマットなどを指定。  
http, server, location, if in location, limit_exceptのコンテキストで指定可能。コンテキストごとに複数のファイルにアクセスログを出力できる。

  ```
  構文：      access_log path [format [buffer=size] [gzip[=level]] [flush=time]     [if=condition]];
              access_log off;
  デフォルト：access_log logs/access.log combined;
  ```

- **error_log**  
エラーログの出力設定。ログの出力先ファイル、出力するエラーのレベルを指定。  
main(global), http, mail, stream, server, locationのコンテキストで指定可能。  
access_logとは違うモジュールのでディレクティブ。指定できる内容や利用可能なコンテキストが違うので注意。エラーレベルは下の記述例では右に行くほど致命的（出力量が減る）もの。
server, locationで設定できるためバーチャルホスト別、URL別に出力できる。

  ```
  構文：      error_log <file|stderr> [debug|info|notice|warn|error|crit|alert|emerg];
  デフォルト：error_log logs/error.log error;
  ```

- **events**  
nginx のパフォーマンスやネットワークに関する設定のコンテキスト。  
このコンテキストはグローバルコンテキストに必ず指定しなければならない（コンテキスト内のディレクティブは未指定でもOK）  

- **include**  
ファイルの読み込みを指定。
パスはconfファイルからの相対パス。

  ```
  構文：      include <file | mask>;
  デフォルト：なし
  ```

- **listen**  
インデックスに利用するファイル名の指定。

  ```
  構文：      listen address[:port] [options..];
              listen port [options...];
              unix:path [options...];
  デフォルト：listen [*:80] | [*:8000];
  ```
  オプションはありすぎてあげるときりがないので[こちら](http://nginx.org/en/docs/http/ngx_http_core_module.html#listen)を見てください。
  記述例↓

  ```
  listen 127.0.0.1:8000;
  listen 127.0.0.1;
  listen 8000;
  listen *:8000;
  listen localhost:8000;
  ```

- **server_name**  
バーチャルサーバー名を指定する（httpリクエストのhostヘッダからサーバを決定する）。
サーバー名は１つ以上複数指定可能。リクエストのホスト名が記述されたサーバー名と一致する場合、このディレクティブがあるserverコンテキストが適用される。ワイルドカードや正規表現での指定も可能。

  ```
  構文：      server_name name1 [name2 ...];
  デフォルト：server_name "";
  ```

  ※サーバー名は以下の順番で優先的に選択される
  1. 静的な名前に完全一致
  2. ワイルドカードで始まる最長の名前への一致, ex: *.example.com
  3. ワイルドカードで終わる最長の名前との一致, ex: www.example.*
  4. 正規表現で表現された名前で最初に一致したもの

- **index**  
インデックスファイルの指定。  
http, server, locationコンテキストで指定可能。  
ファイル名には変数を含ませることや、リストの最後には絶対パスを指定することができる。ただし、絶対パスで記述するとリダイレクトが起きて、他のlocationの値を参照したりすることがあるので注意。

  ```
  構文：      index file1 [file2 ...];
  デフォルト：index index.html;
  ```
  記述順に優先される。記述例↓

  ```
   index  index.html index.htm index.php /index.html;
  ```

- **location**  
リクエストURIに対する設定を指定。
適用するURIのパスを指定し、ブロック{}の中にそのパスごとの設定を記述する。

  ```
  構文：      location [ = | ~ | ~* | ^~ ] uri { ... }
  　　　      location @name { ... }
  デフォルト：なし
  ```
  並置した場合の優先樹陰委などは後述する。  
  ※ location    => 特定のファイルやフォルダへのリクエストを処理
    server_name => 特定のホスト名（ドメイン）へのリクエストを処理

- **root**  
ドキュメントルートのパスを指定。

  ```
  構文：      root path;
  デフォルト：root html;
  ```
  パスには変数を含めての指定も可能。記述例↓

  ```
  location /i/ {
    root /data/w3;
  }
  ```
  この例では、リクエストURIが `/i/top.gif`だった場合 `/data/w3/i/top.gif` のファイルがヒットする。  

- **pid**  
nginxのmainプロセスのプロセスIDを格納するファイルの名前を指定。

  ```
  構文：      pid file;
  デフォルト：pid logs/nginx.pid;
  ```

**設定のチェック**
nignx の設定読み込みチェックは下記コマンドをたたくと可能。

```
$ ./nginx -t -c conf/nginx.conf     # ※
nginx: the configuration file C:\nginx-1.14.0/conf/nginx.conf syntax is ok
nginx: configuration file C:\nginx-1.14.0/conf/nginx.conf test is successful
```
※Windowの場合。confファイルのパスは各環境に合わせること。  

### 3.3. Nginxの起動  
各コマンドは下記のようになっている。
設定ファイルを指定する場合
起動：`$ ./nginx -c conf/nginx.conf`

停止する場合は、起動したコンソールで `Ctrl + c`  

## 4. 正規表現  
NginxではPCRE(Perl Compatible Regular Expressions)をサポートしており、 server, location など色々なところで利用することが出来る。

正規表現：文字列があるパターンに一致(マッチ)するか否かなどを調べるために用いられる表現方法。

正規表現の文字や構文を簡単にまとめる。詳しいことが知りたい場合は各自で調べること。  

### 4.1.1.文字とメタ文字  
**文字**  
英数文字はその文字を表す。  
> abadefg123　　#英数字

**メタ文字**  
以下の文字は特殊な意味がある。メタ文字を英数字などと同じ文字として指定したい場合はその直前に`\`をつける。  
※英数字の前に`\` をつけると違う意味になる。  
>     \  |  (  )  {  }  ^  $  *  +  ?  .

#### 4.1.2. 位置指定  
文字列中の位置を指定するメタ文字。

```
^	行頭
$	行末
\b	単語の区切り
\B	単語の区切り以外
```

#### 4.1.3. 量指定子
繰り返しを指定する。量指定子はアトム（文字や文字列）の後ろに置いて使う。

```
{n,m}	n回以上、m回以下の繰り返し
{n,}	n回以上の繰り返し
{n}	n回の繰り返し
*	0回以上の繰り返し ({0,}に同じ)
+	1回以上の繰り返し ({1,}に同じ)
?	0または1回の繰り返し ({0,1}に同じ)
```

#### 4.1.4. 集合とグループ、後方参照  
**文字の集合**  
文字の集合は`[]`で囲って表す。補集合を指定するする場合は `[^...]`と書く。
利用できるのは、英数小文字、大文字、数字。

```
[a-z]	'a' から 'z' までの英小文字のどれかにマッチ
[^a-z]	'a' から 'z' までの英小文字のいずれにもマッチしない場合
[A-Z]	'A' から 'Z' までの英大文字のどれかにマッチ
[a-zA-Z]	英小文字または英大文字のいずれかにマッチ
[0-9]	'0' から '9' までのいずれかの数字にマッチ
[a-zA-Z0-9]	数字または英文字のいずれかにマッチ
[\]\-]	] または - にマッチ
```

**文字列**  
文字列は`()`で囲って表す。

```
(strings)	strings が一つのグループ
(str1| str2 )	str1またはstr2 にマッチ
```

## 5. location  
locationはURIのマッチに対して様々な条件を定義できる。その方法について詳しく見る。  


### 5.1. locationの基本文法  
locationの構文（再掲）。

```
構文：      location [ = | ~ | ~* | ^~ ] uri { ... }
　　　      location @name { ... }
```
locationには`=`,`~`,`~*`,`^~`のいずれかのprefixを置くことができる（prefixなしでも可能）。
基本的にはパスの指定はより長く一致するものやより高位のもの（後述）が優先される。  

```
    location  /  {
        root /usr/local/www/nginx;
    }
    location  /admin/ {
        root /usr/local/www/admin;
    }
```
この記述例の場合、`/`はどのURIにも一致するが、`/admin/`の条件に一致されるものはそちらが優先される。

https://heartbeats.jp/hbblog/2012/04/nginx05.html

#### 5.1.1. prefix
prefixの種類と意味は下記の通り。

```
=             完全一致
~             正規表現 (大文字小文字を区別)
~*            正規表現 (大文字小文字を区別しない)
^~            前方一致 (後方不参照)
(prefixなし)  前方一致 (後方参照あり)
```

#### 5.1.2. prefixの優先順位  
基本は、プレフィックスの優先順位と最長一致に基づいて決定される。
評価される順番と、検索が完了するタイミングは下記の通り。  
1. 完全一致 =
2. 前方一致 ^~
→同位の複数のlocationに一致する場合は、最長一致を適用する。
3. 正規表現 ~ | ~*
→定義された順番で評価。最初に一致するものを見つけたら終了。
4. 前方一致 (prefixなし) 
→同じ前方一致でも、prefixがあるものとは優先順位が違うので注意。

#### 5.1.3. 名前付き location
下記の例は名前付きlocation。通常のリクエストには利用されず、内部のリダイレクトに使われる。
server ブロック内にしか置けない（locationの中に入れ子にしたりも不可）ので注意。  

```
location  @named_location   { ... }
```

## 6. virtual server  
### 6.1. 名前によるバーチャルサーバ  
nginxはリクエストヘッダの中にあるHostフィールドと一致するserver_nameを探し、その設定を採用する。  
一致するserver_nameが見つからなかった場合は、デフォルトのサーバで処理を行う。
デフォルトのサーバは下記のようにlistenディレクティブで指定するか、されていなければ最初に定義されているサーバになる。

```
    server {
        listen 80  default_server;
        server_name www2.test.jp;
        ...
```

サーバー名をサーバのホスト名にしたい場合は $hostname変数が使える。  
また、サーバー名の代わりにIPアドレスを利用する場合はIPアドレスをサーバー名に指定する。

```
    server {
        server_name $hostname 192.168.1.1;
    }
```

### 6.2. IPによるバーチャルサーバ  
IPアドレスおよびポート番号によるバーチャルサーバも作成できる。

```
    server {
        listen 192.168.0.1:80;
        server_name www.test.jp;
        ...
    }
    server {
        listen 192.168.0.1:88;
        server_name www2.test.jp;
        ...
    }
    server {
        listen 192.168.0.2:80;
        server_name www3.test.jp;
        ...
    }
```

default_server は **IPアドレスとポート番号で指定されるサーバ毎**に決まるので、上記の場合default_serverは3つ(それ自身)になる。

#### 6.2.1. IPおよび名前によるバーチャルサーバ  
IP,Portによるサーバと、名前によるバーチャルサーバ設定はミックスすることが出来る。
その場合、まずIPアドレスおよびポート番号で仕分けされ、次にリクエストのHostヘッダと server_name との比較が行われる。


### 6.3. サーバー名  
#### 6.3.1. ワイルドカードと正規表現  
サーバー名はワイルドカードや正規表現で表すことができる。

```
    server {
        server_name  *.test.jp  www.test.*;   # ※1
        server_name  ~^www[0-9]+\.test\.jp$;  # ※2
    ...
    }
```
※1：ワイルドカードの例。`*.test.jp`のような前方についたワイルドカードは省略して `.test.jp`と書いても同じ意味になる。 
※2：正規表現の例。前に `~`を置く（正規表現との間に空白などを置かないこと）。正規表現で書くときは `.`はエスケープするのを忘れないよう。  

#### 6.3.2. 優先順位  
サーバー名が複数の条件に一致する場合、優先順位は以下の順になる。

1. 完全一致
1. 最長のワイルドカードから始まる名前との一致 
*.test.jp
1. 最長のワイルドカードで終わる名前との一致 
www.test.*
1. 最初に一致した正規表現の名前 
設定ファイルに記載された順に検索される

## 7. Apacheにおけるリバースプロキシ  
apacheの話なので省略  

## 8. Nginxによるリバースプロキシ  
ここでは、Ningxをリバースプロキシとして使うために必要な機能を中心に解説します。  
※リバースプロキシは通常、複数のサーバー間で負荷を分散したり、異なるWebサイトのコンテンツをシームレスに表示したり、HTTP以外のプロトコルを使用してアプリケーションサーバーに処理要求を渡したりするために使用されます。

https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/


### 8.1. プロキシ  
Nginxでプロキシを実現するには、http_proxy_module （と http_rewrite_module）が中心となる。
最初にhttp_proxy_moduleの基本的なディレクティブを取り上げる。

リバースプロキシの設定は、`http`ブロックの代わりに`stream`ブロックをトップレベルに作成して設定する

#### 8.1.1. proxy_pass  
与えられたURIの処理を行うサーバのプロトコルとアドレスを指定。

  ```
  構文：      proxy_pass URL;
  デフォルト：なし
  ```
proxy_pass が利用可能なコンテキストは、 location, if in location, limit_except。
  
```
    location /some/path/ {
        proxy_pass http://www.example.com/link/;
    }   # ※1

    location /back/ {
        proxy_pass  http://backend;
    }   # ※2
```
※1,※2どちらのパターンでも、locationで指定されたパスへのリクエストは、proxy_passで指定された先のサーバーで処理される。  
※1のように記述する（proxy_passに**URI**を指定する）と、`/some/path/`のURIはproxy_passで指定された`http://www.example.com/link/`に書き換えられる。  
※2のように記述する（proxy_passに**URL**を指定する）と、`/back/`を含んだパスがプロキシされたサーバーに渡される。  
また、正規表現で指定したlocationの場合、proxy_passにURIを含んで指定することはできない。  

URLは`http`,`https`プロトコルが指定可能。  

参考：[nginx の proxy_pass へ何を指定するか](https://qiita.com/yujiorama_at_github/items/f02c7e45514f336b50d9)

non-httpサーバにリクエストを渡す場合は、`fastcgt_pass`など `**_pass`ディレクティブを利用できる。  

#### 8.1.4. proxy_pass_header  
プロキシ先からクライアントへ投下させるヘッダフィールドを設定。  
デフォルトでは  “Date”, “Server”, “X-Pad”, and “X-Accel-...” は透過されない。
 
  ```
  構文：      proxy_pass_header field;
  デフォルト：なし
  ```
利用可能なコンテキストは http, server, location。  

#### 8.1.5. proxy_set_header  
プロキシサーバに送られるリクエストヘッダのフィールドを再定義、あるいは追加を行い、プロキシ先のサーバに渡す。

  ```
  構文：      proxy_set_header field value;
  デフォルト：proxy_set_header Host $proxy_host;
             proxy_set_header Connection close;
  ```
指定可能なのはテキストや変数、またはその組み合わせ。  
①のように設定すると、Hostリクエストヘッダフィールドが渡されている場合はオリジナルのものを、渡されなかった場合はなければプライマリサーバ名になる。  
また、ヘッダフィールドを渡したくない場合は②のように設定する。

```
  proxy_set_header  Host  $host;          # ①
  proxy_set_header  Accept-Encoding  "" ; # ②
```

- クライアントのIPアドレスをロギングする方法(http)  
クライアントのオリジナルIPアドレスを記録するには設定が必要となる。
1．http接続の場合、`proxy_set_header` ディレクティブに `$proxy_protocol_addr`を指定し、

```
  proxy_set_header  X-Real-IP       $proxy_protocol_addr;
  proxy_set_header X-Forwarded-For  $proxy_protocol_addr;
```
log_formatディレクティブに`$proxy_protocol_addr`変数を追加する。

```
  http {
    #...
    log_format combined '$proxy_protocol_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';
  }
```

#### 8.1.6. キャッシュのディレクティブ  

- **proxy_cache**  
キャッシュに使われる共有メモリ(zone)を定義する。offだとキャッシュしない。  
zoneは同じものを複数の個所で使用することが可能。

  ```
  構文：      proxy_cache zone | off;
  デフォルト：proxy_cache off;
  ```

- **proxy_cache_bypass**  
キャッシュ（した値）を使わないレスポンスを定義。

  ```
  構文：      proxy_cache_bypass string ...;
  デフォルト：なし
  ```
stringに指定した値のすべてが空、あるいは０の時はレスポンスに対してキャッシュを使わない。記述例↓
  
  ```
  proxy_cache_bypass      $cookie_nocache $arg_nocache$arg_comment;
  proxy_cache_bypass      $http_pragma    $http_authorization;
  ```


- **proxy_no_cache**  
キャッシュに取らないレスポンスを定義。

  ```
  構文：      proxy_no_cache string ...;
  デフォルト：なし
  ```
`proxy_cache_bypass`と同様にstringに指定した値のすべてが空、あるいは０の時はキャッシュに保存しない。  

- **proxy_cache_key**  
キャッシュするキーを指定。

  ```
  構文：      proxy_cache_key string;
  デフォルト：proxy_cache_key $scheme$proxy_host$request_uri;
  ```

- **proxy_cache_valid**  
キャッシュされたレスポンスのうち、ステータスコードを指定してその対象の有効時間を制限する。

  ```
  構文：      proxy_cache_valid [code ...] time;
  デフォルト：なし
  ```
デフォルトだとレスポンスがキャッシュされる時間は無制限。キャッシュのファイルストレージ超過時に使用されていないものから削除される。
以下の記述例だと、200と302コードのレスポンスはキャッシュの中では10分間有効になる。

  ```
  proxy_cache_valid 200 302 10m;
  ```
すべてのステータスコードを指定する場合はコードの代わりに `any`を指定する。

### 8.2. rewrite  
http_rewrite_moduleモジュールを使えば、設定ファイルにrewrite文を書くことでURLをリダイレクトできる。
このモジュールの`break`,`if`,`return`,`rewrite`,`set`ディレクティブは以下の順番で処理を行う。

1. serverレベルに指定されたディレクティブを順番に処理
2. URIにもとづきlocationを検索
3. 該当するlocation内のディレクティブを順番に処理
4. リクエストURIがrewriteされると2に戻る（このループは10回まで繰り返される）

#### 8.2.1. rewrite
指定された正規表現に一致するURIを書き換える。置換文字列が`http`,`https`,`$scheme`で始まる場合は処理を停止し、リダイレクトが返される。  

  ```
  構文：      rewrite regex replacement [flag];
  デフォルト：なし
  ```
flagにはrewriteの終了など、動作を指定することができる。
flagに設定可能なパラメータは以下の通り。

- last
  `http_rewirte_module`ディレクティブの実行を終了し、変更されたURIでロケーションマッチを開始する。

- break
  `http_rewirte_module`ディレクティブの実行を終了する。locationの再探索はされない。

- redirect
  replacementに`http`,`https`,`$scheme`以外が指定されていれば、302コードで一時的なリダイレクトを返す。

- permanent
  302コードで永久的なリダイレクトを返す。  

リダイレクトコードについては[こちら](https://www.symmetric.co.jp/blog/archives/123)が参考になるかも。

#### 8.2.2. rewrite_log  
`http_rewirte_module`モジュールの実行結果を`error_log`へ出力するかを指定する。出力時のログレベルは`notice`。

  ```
  構文：      break;
  デフォルト：なし
  ```

#### 8.2.3. break  
`http_rewirte_module`ディレクティブセットの実行を止める。
locationに記述されていたらリクエストの処理は続けられる。

  ```
  構文：      break;
  デフォルト：なし
  ```

#### 8.2.4. if  
conditionに指定された条件に当てはまる場合、`{}`の中の`http_rewirte_module`ディレクティブを実行する。  

  ```
  構文：      if (condition) { ... }
  デフォルト：なし
  ```

conditionに指定できるものは以下の通り。

  - 変数。値が空の文字列か'0'の時に偽。それ以外は真。
  - `=`,`!=`による変数と文字列の比較。
  - `~`,`~*`, `!~`, `!~*`による正規表現の比較。`~`は大文字小文字を区別し、`~*`は区別しない。
  - `-f`,`!-f`によるファイルの存在チェック。
  - `-d`,`!-d`によるディレクトリの存在チェック。
  - `-e`,`!-e`によるファイルまたはディレクトリまたはシンボリックリンクの存在チェック。
  - `-x`,`!-x`による実行可能ファイルの存在チェック。

以下記述例

```
if ($http_user_agent ~ MSIE) {
    rewrite ^(.*)$ /msie/$1 break;
}

if ($http_cookie ~* "id=([^;]+)(?:;|$)") {
    set $id $1;
}

if ($request_method = POST) {
    return 405;
}

if ($slow) {
    limit_rate 10k;
}

if ($invalid_referer) {
    return 403;
}
```

#### 8.2.5. return  
処理を終了させて指定されたコードをクライアントに返す。

  ```
  構文：      return code [text];
              return code URL;
              return URL;
  デフォルト：なし
  ```

444を指定した場合はリクエストヘッダを送信せず接続を切断する。
nginxのバージョンによって指定できるコードが変わったり、textにリダイレクトURLを指定できたりなど振る舞いが変わる。  
詳しくは[公式](http://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return)のドキュメント参照。

#### 8.2.6. set  
変数に値をセットする。  

  ```
  構文：      set $variable value;
  デフォルト：なし
  ```

valueには文字列、変数か二つの組み合わせを含めることができる。  

### 9. Basic認証  
NginxのBasic認証について。ipを指定してアクセス制御ができるモジュールもあるが省略する。  

#### 9.1. Basic認証  
http_auth_basic_moduleモジュールを使えば、"HTTP Basic Authentication"プロトコルでのユーザー名とパスワードによるアクセス制御が可能になる。

設定例

```
location / {
    auth_basic           "closed site";
    auth_basic_user_file conf/htpasswd;
}
```

#### 9.2. satisfy  
http_access_moduleのディレクティブと、`satisfy`ディレクティブを組み合わせることで、アクセス許可の制御をカスタマイズできる。  
以下の例では特定のIPのみBasic認証せずアクセス可能にする。

```
location / {
        satisfy any;
        allow 192.168.0.0/16;
        deny  all;
        auth_basic           "private";
        auth_basic_user_file  htpasswd;
    }
```

### 10. NginxにおけるSSL, 11. NginxとWAF
NGINXの機能というよりSSLとWAFの使い方っぽい内容なので省略。内容がちょっと古いので、その辺りを知りたいなら他の資料を探した方がよさそう。

### おわりに  
Nginxっていい感じの資料が意外とネットに見つからないなー。主要な機能とか何ができるのかが日本語で大体載ってるサイト（できれば一ページにまとまってるの）があると嬉しいなー。
という発想から隙間時間を使って少しずつ自分用にまとめました。当初の想定の3倍くらいのボリュームになって、アドベントカレンダーの下書きを公開したときに同僚の皆さんからちょっと引かれてしまってうーんこの。
この記事を書くときは ~~日本語の資料があると思ってなかったので~~ 英語の資料を参考にしましたが、NGINXは意外と日本語のドキュメントが充実しています。

この記事が私と同じような悩みを持ってた人や「nginxわからない」と思っている人にとって、ちょっとでも助けになりますと幸いです。

明日は @yagiyuuuu さんになります。よろしくおねがいします！

ウェブクルーでは一緒に働いていただけるエンジニアを随時募集しております。
お気軽にエントリーくださいませ。

[開発エンジニアの募集](https://hrmos.co/pages/1004681658307198976/jobs/0000005)
[フロントエンドエンジニアの募集](https://hrmos.co/pages/1004681658307198976/jobs/0000001)

## 参考  

[NGINX入門](http://www2.matsue-ct.ac.jp/home/kanayama/text/nginx/all.html)
[nginx documentation](http://nginx.org/en/docs/)
[Linode](https://www.linode.com/docs/web-servers/nginx/)
[NGINX and NGINX Plus documentation](https://docs.nginx.com/nginx/)
[Understanding the Nginx Configuration File Structure and Configuration Contexts](https://www.digitalocean.com/community/tutorials/understanding-the-nginx-configuration-file-structure-and-configuration-contexts)
[How to Configure NGINX](https://www.linode.com/docs/web-servers/nginx/how-to-configure-nginx/#directives-blocks-and-contexts)
[NGINX Getting Started](https://www.nginx.com/resources/wiki/start/)
[Pitfalls and Common Mistakes](https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/)
[index of directives](http://nginx.org/en/docs/dirindex.html)
[IT生涯学習Tech](https://gakumon.tech/nginx/index.html)
[Nginx技術ブログ](https://nginx.sios.jp/)