2021.08.14  

【Nginx設定】Docker-composeとDjangoを組み合わせた際の設定

docker-composeでNginx、MySQL、Djangoのコンテナを構築したものの、

Nginxの設定があまり理解できていないと思い、実際に動作しているnginx.conf、default.confに解説を加えるかたちで、内容のまとめを行いました。uwsgi周りの設定についても記述しています。

当記事を作成するにあたり、以下書籍を参考にさせて頂いています。

こちらの書籍はKindle Unlimited の会員であれば無料で読むことができます。

基本的な設定ファイルと配置先

Nginxは主に次のファイルを読み込んで実行されます。

ファイル名 配置先 説明
nginx.conf /etc/nginx 最初に読み込まれる設定ファイル。他の設定ファイルはこのファイルから読み込む(当設定ファイル内でincludeを使用する)
default.conf /etc/nginx/conf.d ポート番号やドキュメントルートの設定等、Webサーバーとしての基本的な設定をおこなう
fastcgi_params /etc/nginx FastCGIのパラメーターとNginx変数とのマッピングを記載
scgi_params /etc/nginx SCGIのパラメーターとNginx変数とのマッピングを記載
uwsgi_params /etc/nginx uWCGIのパラメーターとNginx変数とのマッピングを記載。Djangoで使う
mime.types /etc/nginx ファイルの拡張子とContent-Typeのマッピングテーブル

参考:nginx実践ガイド (impress top gear) 30p

nginx.confの記述例

nginx.conf
# workerが動作するユーザー名。通常は変更不要
user  nginx;
# workerプロセスの数を設定
worker_processes  1;

# エラーログの設定。第一引数に出力先、第二引数にログレベルを設定
error_log  /var/log/nginx/error.log warn;
# プロセスIDを記述したファイルを指定
pid        /var/run/nginx.pid;

# イベントコンテキスト
events {
    # ひとつのプロセスが受付られる接続数
    worker_connections  1024;
}
 
# httpコンテキスト。webサーバー全体の設定を記述する。
http {
 # 設定ファイルmime.typeの読み込み
    include       /etc/nginx/mime.types;
 # mime.typeが設定されていない際の設定
    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;
    keepalive_requests 1000;
    client_header_timeout 100;
    client_body_timeout 100;

    # default.conf の読み込み
    include       /etc/nginx/conf.d/default.conf 
}

nginx.confの設定解説

user

# workerが動作するユーザー名。通常は変更不要
user  nginx;

・構文
user user [group];

workerプロセスを実行するユーザーとグループを設定する。

userとgroupはnginxインストール時のオプション--user=ユーザ名 --group=グループ名で指定した値がnginx.confに設定される。

apt-getでのインストール時に、対象オプションを指定しなかった場合は、--user=nginx、--group=nginxがデフォルトで指定される。

nginx.confの設定からgroupを省略すると、userと同じ名前でgroupの値が設定される。

参考:https://gakumon.tech/nginx/nginx_simple_directives_02.html


worker_processes

# workerプロセスの数を設定
worker_processes  1;

・構文
worker_processes number | auto;
コンテキスト main

ワーカープロセスの数を定義します。

最適な値は、CPUコアの数、データを格納するハードディスクドライブの数、負荷パターンなど、多くの要因によって異なります。

特に拘りがなければ、使用可能なCPUコアの数を設定することが推奨されます。(値「auto」はそれを自動検出しようとします)。

マニュアル:Nginx - worker_processes


error_log

# エラーログの設定。第一引数に出力先、第二引数にログレベルを設定
error_log  /var/log/nginx/error.log warn;

・構文
error_log file [level]
コンテキスト main

ロギングを構成します。複数のログを指定することができます。

メイン構成レベルでファイルへのログの書き込みが明示的に定義されていない場合は、デフォルトのファイルが使用されます。

