Docker による nginx の導入と基本設定

f:id:Naotsugu:20201019221824p:plain


はじめに

Docker による nginx の導入と、nginx の基本設定についての説明です。


nginx のプロセス

nginx は master プロセスでソケットのリスンを行います。

ソケットで待ち受けた接続は、worker プロセスに引き渡され、 accept と送受信といったネットワークI/O処理を行います。

master プロセスは root ユーザで起動し、worker プロセスは一般ユーザ(nginx や www など)で起動します。

worker プロセスでは、epoll や kqueue などを利用した I/O の多重化により、1つのプロセスで複数のクライアントとの会話を処理することができます。これにより大量のクライアントとの接続を少ないリソースで捌くことができます。


docker で nginx を導入する

作業フォルダを作成してdocker-compose.yml を作成します。

$ mkdir nginx
$ cd nginx
$ touch docker-compose.yml

docker-compose.yml を以下のように作成します。

version: '3.8'
services:

  nginx:
    container_name: "nginx"
    image: nginx:1.19
    ports:
      - "80:80"
    volumes:
      - ./html:/usr/share/nginx/html

それでは nginx を起動してみましょう。

$ docker-compose up -d

同フォルダの html に HTML ファイルを用意します。

$ cd html
$ cat <<EOF > index.html
<!DOCTYPE html>
<html><body><h1>Hello nginx</h1></body></html>
EOF

http://localhost/index.html にアクセスすれば作成した HTML が表示されます。

スクリーンショット 2020-10-14 22.50.08


nginx の構成

コンテナにログインしてnginxの構成を見てみましょう。

$ docker-compose exec nginx bash

主なディレクトリ構成は以下のようになっています。

ファイル/ディレクトリ 説明
/etc/nginx/nginx.conf 起点となる設定ファイルで、他の設定ファイルはここから読み込まれる
/etc/nginx/conf.d/default.conf webサーバの設定ファイル
/etc/nginx/mime.types MIME のマッピングファイル
/usr/share/nginx/html/ webサーバのドキュメントルート
/etc/logrotate.d/nginx ログローテーションの設定ファイル
/var/log/nginx/ ログ・ファイルの出力先ディレクトリ
/var/cache/nginx/ キャッシュファイルが格納先ディレクトリ


nginx コマンド

nginx コマンドは以下のようなオプションがあります。

$ nginx -h
nginx version: nginx/1.17.4
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /etc/nginx/)
  -c filename   : set configuration file (default: /etc/nginx/nginx.conf)
  -g directives : set global directives out of configuration file

よく使うのは以下になります。

  • nginx -t で設定ファイルをテストしてエラー内容を表示

  • nginx -s reload 設定ファイルの再読み込みを行う

  • nginx -s stop 実行中の nginx デーモンを停止
  • nginx -s quit 処理中のリクエスト完了を待って nginx デーモンを停止


nginx の基本設定

/etc/nginx/nginx.conf が基本設定となります。

中身を見てみましょう。

$ cat nginx.conf

nginx.conf は以下のような設定になっています。

user  nginx;
worker_processes  1;

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  '$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;

    keepalive_timeout  65;

    #gzip  on;

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


worker プロセスのユーザ名と worker プロセスの数が以下のように定義されています。

これら設定のことをディレクティブと呼びます。

user  nginx;
worker_processes  1;

プロセス数はデフォルトで1となっていますが worker_processes auto; とすることで、CPUコア数と同数のプロセスを選択することができます。


次にあるのはエラーログの出力先とログレベルの設定です。

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

ログレベルには debug, info, notice, warn, error, crit, alert, emerg が設定可能です。

続いてプロセスIDの記載先となるPIDファイルの格納先の指定です。

pid        /var/run/nginx.pid;

プロセスIDが記載されます。


次にあるのは events コンテキストです。

events {
    worker_connections  1024;
}

nginx の設定ファイルでは、<モジュール名> { } という形でそれぞれのモジュールに対する設定を行います。

指定したモジュールのスコープは { } で囲まれた範囲となり、これをコンテキストと呼びます。

先に見た設定値はルートに配備されており、これを main コンテキストと呼びます。

events コンテキストでは、 worker_connections とにて、イベントループを行う worker プロセスで同時に受付可能な接続数を定義しています。


次にあるのが http コンテキストであり、web サーバの設定をここに記載します。

http コンテキストの先頭にあるのは、MIMEタイプのマッピングファイルのインクルードです。

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

default_type では、マッピング定義が存在しない場合の content-type を定義しています。


次にあるのはアクセスログのフォーマット定義です。

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

main という名前でアクセスログに出力する項目を定義しています。変数についてはAlphabetical index of variables が参考になります。

続く行で main として定義したログフォーマットを使い、アクセスログに出力場所を定義しています。

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


次にあるのが以下のような http 通信に関する設定です。

sendfile        on;
#tcp_nopush     on;
keepalive_timeout  65;
#gzip  on;

