Nginxのアーキテクチャと動作原理
Nginxの高いパフォーマンスは、その非同期イベント駆動型アーキテクチャに起因しています。従来のスレッドベースのサーバーとは異なり、Nginxは少数のワーカープロセスで数千の同時接続を効率的に処理できます。
- マスター・ワーカーモデル: マスタープロセスは設定の読み込みとワーカーの管理を行い、実際のリクエスト処理はワーカープロセスが担当します。
- イベント駆動: LinuxのepollやBSDのkqueueなどを利用し、I/O待ち状態でもリソースを消費しません。
- 低メモリフットプリント: プロセス間でメモリを共有する仕組みにより、メモリ使用量を最小限に抑えます。
# プロセス階層の確認
$ ps -ef --forest | grep nginx
root 12345 1 0 10:00 ? 00:00:00 nginx: master process /usr/sbin/nginx
nginx 12346 12345 0 10:00 ? 00:00:00 \_ nginx: worker process
nginx 12347 12345 0 10:00 ? 00:00:00 \_ nginx: worker process
設定ファイルの構造と基礎ディレクティブ
Nginxの設定は、Context(コンテキスト)と呼ばれる階層構造で記述されます。Main context, Events context, HTTP context, Server context, Location contextの順に包含関係にあります。
# グローバル設定
user www-data;
worker_processes auto; # CPUコア数に自動合わせ
pid /run/nginx.pid;
events {
worker_connections 2048; # 1プロセスあたりの最大接続数
multi_accept on; # 可能な限り接続を同時に受け入れる
}
http {
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;
# ログフォーマットのカスタマイズ
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;
server {
listen 80;
server_name example.org;
location / {
root /var/www/html;
index index.html index.htm;
}
}
}
実運用のための構成パターン
1. HTTPS通信の近代的構成
セキュリティを強化したHTTPS設定です。TLS 1.2および1.3のみを許可し、強力な暗号スイートを利用します。
server {
listen 443 ssl http2;
server_name secure.example.com;
# 証明書のパス
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
# SSLプロトコルと暗号化スイート
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
ssl_prefer_server_ciphers off;
# セッションキャッシュ
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# セキュリティヘッダーの付与
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
}
2. 高可用ロードバランシング
バックエンドサーバーのヘルスチェックと負荷分散の実装です。接続数が少ないサーバーへ優先的に振り分ける「Least Conn」アルゴリズムを使用します。
upstream app_cluster {
least_conn; # コネクション数が少ないサーバーへ割り振る
server backend01.internal:8080 weight=5;
server backend02.internal:8080 weight=5;
server backend03.internal:8080 backup; # 待機機
# ヘルスチェック(有料版機能やオープンソース拡張で利用可能)
# keepalive 32;
}
server {
location / {
proxy_pass http://app_cluster;
# リクエストヘッダーの転送
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Port $server_port;
# タイムアウト設定
proxy_connect_timeout 5s;
proxy_read_timeout 30s;
proxy_send_timeout 5s;
}
}
3. 静的コンテンツのキャッシュ戦略
プロキシキャッシュを利用してバックエンドの負荷を低減させます。ブラウザ側のキャッシュとサーバー側のキャッシュを組み合わせた設定です。
# キャッシュ領域の定義
proxy_cache_path /var/cache/nginx/proxy levels=1:2 keys_zone=dynamic_cache:100m max_size=1g inactive=60m;
server {
location ~* \.(?:jpg|jpeg|gif|png|css|js|ico|svg)$ {
proxy_pass http://backend_origin;
proxy_cache dynamic_cache;
# キャッシュキーの定義
proxy_cache_key "$scheme$request_method$host$request_uri";
# ステータスコードごとのキャッシュ期間
proxy_cache_valid 200 302 10m;
proxy_cache_valid 404 1m;
# 古いキャッシュの利用条件(エラー時や更新中)
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
# ブラウザ側へのキャッシュ指示
expires 7d;
add_header Cache-Control "public, immutable";
}
}
4. アクセス制限とレートリミット
DDoS攻撃や急激なアクセス増加に対する防御策です。IPアドレスごとの接続数とリクエスト頻度を制限します。
# リクエスト頻度の制限ゾーン定義 (1秒間に5リクエスト)
limit_req_zone $binary_remote_addr zone=general_limit:10m rate=5r/s;
# 接続数の制限ゾーン定義
limit_conn_zone $binary_remote_addr zone=addr_limit:10m;
server {
# すべてのロケーションで制限を適用
limit_req zone=general_limit burst=10 nodelay;
limit_conn addr_limit 5;
location /login/ {
# 特定のエンドポイントではより厳しい制限を
limit_req zone=general_limit burst=5 nodelay;
proxy_pass http://auth_service;
}
# 制限超過時のレスポンス
limit_req_status 429;
limit_conn_status 503;
}
5. リファラーによる画像保護(ホットリンク防止)
他のサイトから画像等のリソースを直接読み込まれることを防ぐ設定です。
location ~* \.(?:jpg|png|gif|jpeg)$ {
valid_referers none blocked server_names *.example.com;
if ($invalid_referer) {
return 403; # または、警告画像へリダイレクト
# rewrite ^ /static/blocked.png last;
}
root /var/www/assets;
}
パフォーマンスチューニングの深掘り
OSレベルとNginxレベルの両面からボトルネックを解消します。
# OSカーネルパラメータの調整 (/etc/sysctl.conf)
fs.file-max = 2097152
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535
net.ipv4.ip_local_port_range = 1024 65535
# Nginxパフォーマンス関連ディレクティブ
http {
# ファイルディスクリプタのキャッシュ
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# Gzip圧縮の最適化
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml;
# バッファサイズの調整
client_body_buffer_size 128k;
client_max_body_size 10m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
output_buffers 1 32k;
postpone_output 1460;
}
セキュリティ強化対策
不要な情報の隠蔽
Nginxのバージョン情報などをレスポンスヘッダーから削除します。
http {
server_tokens off; # バージョン非表示
more_clear_headers Server; # サーバー名削除(Headersモジュール必要)
}
地理位置制限(GeoIP2)
特定の国からのアクセスをブロックする設定例です。
# GeoIP2データベースの読み込み
geoip2 /etc/GeoIP/GeoLite2-Country.mmdb {
auto_reload 5m;
$geoip2_data_country_code default=XX source=$remote_addr country iso_code;
}
map $geoip2_data_country_code $allowed_country {
default 0;
JP 1; # 日本のみ許可
US 1;
}
server {
if ($allowed_country = 0) {
return 403;
}
# ... その他の設定
}
監視とログ分析
トラフィックを可視化し、問題発生時に迅速に対応するための設定です。
server {
listen 127.0.0.1:80;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
このステータスページをPrometheusなどの監視ツールと連携させることで、接続数やリクエスト処理数を時系列で監視できます。
トラブルシューティングのヒント
- 502 Bad Gateway: バックエンドサーバーがダウンしているか、ファイアウォールで遮断されている可能性があります。バックエンドのログを確認してください。
- 504 Gateway Timeout: Nginxのタイムアウト設定(proxy_read_timeoutなど)がバックエンドの処理時間に対して短すぎる場合に発生します。
- Permission Denied: ワーカープロセスの実行ユーザーに、静的ファイルの読み取り権限またはソケットへの書き込み権限がない場合に発生します。
最適化済みテンプレート例
最後に、汎用的な高パフォーマンス・テンプレートを示します。
user www-data;
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 4096;
use epoll;
multi_accept on;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
charset utf-8;
# ログ設定
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 buffer=32k flush=5s;
error_log /var/log/nginx/error.log warn;
# パフォーマンスチューニング
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 30;
keepalive_requests 100000;
reset_timedout_connection on;
client_body_timeout 10;
send_timeout 2;
# 圧縮
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 4;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
# キャッシュ
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
# バーチャルホスト設定の読み込み
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}