2番目のパラメーターは、ロギングのレベルを決定し、debug、info、notice、warn、error、crit、alert、またはemergのいずれかになります。記載したログレベルは、重大度の高い順にリストされています。

特定のログレベルを設定すると、指定されたより重大なログレベルのすべてのメッセージがログに記録されます。たとえば、デフォルトレベルのerrorにより、エラー、クリティカル、アラート、および緊急メッセージがログに記録されます。

このパラメーターを省略すると、エラーが使用されます。

マニュアル:Nginx - error_log


pid

# プロセスIDを記述したファイルを指定
pid        /var/run/nginx.pid;

・構文
pid file
コンテキスト main

メインプロセスのプロセスIDを格納するファイルを定義します。

マニュアル:Nginx - pid


worker_connections

# ひとつのプロセスが受付られる接続数
 worker_connections  1024;

・構文
worker_connections number
コンテキスト main

ワーカープロセスが開くことができる同時接続の最大数を設定します。

この数には、クライアントとの接続だけでなく、すべての接続(プロキシサーバーとの接続など)が含まれることに注意してください。

もう1つの考慮事項は、同時接続の実際の数は、後述するworker_rlimit_nofileによって変更できる、オープンファイルの最大数の現在の制限を超えることはできないということです。

マニュアル:Nginx - worker_connections


worker_rlimit_nofile

# --- 今回のnginx.confの記述例には記載していない ---

・構文
worker_rlimit_nofile number
コンテキスト main

RLIMIT_NOFILEワーカープロセスの オープンファイルの最大数を変更します。メインプロセスを再起動せずに最大数を増やすために使用されます。

マニュアル:Nginx - worker_rlimit_nofile


include /etc/nginx/mime.types;

include /etc/nginx/mime.types;

mime.types(マイムタイプ)ファイルを読み込む。Apacheでいうところの.htaccess ファイル。
設定ファイルは以下のように記述されている。

types {
    text/html                                        html htm shtml;
    text/css                                         css;
    text/xml                                         xml;
    image/gif                                        gif;
    image/jpeg                                       jpeg jpg;
    application/javascript                           js;
    application/atom+xml                             atom;
    application/rss+xml                              rss;
    # 以下省略
}

mime.typesは、MIMEタイプと拡張子の関連付けを定義したファイルです。

MIMEタイプとは、電子メール、Webで使用され、Webではデータの種類を表すコード(Content-Type)として利用されます。

上記の例でいうと、WEBサーバー(Nginx)は、「.css という拡張子のファイルは text/css というMIMEタイプのデータとして送信する」処理を行ってくれる。

ブラウザが hoge.css というファイルをWEBサーバーに要求すると、WEBサーバーはhoge.cssの内容を「これは text/cssタイプのデータです」と言いながら返却してくれます。

参考:IT用語辞典拡張子とMIMEタイプMIMEタイプとは


default_type

 default_type  application/octet-stream;

応答のデフォルトのMIMEタイプを定義します。

application/octet-streamはファイルの種類が分からない時に使用するMIMEタイプです。

参考:application/octet-stream【MIMEタイプ】とは典


log_format

・構文
log_format name [escape=default|json|none] string ...;
コンテキスト http

ログフォーマットを指定する。

マニュアル:Nginx - log_format


access_log

・構文
access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
access_log off
コンテキスト http, server, location, if in location, limit_except

バッファリングされたログ書き込みのパス、形式、および構成を設定します。同じ構成レベルで複数のログを指定できます。
Syslogへのログ記録は、最初のパラメーターに「syslog:」プレフィックスを指定することで構成できます。
特別な値offは、現在のレベルのすべてのaccess_logディレクティブをキャンセルします。
形式が指定されていない場合は、事前定義された「結合」形式が使用されます。

マニュアル:Nginx - access_log


sendfile、tcp_nopush

sendfile on;
tcp_nopush  on;

・構文
sendfile on | off;
コンテキスト http, server, location, if in location

sendfileの使用を有効または無効にします。

