2026年7月8日

2026年7月8日

WordPressのNginxのセキュリティ設定

はじめに

NginxはWordPressの高速・安定運用に広く使われていますが、デフォルト設定のままではセキュリティリスクがあります。サーバー情報の隠蔽・適切なバッファ設定・TLS強化・不正リクエストのブロックを設定することで、攻撃耐性を大幅に向上できます。

症状・原因

  • Nginxのバージョン情報がレスポンスヘッダーに表示されている
  • 大きなリクエストボディによるバッファオーバーフロー攻撃を受けている
  • wp-login.phpやxmlrpc.phpへのブルートフォース攻撃が続いている
  • HTTPSリダイレクトやHSTSが設定されていない

解決手順

ステップ1:現在のNginx設定を診断する

# Nginx バージョン確認
nginx -v

# 設定の構文チェック
sudo nginx -t

# バージョン情報がレスポンスに含まれているか確認
curl -sI https://example.com/ | grep -i "server"

# 設定ファイルのパスを確認
sudo nginx -T | grep "configuration file"

# 現在の接続数・リクエスト状況を確認
sudo nginx -T | grep "worker_processes\|worker_connections"

ステップ2:nginx.conf のグローバル設定を強化する

# /etc/nginx/nginx.conf

user www-data;
worker_processes auto;
pid /run/nginx.pid;

events {
    worker_connections 1024;
    multi_accept on;
}

http {
    # バージョン情報を非表示
    server_tokens off;

    # MIME タイプのスニッフィングを防ぐ
    add_header X-Content-Type-Options nosniff always;

    # クリックジャッキング対策
    add_header X-Frame-Options SAMEORIGIN always;

    # XSS 保護
    add_header X-XSS-Protection "1; mode=block" always;

    # HSTS(HTTPS を強制)
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

    # バッファサイズ制限(大きなリクエストへの対策)
    client_max_body_size 10m;
    client_body_buffer_size 128k;
    client_header_buffer_size 1k;
    large_client_header_buffers 4 4k;
    client_body_timeout 12;
    client_header_timeout 12;
    send_timeout 10;
    keepalive_timeout 15;

    # レート制限ゾーン定義
    limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
    limit_req_zone $binary_remote_addr zone=api:10m rate=60r/m;
    limit_req_zone $binary_remote_addr zone=general:10m rate=100r/s;
    limit_conn_zone $binary_remote_addr zone=addr:10m;

    include /etc/nginx/mime.types;
    default_type application/octet-stream;

    include /etc/nginx/conf.d/*.conf;
    include /etc/nginx/sites-enabled/*;
}

ステップ3:WordPress 用サーバーブロックを設定する

# /etc/nginx/sites-available/wordpress

# HTTP → HTTPS リダイレクト
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl http2;
    server_name example.com;
    root /var/www/html;
    index index.php;

    # SSL 証明書
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;

    # TLS 1.2/1.3 のみ許可
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384;
    ssl_prefer_server_ciphers off;
    ssl_session_cache shared:SSL:10m;
    ssl_session_timeout 10m;

    # OCSP Stapling
    ssl_stapling on;
    ssl_stapling_verify on;
    resolver 8.8.8.8 8.8.4.4 valid=300s;

    # 同時接続数制限
    limit_conn addr 10;

    # 一般ページにレート制限
    limit_req zone=general burst=200 nodelay;

    # wp-login.php に厳格なレート制限
    location = /wp-login.php {
        limit_req zone=login burst=2 nodelay;
        limit_req_status 429;
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }

    # xmlrpc.php を完全ブロック
    location = /xmlrpc.php {
        deny all;
        access_log off;
        log_not_found off;
    }

    # wp-config.php を保護
    location = /wp-config.php {
        deny all;
    }

    # .htaccess 等の隠しファイルを保護
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }

    # uploads ディレクトリの PHP 実行を禁止
    location ~* /wp-content/uploads/.*\.(php|phtml|php5|phar)$ {
        deny all;
    }

    # WordPress パーマリンク設定
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_hide_header X-Powered-By;
    }

    # 静的ファイルのキャッシュ
    location ~* \.(css|js|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        access_log off;
    }
}

ステップ4:不正なリクエストをブロックする

# /etc/nginx/conf.d/block-bad-requests.conf

# 不正な HTTP メソッドをブロック
map $request_method $bad_method {
    default 0;
    TRACE   1;
    DELETE  1;
    CONNECT 1;
    OPTIONS 1;
}

server {
    if ($bad_method) {
        return 405;
    }

    # 不正な User-Agent をブロック
    map $http_user_agent $bad_bot {
        default 0;
        ~*masscan 1;
        ~*nikto 1;
        ~*sqlmap 1;
        ~*nmap 1;
        ~*(wget|curl).*scan 1;
    }

    if ($bad_bot) {
        return 403;
    }

    # 空の User-Agent をブロック
    if ($http_user_agent = "") {
        return 403;
    }
}

ステップ5:設定を反映して確認する

# 設定の構文チェック
sudo nginx -t

# Nginx をリロード
sudo systemctl reload nginx

# ヘッダーを確認
curl -sI https://example.com/ | grep -E "server:|x-frame|strict-transport|x-content"

# wp-login.php のレート制限を確認
for i in {1..10}; do
    curl -s -o /dev/null -w "%{http_code}\n" \
        -X POST https://example.com/wp-login.php
done
# 6回目以降は 429 が返るはず

# SSL 設定のスコアを確認
# https://www.ssllabs.com/ssltest/ で A+ を目指す

# Nginx のエラーログを確認
sudo tail -f /var/log/nginx/error.log

注意事項

  • client_max_body_sizeはWordPressのメディアアップロードサイズに合わせて設定してください。小さすぎると画像・動画のアップロードが失敗します
  • レート制限を厳しくしすぎると正当なユーザーもブロックされます。最初は緩めに設定してアクセスログを確認した後に段階的に厳しくしてください
  • ssl_stapling onの設定にはssl_trusted_certificate(Let's Encryptの場合はchain.pem)の指定が必要な場合があります

まとめ

Nginxのセキュリティ設定は①server_tokens offでバージョン情報を非表示・client_max_body_size 10mでバッファ上限を設定、②limit_req_zoneloginapigeneralの3ゾーンを定義、③VirtualHostでssl_protocols TLSv1.2 TLSv1.3xmlrpc.php完全ブロック・wp-config.php保護・uploadsのPHP実行禁止、④map $http_user_agent $bad_botで悪意あるスキャナーをブロック、⑤nginx -tで検証後systemctl reload nginx・SSL Labsでスコア確認します。

お気軽にご相談ください

お見積りへ お問い合わせへ