【2026年版】Nginx セキュリティ設定完全ガイド:SSL/TLS・WAF・アクセス制御の最適化

Tech Trends AI
- 5 minutes read - 1035 wordsはじめに
Nginxは2026年現在、世界のWebサーバー市場で最大のシェアを持つソフトウェアです。リバースプロキシ、ロードバランサー、APIゲートウェイとして広く利用されていますが、デフォルト設定のまま運用することは深刻なセキュリティリスクをもたらします。
本記事では、Nginxのセキュリティを本番環境レベルまで引き上げるための設定を、SSL/TLS、WAF、レート制限、アクセス制御、セキュリティヘッダーの各領域にわたって網羅的に解説します。すべて実際の設定ファイルのコード例付きです。
セキュリティ設定の全体像
Nginx セキュリティの防御レイヤー
Nginxのセキュリティ対策は、以下の多層防御(Defense in Depth)で構成されます。
| レイヤー | 対策内容 | 防御対象 |
|---|---|---|
| L1: 通信暗号化 | SSL/TLS設定、HSTS | 盗聴、中間者攻撃 |
| L2: アクセス制御 | IPフィルタ、Basic認証、GeoIP | 不正アクセス |
| L3: レート制限 | リクエスト制限、接続数制限 | DDoS、ブルートフォース |
| L4: WAF | ModSecurity、NAXSI | SQLi、XSS、RCE |
| L5: ヘッダー | セキュリティヘッダー | クリックジャッキング、XSS |
| L6: 情報漏洩防止 | バージョン非表示、エラーページ | 偵察行為 |
| L7: ログ・監視 | アクセスログ、エラーログ | インシデント検知 |
L1:SSL/TLS の最適設定
2026年推奨のSSL/TLS構成
# /etc/nginx/conf.d/ssl-params.conf
# TLSバージョン: TLS 1.2以上のみ許可(TLS 1.3推奨)
ssl_protocols TLSv1.2 TLSv1.3;
# 暗号スイート: サーバー側の優先順位を使用
ssl_prefer_server_ciphers on;
# TLS 1.2用の暗号スイート(強度の高いもののみ)
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256';
# TLS 1.3の暗号スイート(Nginx 1.19.4+)
ssl_conf_command Ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256;
# ECDH曲線
ssl_ecdh_curve X25519:secp384r1:secp256r1;
# セッションキャッシュ
ssl_session_cache shared:SSL:50m;
ssl_session_timeout 1d;
ssl_session_tickets off;
# OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s;
resolver_timeout 5s;
# DH パラメータ(2048bit以上)
ssl_dhparam /etc/nginx/ssl/dhparam.pem;
# HSTS(HTTP Strict Transport Security)
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
Let’s Encrypt 証明書の自動更新設定
# certbot のインストール(Ubuntu/Debian)
sudo apt install certbot python3-certbot-nginx
# 証明書の取得
sudo certbot --nginx -d example.com -d www.example.com
# 自動更新の設定(cron)
echo "0 3 * * * root certbot renew --quiet --post-hook 'systemctl reload nginx'" | sudo tee /etc/cron.d/certbot-renew
SSL/TLS設定の評価基準
| 項目 | A+評価の条件 | 確認方法 |
|---|---|---|
| プロトコル | TLS 1.2/1.3のみ | ssl_protocols ディレクティブ |
| 暗号スイート | AEAD暗号のみ | ssl_ciphers ディレクティブ |
| 鍵交換 | ECDHE/DHE | 前方秘匿性の確保 |
| 証明書 | RSA 2048+/ECDSA P-256+ | 証明書の鍵長 |
| HSTS | max-age 1年以上 | レスポンスヘッダー確認 |
| OCSP Stapling | 有効 | ssl_stapling on |
# SSL Labs でテスト
# https://www.ssllabs.com/ssltest/
# コマンドラインでのテスト
openssl s_client -connect example.com:443 -tls1_3
testssl.sh https://example.com
L2:アクセス制御
IPベースのアクセス制御
# /etc/nginx/conf.d/access-control.conf
# 管理画面へのアクセス制限
location /admin/ {
# 許可するIPアドレス
allow 203.0.113.10; # オフィスIP
allow 198.51.100.0/24; # VPNレンジ
allow 127.0.0.1; # ローカル
deny all;
proxy_pass http://backend;
}
# API エンドポイントへのアクセス制限
location /api/internal/ {
allow 10.0.0.0/8; # 内部ネットワーク
deny all;
proxy_pass http://api-backend;
}
GeoIPベースのアクセス制御
# GeoIP2モジュールの設定
geoip2 /usr/share/GeoIP/GeoLite2-Country.mmdb {
auto_reload 60m;
$geoip2_data_country_code country iso_code;
}
# 特定の国からのアクセスをブロック
map $geoip2_data_country_code $allowed_country {
default yes;
CN no; # 中国
RU no; # ロシア
KP no; # 北朝鮮
}
server {
if ($allowed_country = no) {
return 403;
}
}
Basic認証(ステージング環境用)
# htpasswd ファイルの生成
# sudo htpasswd -c /etc/nginx/.htpasswd admin
location / {
auth_basic "Restricted Access";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://backend;
}
L3:レート制限
リクエストレート制限
# /etc/nginx/conf.d/rate-limit.conf
# レート制限ゾーンの定義
# $binary_remote_addr: クライアントIPごとに制限
limit_req_zone $binary_remote_addr zone=general:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=1r/s;
limit_req_zone $binary_remote_addr zone=api:10m rate=30r/s;
limit_req_zone $binary_remote_addr zone=search:10m rate=5r/s;
# 接続数制限
limit_conn_zone $binary_remote_addr zone=conn_per_ip:10m;
server {
# 一般的なページ: 10req/s、バースト20まで許容
location / {
limit_req zone=general burst=20 nodelay;
limit_conn conn_per_ip 50;
proxy_pass http://backend;
}
# ログインページ: 1req/s、バースト5まで(ブルートフォース対策)
location /login {
limit_req zone=login burst=5 nodelay;
limit_req_status 429;
proxy_pass http://backend;
}
# API: 30req/s、バースト50まで
location /api/ {
limit_req zone=api burst=50 nodelay;
limit_req_status 429;
proxy_pass http://api-backend;
}
# 検索: 5req/s、バースト10まで
location /search {
limit_req zone=search burst=10 nodelay;
proxy_pass http://backend;
}
}
レート制限のパラメータ比較
| パラメータ | 説明 | 推奨値 | ユースケース |
|---|---|---|---|
| rate | 1秒あたりの許可リクエスト数 | 1〜30r/s | エンドポイントの重要度に応じて |
| burst | バーストで許容する追加リクエスト数 | rateの2〜5倍 | 一時的なトラフィック増加に対応 |
| nodelay | バースト内リクエストを即座に処理 | 推奨 | UX向上(待機なし) |
| zone | 共有メモリゾーンのサイズ | 10m(約16万IP) | サーバーのメモリ量に応じて |
L4:WAF(Web Application Firewall)
ModSecurity v3 の導入
ModSecurityはオープンソースのWAFエンジンで、OWASP Core Rule Set(CRS)と組み合わせることで、SQLインジェクション、XSS、RCEなど主要な攻撃を検出・遮断します。
# /etc/nginx/nginx.conf に追加
load_module modules/ngx_http_modsecurity_module.so;
http {
modsecurity on;
modsecurity_rules_file /etc/nginx/modsecurity/main.conf;
}
# /etc/nginx/modsecurity/main.conf
Include /etc/nginx/modsecurity/modsecurity.conf
Include /etc/nginx/modsecurity/crs/crs-setup.conf
Include /etc/nginx/modsecurity/crs/rules/*.conf
# カスタムルール
SecRule REQUEST_URI "@contains /admin" \
"id:10001,phase:1,deny,status:403,msg:'Admin access attempt'"
NAXSI(Nginx Anti XSS & SQL Injection)
NAXSIはNginxネイティブの軽量WAFモジュールです。
# メインルールの読み込み
include /etc/nginx/naxsi_core.rules;
server {
location / {
# NAXSIの有効化
SecRulesEnabled;
# 学習モード(初期導入時)
# LearningMode;
# 拒否時のリダイレクト先
DeniedUrl "/request-denied";
# ルール閾値
CheckRule "$SQL >= 8" BLOCK;
CheckRule "$RFI >= 8" BLOCK;
CheckRule "$TRAVERSAL >= 4" BLOCK;
CheckRule "$EVADE >= 4" BLOCK;
CheckRule "$XSS >= 8" BLOCK;
proxy_pass http://backend;
}
location /request-denied {
internal;
return 403 '{"error": "Request blocked by WAF"}';
add_header Content-Type application/json;
}
}
WAFソリューション比較
| WAF | 種類 | 性能影響 | 設定難易度 | ルールセット | 適したケース |
|---|---|---|---|---|---|
| ModSecurity v3 | オープンソース | 中 | 高 | OWASP CRS | 高度なカスタマイズが必要 |
| NAXSI | Nginx モジュール | 低 | 中 | 独自ルール | シンプルな構成 |
| Cloudflare WAF | クラウド型 | なし(CDN経由) | 低 | マネージドルール | 手軽に導入したい |
| AWS WAF | クラウド型 | なし(ALB経由) | 中 | マネージド + カスタム | AWS環境 |
| Coraza | オープンソース | 低〜中 | 中 | OWASP CRS互換 | ModSecurityの代替 |
L5:セキュリティヘッダー
推奨セキュリティヘッダー一覧
# /etc/nginx/conf.d/security-headers.conf
# XSS防止
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "0" always; # 最新ブラウザではCSPに委譲
# クリックジャッキング防止
add_header X-Frame-Options "SAMEORIGIN" always;
# Content Security Policy
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'nonce-{random}'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self'; connect-src 'self' https://api.example.com; frame-ancestors 'self';" always;
# Referrer Policy
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
# Permissions Policy
add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), payment=()" always;
# Cross-Origin 系ヘッダー
add_header Cross-Origin-Opener-Policy "same-origin" always;
add_header Cross-Origin-Embedder-Policy "require-corp" always;
add_header Cross-Origin-Resource-Policy "same-origin" always;
セキュリティヘッダーの効果一覧
| ヘッダー | 防御対象 | 重要度 |
|---|---|---|
| Strict-Transport-Security | プロトコルダウングレード攻撃 | 必須 |
| Content-Security-Policy | XSS、データインジェクション | 必須 |
| X-Content-Type-Options | MIMEスニッフィング | 必須 |
| X-Frame-Options | クリックジャッキング | 必須 |
| Referrer-Policy | 情報漏洩 | 推奨 |
| Permissions-Policy | 不正なAPI利用 | 推奨 |
| Cross-Origin-Opener-Policy | Spectre系攻撃 | 推奨 |
L6:情報漏洩防止
サーバー情報の秘匿
# Nginx バージョンの非表示
server_tokens off;
# カスタムエラーページ
error_page 403 /errors/403.html;
error_page 404 /errors/404.html;
error_page 500 502 503 504 /errors/50x.html;
location /errors/ {
internal;
root /var/www/html;
}
# 隠しファイルへのアクセス拒否
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# バックアップファイルへのアクセス拒否
location ~* \.(bak|config|sql|fla|psd|ini|log|sh|inc|swp|dist|old|save)$ {
deny all;
access_log off;
log_not_found off;
}
# Git リポジトリへのアクセス拒否
location ~ /\.git {
deny all;
}
L7:ログと監視
構造化ログの設定
# JSON形式のログ出力
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request":"$request",'
'"status":"$status",'
'"body_bytes_sent":"$body_bytes_sent",'
'"request_time":"$request_time",'
'"http_referrer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for",'
'"ssl_protocol":"$ssl_protocol",'
'"ssl_cipher":"$ssl_cipher",'
'"request_id":"$request_id"'
'}';
access_log /var/log/nginx/access.json json_combined;
error_log /var/log/nginx/error.log warn;
攻撃検知のためのログ分析
# 高頻度アクセスの検出(1分間に100回以上)
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
# 4xx/5xx エラーの多いIP
grep -E '"status":"(4|5)[0-9]{2}"' /var/log/nginx/access.json | \
jq -r '.remote_addr' | sort | uniq -c | sort -rn | head -20
# 不審なUser-Agentの検出
grep -iE '(sqlmap|nikto|nmap|masscan|zgrab)' /var/log/nginx/access.log
本番環境向け統合設定テンプレート
以下は、これまでの設定を統合した本番環境向けのNginx設定テンプレートです。
# /etc/nginx/sites-available/production.conf
upstream backend {
server 127.0.0.1:3000;
keepalive 32;
}
# HTTP → HTTPS リダイレクト
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
return 301 https://$server_name$request_uri;
}
# HTTPS サーバー
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name example.com www.example.com;
# SSL証明書
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
# SSL設定(別ファイルからインクルード)
include /etc/nginx/conf.d/ssl-params.conf;
# セキュリティヘッダー
include /etc/nginx/conf.d/security-headers.conf;
# サーバー情報の非表示
server_tokens off;
# レート制限
limit_req zone=general burst=20 nodelay;
limit_conn conn_per_ip 50;
# アクセスログ
access_log /var/log/nginx/example.com.access.json json_combined;
error_log /var/log/nginx/example.com.error.log warn;
# メインアプリケーション
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Request-ID $request_id;
}
# 静的ファイル
location /static/ {
root /var/www/html;
expires 1y;
add_header Cache-Control "public, immutable";
}
# ヘルスチェック
location /health {
access_log off;
return 200 'OK';
add_header Content-Type text/plain;
}
# 隠しファイル・バックアップファイルの拒否
location ~ /\. { deny all; }
location ~* \.(bak|sql|log|sh|old)$ { deny all; }
}
セキュリティ設定チェックリスト
| カテゴリ | チェック項目 | 確認コマンド/方法 |
|---|---|---|
| SSL/TLS | TLS 1.2/1.3のみ有効 | testssl.sh |
| SSL/TLS | HSTS設定済み | レスポンスヘッダー確認 |
| SSL/TLS | OCSP Stapling有効 | openssl s_client |
| アクセス制御 | 管理画面のIP制限 | curl でテスト |
| レート制限 | ログイン・APIに設定済み | 負荷テスト |
| WAF | ModSecurity/NAXSIが有効 | WAFログ確認 |
| ヘッダー | CSP設定済み | securityheaders.com |
| 情報漏洩 | server_tokens off | レスポンスヘッダー |
| ログ | JSON構造化ログ | ログファイル確認 |
まとめ
Nginxのセキュリティ設定は、単一の対策ではなく多層防御の考え方で構築することが重要です。本記事で解説したポイントをまとめます。
- SSL/TLSはTLS 1.3を優先: HSTSとOCSP Staplingも必ず設定
- アクセス制御は最小権限の原則: 管理画面・内部APIはIP制限を必須に
- レート制限でブルートフォースとDDoSに対抗: エンドポイントごとに適切な閾値を設定
- WAFで既知の攻撃パターンを自動遮断: OWASP CRSの導入を推奨
- セキュリティヘッダーでブラウザ側の防御を強化: CSP、HSTS、X-Frame-Optionsは必須
- 情報漏洩を防止: バージョン非表示、隠しファイルへのアクセス拒否
- ログは構造化してリアルタイム監視: JSON形式でSIEM連携を容易に
セキュリティ設定は一度行えば終わりではなく、定期的な見直しと更新が必要です。SSL Labsやsecurityheaders.comなどの外部ツールを活用し、継続的にセキュリティレベルを維持してください。