sendfileディレクティブはコンテンツのファイルの読み込みとクライアントへのレスポンスの送信にsendfile() APIを使うかを設定します。
sendfile()を使うとカーネル空間内でファイルの読み込みと送信が完了するため、効率良くファイルの内容をクライアントに送信できます。
デフォルトの設定値はoffです。

・構文
tcp_nopush on | off;
コンテキスト http, server, location

sendfileが有効なとき適用される。
Linuxの場合はTCP_CORKソケットオプションを使うかどうかを設定します。
このオプションを使うと、レスポンスヘッダとファイルの内容をまとめて送るようになり、少ないパケット数で効率良く送ることができます。

参考:sendfile, tcp_nopush
マニュアル1:Nginx - sendfile
マニュアル2:Nginx - tcp_nopush


keepalive_timeout

keepalive_timeout  65;

・構文
keepalive_timeout timeout [header_timeout];
コンテキスト http, server, location

最初のパラメーターは、サーバー側でキープアライブのタイムアウトを設定します。
ゼロの値は、キープアライブを無効にします。 (Apache ではKeepAliveTimeout)

キープアライブとは、WEBサーバーとクライアント(ウェブブラウザ)の通信時にHTTP通信を切断せずに、HTTP通信を送受信する仕組みです。
ここで言うキープアライブとは、http KeepAliveのことで、これを有効にすると1つの TCP コネクションの中に複数の HTTP リクエストを実行できる。
これにより通信の効率化が図れます。

・http KeepAliveなしの通信の流れ (keepalive_timeout 0;)

3way_handshake → GETメソッド1 → FIN/ACK
3way_handshake → GETメソッド2 → FIN/ACK
3way_handshake → GETメソッド3 → FIN/ACK

・http KeepAliveありの通信の流れ(keepalive_timeout timeout;)

3way_handshake → GETメソッド1 → GETメソッド2 → GETメソッド3 → FIN/ACK

keepalive_timeout に秒数を設定するとhttp KeepAliveを有効にした上で、何秒でこの通信がタイムアウトするのかを設定できます。

参考1:Nginx のKeep-aliveの設定
参考2:【図解】TCP Keep-Alive/http Keep-Aliveの仕組みと違い
マニュアル:Nginx - keepalive_timeout


keepalive_timeout

keepalive_requests 1000;

・構文
keepalive_requests number;
デフォルト keepalive_requests 1000;
コンテキスト http, server, location

1つのキープアライブ接続を介して処理できる要求の最大数を設定します。
最大数の要求が行われた後、接続は閉じられます。 接続ごとのメモリ割り当てを解放するには、接続を定期的に閉じる必要があります。
したがって、リクエストの最大数が多すぎると、メモリ使用量が過剰になる可能性があるため、お勧めしません。

マニュアル:Nginx - keepalive_requests


client_header_timeout

client_header_timeout 100;

・構文
keepalive_requests number;
デフォルト client_header_timeout 60s;
コンテキストhttp, server

クライアント要求ヘッダーを読み取るためのタイムアウトを定義します。
クライアントがこの時間内にヘッダー全体を送信しない場合、要求は408(要求タイムアウト)エラーで終了します。

マニュアル:Nginx - client_header_timeou


client_body_timeout

client_body_timeout 100;

・構文
client_body_timeout time;
デフォルト client_body_timeout 60s;;
コンテキストhttp, server, location

クライアント要求本文を読み取るためのタイムアウトを定義します。
タイムアウトは、要求本文全体の送信ではなく、2つの連続する読み取り操作の間の期間にのみ設定されます。
クライアントがこの時間内に何も送信しない場合、要求は408(要求タイムアウト)エラーで終了します。

マニュアル:Nginx - client_body_timeout

default.confの記述例

default.conf
upstream django {
    ip_hash;
    server python:8001;
}

