nginx
HTTP サーバ
特徴
- C10K 問題を解消
- イベント駆動
- I/O Multiplexing
- ノンブロッキング I/O
- 非同期 I/O
アーキテクチャ
- イベント駆動
- 何らかのイベントが発生するまで待機し、発生したイベントの種類に応じて定められた手順を実行
- システムコール
- epoll
- inotify
- sigaction
- ライブラリ
- libevent
- libuv
- Web サーバのように同時に複数の処理を行うシステムでは、ディスクやネットワークといった I/O の多重化が必要
- I/O 多重化を実装する select / poll といったシステムコールが利用される
- プログラムがアクセスするファイルやネットワークソケットなどのファイルディスクリプタを 1 つ 1 つチェックするため、チェックするディスクリプタが増えると処理も増える
- O(n)
epoll
はディスクリプタの状態がカーネル内で管理されるため、プログラムはディスクリプタを 1 つ 1 つチェックする必要が無くなる- O(1)
- I/O 多重化を実装する select / poll といったシステムコールが利用される
I/O Multiplexing
- 複数のファイルディスクリプタを監視し、それらのうちどれかが入出力可能になるまでプログラムを待機させる手法
- これにより複数のクライアントのディスクリプタとの入出力を並行して行うことができる
ノンブロッキング I/O
- I/O 関連のシステムコールによってプログラムがブロックされる見込みの場合やまだ処理できるデータがない場合にエラーを返し、適切な errno がセット
- すぐに処理できないディスクリプタとの入出力処理は中断して別のディスクリプタとの入出力処理に移ることでプログラムの並行性を高めることができる
- 非同期 I/O
- 入出力処理が開始されてもプログラムをブロックせず、入出力処理とそれ以外の処理を並行して実行するための仕組み
- 動的コンテンツ
- 動的コンテンツは SSI(Server Side Include) 以外は扱えない
- nginx とは別プロセスでアプリケーションプログラムを可動させる必要がある
動作モデル
- マルチプロセス構成
- マスタープロセス
- ワーカープロセスの制御と管理
- ワーカープロセスの PID を保持しているので設定ファイルの再読込などはマスタープロセスに対してシグナルを通して命令するだけで nginx 全体のプロセスを制御できる
- ワーカープロセス
- クライアントからの接続要求にはじまる一連の処理をイベント駆動で実行
- シングルスレッドで動作
- マスタープロセス
Install
-
設定ファイル準備(/etc/yum.repos.d/nginx.repo)
[nginx] name=nginx repo baseurl=http://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=0 enabled=1
install
# yum install nginx
conf チェック
# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
設定ファイルが別のデフォルト以外にある場合
# nginx -c /path/to/nginx.conf
起動
# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) # systemctl start nginx # ps auxfww | grep [n]ginx root 3777 0.0 0.1 46320 968 ? Ss 15:57 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf nginx 3778 0.0 0.3 46720 1928 ? S 15:57 0:00 \_ nginx: worker process
reload
は現在処理中のリクエストは中断しない
- バージョン
- stable 版
- API 非互換はありえない
- 高いバグ修正のみ取り込まれる
- mainline 版
- 新機能やバグフィックスが最初に取り込まれる
- API 非互換がありえる
- 通常はこちらを利用する
- stable 版
基本設定
- main ディレクティブ
- events ディレクティブ
- http ディレクティブ
- server ディレクティブ
- location ディレクティブ
url に応じてバックエンドサーバの振り分けを変更する
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 /team01 { rewrite ^/(.+) $1 break; proxy_pass http://127.0.0.1:3001/$1; } location /team02 { rewrite ^/(.+) $1 break; proxy_pass http://127.0.0.1:3002/$1; }
リバースプロキシ
nginx を経由してバックエンド( Apache 等)が処理
注意
- Apache のアクセスログを見るとアクセス元が 127.0.0.1 になっている
- mod_rpaf の導入
- nginx の設定に X-Real-IP を HTTP ヘッダに追加する設定が必要
- mod_rpaf はプロキシサーバーが追加した X-Real-IP ヘッダをアクセス元として扱うモジュール
- mod_rpaf は 127.0.0.1 からのアクセスだけに対して処理をするのでもし、リバースプロキシが他のホストにあるのであれば /etc/apache2/mods-enabled/rpaf.conf の RPAFproxy_ips をリバースプロキシサーバーのIPアドレスに変更する
- Apache のアクセスログを見るとアクセス元が 127.0.0.1 になっている
リバースプロキシ設定 1
server { location / { // リクエストボディのバッファリングに関する設定 client_max_body_size 8m; client_body_buffer_size 16k; client_body_temp_path /dev/shm/nginx_client_body_temp; // アップストリームサーバからのレスポンスのバッファリングに関する設定 proxy_buffering on; proxy_buffer_size 8k; proxy_buffers 64 8k; proxy_max_temp_file_size 1024m; proxy_temp_path /dev/shm/nginx_client_body_temp; // タイムアウトに関する設定 proxy_connect_timeout 5s; proxy_send_timeout 10s; proxy_read_timeout 10s; // アップストリームへ proxy_pass http://172.17.0.3; // ソケット経由 // proxy_pass http://unix:/var/run/nginx.sock:/api/; } }
リバースプロキシ設定 2
upstream backend { server 127.0.0.1:8080; } server { listen 80; server_name _; location / { proxy_redirect off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Server $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://backend; } }
Apache HTTPD からの乗り換えポイント
乗り換え時のポイント
動的機能の対応
- CGI や PHP などの動的機能の利用を考える
- nginx をリバースプロキシとして利用し、バックエンドのサーバ(upstream ディレクティブ指定) に動的機能を任せる形
- FastCGI や Apache(mod_php) を併用
- SSI は対応しているがすべての SSI コマンドには対応していない
コンテンツのストレージ
コンテンツキャッシュ機能において、キャッシュのストレージはディスクのみ
- Apache 2.4 で言う mod_cache_disk のみが可能
tmpfs
- キャッシュをオンメモリで処理したい場合には、キャッシュの保存場所を tmpfs にする
- CentOS 7
- /dev/shm
allow, deny でホスト名の指定
- nginx の allow ディレクティブや deny ディレクティブには、ホスト名での指定ができない
- どうしてもホスト名での指定が必要な場合には、ngx_http_rdns_module などのサードパーティモジュールを検討してみる
コンテンツレベルでの設定上書き
- nginx では .htaccess が無いので、サーバ管理者の作業(nginx の reload 等) が必要
ログフォーマットの互換性
- log_format ディレクティブで任意に設定できるため、Apache と揃えることが可能
- %D (応答時間) の単位に注意
- nginx($request_time) の単位はミリ秒
- Apache($D) はマイクロ秒
CPU・メモリなどのリソース、キャパシティ
静的コンテンツ配信のサーバを Apache から nginx に変更すると、nginx のイベントドリブン実装が影響し、CPU 利用率、メモリ使用量は少なくなる
メモリ使用量
- nginx と Apache で 100 並列アクセス(keepalive 接続)した状態のメモリ使用量を確認
- nginx の優位性
設定ファイルのコンバート
SSL 中間証明書の設定方法
- Apache は SSLCertificateChainFile ディレクティブで中間証明書の指定を行なうが、 nginx にはない
- nginx では SSL 証明書の下部に中間証明書を追記する
Apache 設定ファイルの秘匿
nginx に移行した際に、.ht〜 ファイル(.htaccess や .htpasswd) が外部から意図せずアクセスできる状態にならないように設定を入れる
location ~* \.ht.*$ { deny all; }
mod_rewrite の書き換え
- mod_rewrite の移植が難しい
設定ファイル以外の変更
ログローテーション
- Apache で rotatelogs プログラムを使っている場合は、ログローテーションのための外部設定は必要ないけど、nginx にはない
- rpm でインストールすると logrotate の設定が
/etc/logrotate.d/nginx
に入る
Security
クライアントの IP アドレスでアクセスを制限する
location / { # 192.168.1.1 からのアクセスを拒否 deny 192.168.1.1; # サブネット単にでの拒否 deny 192.168.2.0/24 ; # 特定の IP アドレスを許可 allow 192.168.3.1; # サブネット単位で許可 allow 192.168.4.0/24; # 他はすべて拒否 deny all; }
複数の IP を 1 行で指定することは不可
最初に deny all; を指定してしまうと 2 行目の allow 以降は評価されない
location / { deny all; allow 192.168.3.1; ... }
ホスト名やドメイン名を指定することは不可
ユーザエージェントタイプでアクセスを制限する
- ★
HTTP メソッドを制限する
GET と HEAD と POST に限定してみる。それ以外は 444 を返して、クライアントには応答せず、コネクションを閉じる
if ($request_method !~ ^(GET|HEAD|POST)$) { return 444; }
ユーザ認証を設定
server ディレクティブのコンテキストで指定するとバーチャルサーバ単位で設定可能
http ディレクティブのコンテキストでは Nginx 単位でユーザ認証を実施できるようになる
auth_basic ディレクティブを off に指定すると、Basic 認証方式のアクセス制限を無効にする
サンプル
location / { auth_basic "Restricted"; auth_basic_user_file /etc/nginx/passwd; }
バーチャルサーバ単位でユーザ認証を有効にしつつ、特定のディレクトリだけユーザ認証を行わないようにする
server { ... auth_basic "closed website"; auth_basic_user_file /etc/nginx/passwd; location /public/ { auth_basic off; } }
複数のアクセス制限を組み合わせる
ホットリンク(直リンク) を禁止する
X-Frame-Options ヘッダ対策
X-Content-Type-Options ヘッダ対策
X-XSS-Protection ヘッダ対策
Content-Security-Policy ヘッダ対策
不要なモジュールの見直し
バージョン情報を隠蔽
server_tokens
DoS / DDoS 攻撃によるメモリ枯渇に備える
- client_body_buffer_size
- client_header_buffer_size
- client_max_body_size
- large_client_header_buffers
ModSecurity
CRS(ModSecurity Core Rule Set)
iptables でパケットフィルタリング
SELinux を利用する
SYN flood 攻撃対策
無効
# sysctl -w net.ipv4.tcp_syncookies=0
ブロードキャスト ping に応えない(Smurf 攻撃対策)
応えない
# sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
RFC 1337 に準拠させる
準拠させると TIME_WAIT 状態の時に RST を受信した場合、TIME_WAIT 期間の終了を待たずにそのコネクションをクローズできるようになりたい
# sysctl -w net.ipv4.tcp_rfc1337=1
TIME-WAIT ソケットを高速にリサイクルする
# sysctl -w net.ipv4.tcp_tw_recycle=1
- TIME_WAIT 状態のコネクションを再利用すると、TIME_WAIT 状態を管理するためのキャッシュがオーバーフローするのを防ぎ、TIME_WAIT 状態のコネクションを減らすことができる
DoS 対策攻撃
- TIME_WAIT 状態のコネクションが大量に残るような場合、最終 FIN パケットを待つ時間を短くすることで解消することができる
# sysctl -w net.ipv4.tcp_fin_timeout=15
Ping of Death(PoD) 攻撃対策
ICMP リダイレクトパケットを拒否する
- ICMP リダイレクトパケットを送信することで、ルーティング情報を変更することができるようになる
- 不正な ICMP リダイレクトパケットによりネットワーク経路を強制的に変更され、パケットの盗聴や改ざんされると言った危険にさらされる可能性がある
# sysctl -w net.ipv4.conf.*.accept_redirects=0
- 設定は全ネットワークインタフェースに対して行なう必要がある
- 起動時には次のようなシェルスクリプトを実行し有効化する
IP スプーフィング攻撃対策
送信元ホストの IP アドレスを偽装したパケットによる攻撃
対策としては、Linux で送信元ホストの IP アドレスが正しいかどうかを確認するようにする
# sysctl -w net.ipv4.conf.*.rp_filter=1
- 設定は全ネットワークインタフェースに対して行なう必要がある
- 起動時には次のようなシェルスクリプトを実行し有効化する
ソースルーティングされたパケットを拒否
ソースルーティングを使うと、中継ルータを指定することができる
これを悪用すると、送信元の IP アドレスを詐称して送信先ホストと IP 通信を行なうことが可能になる
SSR オプションがついたパケットを拒否することで、ソースルーティングされたパケット無効化できる
# sysctl -w net.ipv4.conf.*.accept_source_route=0
- 設定は全ネットワークインタフェースに対して行なう必要がある
- 起動時には次のようなシェルスクリプトを実行し有効化する
HTTPS を強制する
DH パラメーターを強固にする
暗号化プロトコルの設定
- 使用する TLS/SSL のバージョンを限定する
- SSLv2, SSLv3 を使用しない
- 使用されているかどうかは curl コマンドで確認できる
- 使用する暗号化スイートを限定する
- サーバ側が指定した暗号スイートを優先する
- 使用する TLS/SSL のバージョンを限定する
Cacti
pecrona 使用
下記を追加(/etc/nginx/default.conf)
location /server-status { stub_status on; access_log off; allow 127.0.0.1; deny all; }
local から接続確認
# curl localhost/server-status Active connections: 1 server accepts handled requests 1019 1019 1112 Reading: 0 Writing: 1 Waiting: 0
item content Active connections 現在の接続数 server accepts handled requests 接続数
ハンドラ数
1 リクエスト当たりのハンドラ数Reading リスクエストヘッダ読み取り数 Writing リクエストに応じた応答数 Waiting キープアライブ数
active - (reading + writing)
Stream
- 任意のポートで TCP 接続を待ち受けることができる
- ngx_stream_core_module
References
設定ファイルをいい感じに出力してくれる
-
- 設定フィアルの改善提案ツール
パフォーマンス
ファイルオープン
- worker_rlimit_nofile
- 1 プロセスで同時にオープン可能なファイルディスクリプタの数を指定
- open_file_cache
- 一度オープンしたファイルを一定期間保存
open_file_cache max=1000 inactive=60s
- キャッシュは最大 1000 登録でき、キャッシュに最後にアクセスがあってから 60 秒間有効
- open_file_cache_errors
- オープンしたファイルのエラー情報のキャッシュ設定
- worker_rlimit_nofile
CPU
- worker_cpu_affinity
- 各ワーカープロセスを特定の CPU コアに割り当てることができる
- CPU の割り当ては各プロセスをどの CPU コアに割り当てるか 2 進数のビットマスクで指定
worker_cpu_affinity 0001 0010 0100 1000;
- 4 コアに対して 4 つのワーカープロセスがそれぞれ 1 つずつ CPU コアを使用
- あんまり使用しない
- worker_priotiry
- worker_cpu_affinity
- open_file_cache_valid
- open_file_cache_min_uses
- open_file_cache_errors