それぞれ以下の設定になります。

  • sendfile クライアントへのレスポンス送信に sendfileシステムコール を利用するかどうか(I/Oパフォーマンスが向上するが一部の環境で不具合が発生する場合がある)
  • tcp_nopush on とすることで(sendfile が on の場合)レスポンスヘッダどレスポンスボディをまとめて送信するようになりパケットの利用が効率的になる
  • keepalive_timeout サーバのkeepaliveタイムアウト秒数を設定。タイムアウト内の連続したリクエストにコネクションが使い回されるようになる
  • gzip コンテンツをgzip 圧縮して通信量を減らす。デフォルトで圧縮対象は text/html となるため、他のコンテンツを対象にするには gzip_types text/css text/javascript; のように指定する


http コンテキストの最後では別の設定ファイルを読み込んでいます。

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

対象ディレクトリには default.conf があり、以下のように定義されています。

server {
    listen       80;
    server_name  localhost;

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }
}

http コンテキストの中の server コンテキストになります。

server コンテキストは複数を並列に書くことで、バーチャルホストを複数定義できます。通常は xxx.conf のような定義を /etc/nginx/conf.d/ 配下に配備することになります。

設定内容を見ていきます。最初はこのバーチャルホストの待ち受けポートとバーチャルホストのサーバ名を定義しています。

listen       80;
server_name  localhost;

server_name はスペース区入りで複数書くこともできますし、正規表現やワイルドカードを使って書くこともできます。HTTPリクエストの Host ヘッダから、該当するバーチャルホストが選択されます。

Host ヘッダ名にマッチするものが無かった場合のデフォルトを指定する場合には以下のように指定しておくことで、対象のバーチャルホストが選択されます。

listen       80 default_server;


次にあるのが location ディレクティブで、HTTPリクエストパスに応じたコンテキストを定義します。

location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
}

root ディレクティブでは対象のパスに対応したドキュメントルートを指定します。

index ディレクティブでは、ここでの例では localhost/ でアクセス時に利用されるファイルを指定します。


最後にあるのがエラーレスポンス用のページの定義となります。

error_page   500 502 503 504  /50x.html;
location = /50x.html {
    root   /usr/share/nginx/html;
}

error_page ディレクティブでは、HTTPレスポンスコードに応じたエラーページを指定しています。この例では /50x.html ファイルにリダイレクトします。

location ディレクティブは先の説明と同様で、リダイレクトしたパスに応じたドキュメントルートを指定しています。エラーページは /50x.html ファイルでカスタマイズすることができます。


default.conf をローカル側で編集するには docker-compose.yml を以下のようにしてマウントします。

version: '3.8'
services:

  nginx:
    container_name: "nginx"
    image: nginx
    ports:
      - "80:80"
    volumes:
      - ./default.conf:/etc/nginx/conf.d/default.conf:ro
      - ./html:/usr/share/nginx/html

default.conf のマウントは読み込み専用のアクセス(ro) として指定しています(読み書きの場合は rw を指定できます)。


location ディレクティブのマッチング

location ディレクティブは引数のパスに応じたコンテキストを作成します。

パス名はいくつかの書式が用意されています。

  • location <pass> { } パス名の前方一致。/ とすると全てのパスにマッチする
  • location = <pass> { } パス名の完全一致
  • location ~ <pattern> { } 正規表現でパス名にマッチするパターンを指定する
  • location ^~ <pattern> 正規表現より優先度の高い前方一致
  • location @<name> パス名に直接マッチしない名前付きロケーション

名前付きロケーションは以下のように利用します。

location / {
  try_file $uri @fallback
}
location @fallback {
  ...
}

try_file ディレクティブは指定されたレスポンスが見つかるかを試行し、レスポンス用のファイルが見つからなければ名前付きロケーションとなっている @fallback を試行します。


location ディレクティブの優先順位は 完全一致 > 最長の前方一致で ^~ が付いたもの > 正規表現による最初の一致 > 最長の前方一致 の順番になります。


アクセス制限を行う

IPアドレスによりアクセス制限を行うには location ディレクティブ内に、allowdeny にてIPアドレスを指定することで可能です。

location /private {
    allow 192.168.1.0/24;
    deny all;
}

アクセス制限は、上から見ていき最初に一致した設定内容で制御が行われます。


Basic 認証を行うには、auth_basic_user_file ディレクティブを指定します。

location /private {
    auth_basic "Basic Auth";
    auth_basic_user_file /etc/nginx/htpasswd;
}

auth_basic には何らかの文字列を設定すれば Basic 認証が on となります。ブラウザによってはこの文字列を認証画面に表示することがあります。off とする場合は off と記載すれば良いです。

パスワードファイルは htpasswd コマンドで作成します。

$ htpasswd -b -c htpasswd user pass

$ cat htpasswd
user:$apr1$aaM0XmBZ$Ibx...

とすることで htpasswd ファイルが作成されます。-c でパスワードファイルの新規作成、-b で対話形式でなく、コマンドラインからのオプションでユーザ名とパスワードを指定する意味となります。

docker-compose.yml で以下のようにマウントすればBasic認証が使えます。

    volumes:
      - ./htpasswd:/etc/nginx/htpasswd:ro