# サーバーコンテキスト
server {
    # 待ち受けポート番号
    listen 80;
    # バーチャルホストサーバーのホスト名を指定。IPアドレスでも可
    server_name example.com;
    # 80ポートにアクセスされた際はhttps://example.com(443ポート)にリダイレクトする
    return 301 https://example.com;
    }

server {
    listen 443; 
    server_name example.com;
    charset     utf-8;
    client_max_body_size    100M;
    ssl on;
    ssl_certificate /ssl/fullchain.pem;
    ssl_certificate_key /ssl/privkey.pem;

    # ロケーションディレクティブ
    location /static {
        alias /web_app_src/static;
    }

    location /media {
        alias /web_app_src/media;
    }

    location / {
        # uwsgiのアドレスを指定する。Djangoでuwsgi --socket :8001を実行しているなら172.0.0.1:8001にアクセスする
        uwsgi_pass  django;
        include     /etc/nginx/uwsgi_params;
    }

    # Djangoを使わない場合のlocationの設定
    # location / {
    #     # ドキュメントルートを設定する場合はrootを使う
    #     root /www/dir;
    #     # ドキュメントルートにアクセスがあった際に表示するファイル
    #     index     index.html index.html;
    # }
    }
}


upstream

upstream django {
    ip_hash;
    server python:8001;
}

・構文
upstream name { ... }
コンテキストhttp

サーバーのグループを定義します。
これはロードバランシングを使用したい場合などに設定します。
今回はロードバランシングを使用していませんが、使用する場合はserverを複数設定します。

upstream backend {
    ip_hash;
    server backend1.example.com;
    server backend2.example.com;
    server backend3.example.com down;
}

serverサーバーのアドレスおよびその他のパラメーターを定義します。
さまざまなポートでリッスンでき、TCPドメインソケットとUNIXドメインソケットをリッスンしているサーバーを混在させることができます。

アドレスは、オプションのポートを使用してドメイン名またはIPアドレスとして指定するか、「unix:」プレフィックスの後に指定されたUNIXドメインソケットパスとして指定できます。

ソケットとは、プログラムとネットワークをつなげる接続口のことです。

UNIXドメインソケットとは、LinuxなどのUNIX系OS(オペレーティングシステム)で実行されるプロセス間のデータ通信の終点に使われるインターフェースのことです。

ポートが指定されていない場合は、ポート80が使用されます。

ip_hash;はクライアントのIPアドレスに基づいてロードバランスを行う設定です。
これを設定すると接続するクライアントと接続先のサーバーが常に同じになります。

たとえば以下のようにクライアント1 がbackend1サーバーに接続された場合、backend2、3サーバーには接続されないようになります。
クライアント1 ⇨ backend1サーバー

server python:8001;

serverの接続先がpythonとなっているのはDocker-composeを使用しているからです。

docker-compose.yamlでは次のような設定をしています。

services:
   python:
        build: ./python
        command: uwsgi --socket :8001 --module project.wsgi --py-autoreload 1 --logto /tmp/uwsgi.log
      ・・・・・

docker-compose.ymlで宣言したサービスは、docker-compose upなどでコンテナ起動すると、同一のネットワークに所属することになります(Dockerネットワークと呼ぶ)。
そして、それぞれホスト名が割り当てられる。そのホスト名はサービス名、もしくはdocker-compose.ymlで指定したコンテナ名となります。
上記の場合、サービス名に当たる部分はpython:となります。

serverのポート設定8001はuwsgiへの接続先です。

WSGIとは、PythonのWebアプリケーションとWebサーバー間とのやり取りの規約、プロトコールのことでPEP333で定義されています。
Pythonの大抵のWebフレームワーク(Djangoを含む)はこのWSGIという規約に則っています。

uWSGIとは、PythonでWebサービスを動かすためのアプリケーションサーバの一種です。
上記のWSGIに則ったアプリケーションを動作させるアプリケーションサーバをWSGIアプリケーションコンテナやWSGIサーバなどと呼びます。

