開発環境にnginxを用い開発し振り返りと整理(自己学習用備忘録)

#今回の開発環境の構成

```
root
 |
 |--docker--dev----app--------supervior
                |            |-----nginx
                |            |-----php-fpm
                |            |-----Dockerfile
                |-----mysql
                |-----docker-compose.yml              
```
backendはlaravelで実装
appディレクトリ配下supervior,nginx,php-fpmという構成。
appの子ディレクトリには各種設定ファイルを配置。
コンテナに関してはsupervior、nignx,php-fpmlをまるっと１コンテナに集約。
superviorにてphp-fpm,nginxを制御する。
(dockerの思想上あまりよくないかもですが)
そして今回はnginxの設定周りやらを備忘録に残していますので、
dockerfile、docker-compose.yml等は割愛させていただきます。（また備忘録として残していきます）
筆者はずぶずぶの素人の為、学習用として活用させていただいています。（申し訳ございません）

##nginxとは
Apache同様オープンソースなWebサーバーのひとつで、並行処理性能の高さ、比較的メモリ消費が少ないなどの特徴を持っている。

そもそもなぜ、apacheじゃなく、nginxなのか？
従来はapacheを使用していましたが、（今ももちろん使われています） あるサイトでアクセス数が増加したときにapacheでは処理できず、レスポンスが遅くなってしまいました。この大量アクセスに対応できる様に作られたのが、nginxなのです。

###nginxとapacheは何が違うの？
####apache
httpに特化しています。1リクエスト、１プロセスとして処理をする為、メモリを消費しやすいです。

####nginx
nginxは同時処理を行うことに特化している。余計な機能はつけていない分、非常にシンプルな構成になります。
その分ソフトウェア自体は小さく、メモリ使用量も少ない。
大量処理を振り分け、他に処理してもらうということ。
役割としてはリバースプロキシとなっているですね。その為ロードバランサーとして機能したりします。
AWSでのELBも裏で動いているのnignxらしいです。
この構成でいう処理をしてくれているのがphp-fpmということですね。

>リバースプロキシついてはこちらのURLを参考にhttps://wa3.i-3-i.info/word12251.html

###nginxの設定ファイル群について

nginxの設定ファイルは、/etc/nginx/nginx.conf
/etc/niginx 配下にあります

```
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 {
        }
    }
}
```

大項目構成はこの様な感じ。　http{ }とかserver{ }、location / {}とかは**ディレクティブ**と呼ばれる。
include〜もディレクティブと呼ばれる。
ブロック{ }で囲む構文と、include hoge;のように、セミコロンを使った構文があり、ディレクティブによって構文が決まっています。

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

httpディレクティブのブロック内は、httpコンテキストと定義されます。ディレクティブによって、どのコンテキストで使えるかが決まっているので、非常に重要なポイントです。たとえば、serverディレクティブはhttpコンテキスト内でしか使えません。

どのブロックにも囲まれていないところは**mainコンテキスト**として扱われます。

--------------------

###各要素を切り分ける
####mainコンテキスト内
```
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;
```
user→nginxの実行ユーザーをさす。　Debian系列においてはwww-dataにするのが慣習

worker_processes　→　ワーカーのプロセス数。nginxは、複数のワーカープロセスを、一つのマスタープロセスで制御する仕組みで、ワーカープロセスは基本的にCPUのコア数と同じにしておけばよいのですが、autoとすることで、自動的にCPUのコア数分割り当ててくれます。

error_log　→　errorファイルの場所です。syslogと同様のパラメータによるエラーレベルも指定できて、指定しない場合はerror以上のエラーが吐き出されます。

pid →　先述のマスタープロセスのPIDを出力する、PIDファイルのパスを指定します。

####eventsコンテキスト内
nginxの特徴はイベント駆動型、それに関するコンテキスト

```
events {
    worker_connections 1024;
}
```
worker_connections →　一つのワーカーが処理できるコネクション数を指定します。チューニングのポイント

###httpコンテキスト内

```
http {                  
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
　　　　　　　　　　　　　　#statuscode レスポンスのバイト数
                      '$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;
中略
}
```
#####log_format
ログファイルの書式を指定し、その書式に名前をつけます。mainという名前の書式を作っています。　アクセスログにログを出力する際に使用するフォーマットのことで、設定ファイル（今回の場合 /usr/local/nginx/conf/nginx.conf） に記述して設定する。

