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の記述例
# 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の記述例
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
}
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を有効にした場合に使用。
プライベート鍵のファイルのパスを指定します。
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アドレスとポート番号を使って相手を探すのではなく、 ファイルパスを使って通信相手を探します。
ファイルのパーミッションを使ってアクセス制限を加えることも可能です。