uWSGIは、UNIXドメインソケット、またはHTTPで通信することが可能です。

今回使用しているのはUNIXドメインソケットです。

uwsgi コマンドの引数に--socket :8001と指定することで、ホストpythonの8001ポートに接続するとuWSGIに接続されます。

余談ですがポートとソケットの違いについて記載しておきます。

ポートはTCP / IPネットワーキングの概念であり、「ソケット」はAPI(プログラミング)のことです。
ソケットは、ポートとホスト名またはネットワークアダプターを取得し、それらを組み合わせてデータ構造を作成し、データの送受信に使用することで作成されます。

--module project.wsgiについては、Djangoのwsgi.pyの配置先(src/project/wsgi.py)を記述しています。

参考1: Nginx - upstream 
参考2: Nginx - server 
参考3:8.3.3 ip_hash
参考4:ソケット(英:socket)とは
参考5:ip_hash
参考6:docker-composeとネットワーク、ホスト名の割りあて
参考7:uWSGI入門
参考8:【公式】uWSGIの構成
参考9:ポートとソケットの違いはなんですか?


server {・・・}

server {
    listen 443; 
    server_name example.com;
    charset     utf-8;
    client_max_body_size    100M;
    ssl on;
    ssl_certificate /ssl/fullchain.pem;
    ssl_certificate_key /ssl/privkey.pem;

listen

listenディレクティブにはバーチャルサーバがリクエストを受け付けるIPアドレス、ポート番号、UNIXドメインソケットを設定します。

listen IPアドレス:ポート番号;

IPアドレスを省略するとサーバーの全てのインターフェイスから接続を受け付ける。
またポート番号を省略すると80ポートがデフォルトで設定される。
つまり、listenを省略すると次の設定と同じになる。

listen *:80;

参考:nginxの設定

server_name

nginxは HTTP リクエストに対して、最初にどのサーバでそれを処理すべきかを決定します。
その際使われるのが、リクエストヘッダ中の Host フィールドです。
つまりHost フィールドと server_name が一致したserver {・・・}の設定が使用されます。

server_name と Hostフィールドの名前が一致 しなかった場合は、デフォルトのサーバでリクエストは処理されます。
デフォルトのサーバは最初に定義されているサーバになります。
下の例でいうとexample_A.comの設定が使用されます。

server {
    listen 80;
    server_name example_A.com;
    ...
}
server {
    listen 80;
    server_name example_B.com;
    ...
}

記述順でデフォルトサーバーを指定したくない場合は、listen にdefault_serverを設定します。

server {
    listen 80 default_server;
    server_name example_B.com;
    ...
}

該当エラーに対してエラーページを表示させることもできます。

    server {
        listen 80;
        server_name example_A.com;
        error_page 404   /error_404.html
        error_page 500 502   /error_500.html
    }

参考:6.1 名前によるバーチャルサーバ

charset

指定された文字セットを"Content-Type"応答ヘッダフィールドに追加します。
この文字セットがsource_charset ディレクティブで指定された文字セットと違う場合は、変換が実行されます。

参考:ngx_http_charset_module モジュール

client_max_body_size

アップロードするデータの上限を設定できます。
この値が小さいと画像をサーバーにアップロードした際に413 Request Entity Too Largeが発生します。

参考:【Nginx】413 Request Entity Too Large 対処法(Docker-Composeにも対応)

ssl on

sslディレクティブをonに設定すると、SSLが有効になります。

ssl_certificate

SSLを有効にした場合に使用。
サーバ証明書のファイルのパスを指定します。

ssl_certificate_key

SSLを有効にした場合に使用。
プライベート鍵のファイルのパスを指定します。

参考:nginxの設定、その4 - TLS/SSLの設定


location

    location / {
        uwsgi_pass  django;
        include     /etc/nginx/uwsgi_params;
    }

uwsgi_pass

uwsgiのアドレスを指定する。設定は次のように行います。

    location / {
        uwsgi_pass 127.0.0.1:8001;
    }

また、uwsgi_passにはupstreamで設定したグループを使用することができます。

    location / {
        uwsgi_pass  django;
    }

参考1: Nginxサポート
参考2: Nginx - uwsgi_pass 

用語

workerプロセス

Nginxには大まかに2つのプロセスが存在する。

ひとつはmaster、もうひとつはworkerです。

masterはrootユーザーで起動します。

masterが起動すると設定ファイルの読み込み、ソケット待ち受け設定、workerプロセスの起動を行います。

workerプロセスはnginx.confのuserで設定したユーザーが起動します。

workerはmasterが待ち受け設定を行なったソケットを利用し、接続を受け付け、ファイルIOやHTTP、SSL/TLSのプロトコルの処理を行います。

また、masterは複数のworkerを動作させることができます。

参考:nginx実践ガイド (impress top gear) P17

リンク元に戻る


ソケット

192.168.1.1:8000 というような、送信元IPアドレス:送信ポート、 宛先IPアドレス:宛先ポートの組合せのことをソケット(socket)と呼びます。

クライアント (Webブラウザ) も、サーバ (NginxやApache)も、このソケットという単位で通信を管理しています。

(ソケットの解説)【図解】初心者にも分かる TCP/UDP 〜違いや共通点,使い分け,ポート番号,具体例について〜


UNIXドメインソケット

UNIXドメインソケットとは、LinuxなどのUNIX系OSで実行されるプロセス間のデータ通信の終点に使われるインターフェースのことをいう。

通常インターネットで利用しているソケット通信(INETドメインソケット通信)とは異なり、ネットワーク経由ではないローカルマシン上のプロセスが利用するソケットを、UNIXドメインソケットという。

TCPとUDPによるソケット通信は、外部のネットワークに繋がるインタフェースに接続します。

これに対し、Unixドメインソケットでは外部インタフェースへの接続は行いません。

その代わり、カーネル内部で完結する高速なネットワークインタフェースを作成します。

Unixドメインソケットを使うことで、Webサーバ(Nginxなど)とリバースプロキシの間、あるいはWebサーバとデータベースとの間の接続を高速にできる場合があります。

UNIXドメインソケットをサポートするミドルウェアには、Nginx、Unicorn、Mysql、Redis、Memcachedなどがあります。

Unixドメインソケットを開くには、ファイルシステムのパスを指定します。

サーバプロセスを起動すると、ファイルシステム上の指定した位置にファイル(拡張子 .sock)ができます。

そのサーバが作成したファイルに、クライアントプロセスから繋ぎに行きます。

クライアントは、通常のソケット通信のようにIPアドレスとポート番号を使って相手を探すのではなく、 ファイルパスを使って通信相手を探します。

ファイルのパーミッションを使ってアクセス制限を加えることも可能です。

参考1:大塚商会 UNIXドメインソケットとは
参考2:ascii Unixドメインソケット

リンク元に戻る

コメント
@ppu-prof_Si
2024年2月25日9:44
Наша группа профессиональных мастеров приготовлена предложить вам новаторские системы утепления, которые не только обеспечивают надежную защиту от зимы, но и дарят вашему собственности элегантный вид.
Мы деятельны с последними материалами, ассигнуруя долгий запас службы и прекрасные результаты. Изолирование фронтонов – это не только экономия на отапливании, но и трепет о экологической обстановке. Спасательные методы, какие мы претворяем в жизнь, способствуют не только зданию, но и поддержанию природы.
Самое центральное: <a href=https://ppu-prof.ru/>Утепление фасадов под ключ</a> у нас начинается всего от 1250 рублей за квадратный метр! Это доступное решение, которое превратит ваш резиденцию в действител&#
コメントする
コメント入力

名前 (※ 必須)

メールアドレス (※ 必須 画面には表示されません)

送信