remote_addr →　クライアントのIPアドレス
remote_user　→　クライアントのuser_name
request     →　リクエスト URL および HTTP プロトコル
[$time_local]　→　一般的なログフォーマットが適用されるローカル時刻

status →　リクエストステータス
body_bytes_sent　→　クライアントへの送信バイト数
http_referer　→　Web ページの参照元
http_user_agent　→　クライアントのブラウザ情報
http_x_forwarded_for　→　接続元IP
######access_log　
アクセスログのパスと、その書式を指定します。書式の指定には、log_formatで定義したものを使用します。
ここに定義された、log_formatが書き出される模様
#####sendfile
内部的にsendfile()システムコールを用いるかどうかを指定
#####tcp_nopush
sendfileディレクティブ有効時に、TCP_NOPUSHオプションを有効にするかどうかを指定します。有効にすると、最も大きなパケットサイズで送信します。
#####tcp_nodelay
tcp_nopushと同じく、TCP_NODELAYオプションを有効にするかどうかを指定します。小さなパケットを待たずに送信するものとのことです
#####keepalive_timeout
クライアントと常時接続する時間を指定します。ずっとアクセスしてくれているユーザーに対して、いちいち繋ぎ直したりしないためのものですね。フォルトの設定値は75sです。ELBを挟んでいる時はアイドルタイムアウトに注意です。
#####include
設定ファイルを読み込みます。/etc/nginx/mime.types　フルパスをしてすることで読み込めます。
MIMEタイプのファイルを読み込んでいる設定ですね。
includeディレクティブを次のような内容でnginx.confに記述して、conf.dというサブディレクトリ内の拡張子がconfであるファイルを読み込む設定を行うことがよくあります。
include /etc/nginx/conf.d/*.conf;

このincludeを使用することで個別に設定ファイルをセットアップして必要なものは読み込むと可読性も良くなります。
###serverコンテキスト内
serverコンテキストは複数作れます。バーチャルホストの設定をここで行います。
>1台のサーバで複数のドメインを設定する方法。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アドレスやポート番号あるいはUNIXドメイン ソケットを設定します。
listen IPアドレス:ポート番号;
listen 192.0.2.1:80

記述するとIPアドレス192.0.2.1の80番ポートでリクエストを受け付けるようになります。
もちろんでフォルトポートは80なので省略は可能
listen 192.0.2.1；

IPアドレスのデフォルト値はすべてのインターフェイス アドレスを意味する"*"であり、ポート番号のデフォルト値は"80"になります。そのため、listenディレクティブを省略すると、次の設定と同じになります。
listen *:80;
listen *:80; = listen *; = listen 80;

nginxではUNIXドメイン ソケットでもリクエストを受け付けることができます。記述方法は"listen unix:UNIXドメイン ソケットのパス"です。
listen unix:パス;
#####server_name
バーチャル サーバの名前を設定します。

ウェブブラウザはウェブサーバに対して次のようなリクエストを送り、リクエストのサーバーのホスト名がHost: example.comなっていた場合、server_name example.com;としておくことでnginxが名前解決してくれる訳です。
名前解決を利用して、バーチャルホスト（バーチャルサーバー）を振り分けができる。
#####root
ドキュメントルートを指定します。今回のドキュメントrootは /usr/share/nginx/html;
#####location
標準のドキュメントルートを設定して、必要に応じて個別のパスのlocationコンテキストに個別にドキュメントルートを設定することになります。

>URIのパス毎の設定を記述できます。括弧{ }で囲まれた部分がlocationコンテキストになります。リクエストURIのパスがこのlocationディレクティブのパスの条件に一致した場合にこのlocationコンテキストに記述した設定が適応されます。パスの条件の評価方法は前方一致と正規表現の2つです。locationコンテキストにlocationディレクティブを記述してネストすることもできます。上記の例ではリクエストURIのパスの先頭が"/"に一致した場合に適応されます。すべてのパスは"/path/to/page.html"のように"/"で始まるため、他のlocationディレクティブのパスの条件に一致したもの以外はこのlocationディレクティブが適応されます。

```
location / {
     [locationコンテキスト]
}
```
#####error_page
エラーページのカスタマイズに使用します。
カスタマイズの基本的な方法は、404.html;を作成し root /etc/nginx/html/〜といったrootを指定する
存在しないファイルへリクエストすると404.htmlが帰ってくるようになります。

-----------------------
###今回nginxの設定ファイル
####親ファイルとしてnginx.conf

```
user root;
worker_processes auto;

error_log /var/log/nginx/error.log warn;
pid       /var/run/nginx.pid;

events {
    worker_connections 1024;
}

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

    log_format main '[nginx]\t'
                    'time:$time_iso8601\t'
                    'server_addr:$server_addr\t'
                    'host:$remote_addr\t'
                    'method:$request_method\t'
                    'reqsize:$request_length\t'
                    'uri:$request_uri\t'
                    'query:$query_string\t'
                    'status:$status\t'
                    'size:$body_bytes_sent\t'
                    'referer:$http_referer\t'
                    'ua:$http_user_agent\t'
                    'forwardedfor:$http_x_forwarded_for\t'
                    'reqtime:$request_time\t'
                    'apptime:$upstream_response_time\t';

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

    sendfile on;
    keepalive_timeout 65;

    include /etc/nginx/conf.d/*.conf;
}

```
workerプロセスの実行権限はroot

event/worker_connections
ディレクティブは一つのworkerプロセスが同時に処理できる最大コネクション数を設定します。今回は1024です。
nginxの最大接続数は、「worker_processes」×「worker_connections」

error_log,pidの書き出し先→defa

httpディレクティブをみてみるとincludでMIMEタイプ.拡張子を適応
default_type application　レスポンスのデフォルトのMIMEタイプを設定します。上述のmime.typesで拡張子からMIMEタイプを決定できなかったときに、ここで指定したMIMEタイプが適応されます　例外が起きたときの対処ですね

あとはlogformatの定義とaccess_logの出力先を定義。

keepaliveなどの設定が定義され、バーチャルホストのファイルは/conf.d/以下からinclede 

###バーチャルホストの設定


```
 server {
    listen 80;
    server_name dev.experience.com;
    root  /var/www/product/public;
    index index.php index.html;

    access_log /var/log/nginx/ninaite.access.log;
    error_log  /var/log/nginx/ninaite.error.log;

    location / {
        try_files $uri $uri/ /index.php$is_args$args;

    }

    location ~ \.php$ {
        fastcgi_split_path_info ^(.+\.php)(\.+)$;
        #socket通信を用いてphp-fpmにアクセスしている
        fastcgi_pass unix:/var/run/php-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
　　　　　#fastcgi_paramにパラメータを設定、これらを送信する。
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

    }
}
```
portは８０で待ち構えています。
バーチャルホスト名はserver_name通り
ドキュメントrootはpublic配下のindex.phpを読みとっています。
locationの部分はすべてのリクエストがindex.phpフロントコントローラへ集まるように、サイト設定に以下のディレクティブを使用します。（laravel）ドキュメントより
 
local ~ \.php
.phpの拡張子を探し出し、fastcgiパラメータをphp-fpmにsokcet通信を用いparamsを送っているのですね。

farstCGIとは予めリクエストに対しての処理の割り当（プロセスをメモリに割り当ておく）てをしてリクエストに素早く対応できる様にしましょうとい処理のこと。

>ソケットとは
ネットワーク上で名前付けやアドレス指定が可能な通信接続ポイント 
接続を確立する為にソケットの確立。ブラウザー、サーバー間はtcpソケット通信。bind()により、IP,portを設定する。
サーバー、サーバー間unxソケット通信(同じマシン上で動いているプロセスが通信を行うためのソケット。)。なぜファイルのフルパスなのかというと、unixドメインソケットにはIP,portがないのでファイルパスで明示的に識別する。

-----------------
###まとめ
今まで、設定ファイルを読み込んでおらず、流していた部分があったので、実際にどういう風に構成して行けば良いか、またどこにその設定をしないと行けないのかが整理できました。深ぼって行けばまだまだ掘れますが、理解が深まったらまた編集して追記していきたいです。
参考サイト：https://heartbeats.jp/hbblog/2012/04/nginx05.html