WordPress + Nginx
ネタがないので、NginxでWordPressを動作させる時の雛形を用意してみる。
- /etc/nginx/conf.d/sitename.conf
server {
### TLS + HTTP/2
listen 443 ssl http2 default_server;
server_name www.foofoomywebsite.jp;
### 基本I/O制御
client_max_body_size 10m;
etag off; # ETagはキャッシュ不整合の温床になりやすい
autoindex off; # ディレクトリ列挙を抑止
### ドキュメント配置
root /var/www/www.foofoomywebsite.jp/document_root;
index index.php index.html index.htm;
### ログ
access_log /var/log/nginx/www.foofoomywebsite.jp_access.log combined;
error_log /var/log/nginx/www.foofoomywebsite.jp_error.log warn;
### TLS証明書(Let's Encrypt前提)
ssl_certificate "/etc/letsencrypt/live/www.foofoomywebsite.jp/fullchain.pem";
ssl_certificate_key "/etc/letsencrypt/live/www.foofoomywebsite.jp/privkey.pem";
### TLSセッション
ssl_session_timeout 1d;
ssl_session_cache shared:MozSSL:10m;
ssl_session_tickets off;
### DHパラメータ(2048bit以上推奨)
ssl_dhparam /etc/nginx/dhparam.pem;
### プロトコル/暗号(TLS1.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:ECDHE-RSA-AES256-GCM-SHA384:"
"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:"
"DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";
ssl_prefer_server_ciphers off; # TLS1.3では無視される
1. OCSP Stapling
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/www.foofoomywebsite.jp/fullchain.pem;
### セキュリティヘッダ(CSPは別途要件に合わせて)
add_header Strict-Transport-Security "max-age=31536000" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
### --- Harden: 明示deny/制限 ---------------------------------------------
### xmlrpcは仕様上の脆弱点が多い。原則遮断(必要時のみ解除)
location = /xmlrpc.php { deny all; }
### 隠し/管理系: .ht*, .git*, .env など一括deny
location ~* ^/\. { deny all; }
### バックアップ/設定/ビルド関連の生ファイルを露出させない
location ~* \.(?:sql|bak|orig|dist|ini|log|conf|env)$ { deny all; }
location ~* ^/(?:readme\.html|license\.txt|wp-config\.php)$ { deny all; }
### composer/node等の開発資材は公開不要
location ~* ^/(?:vendor/|node_modules/|composer\.(?:json|lock)|package\.json|yarn\.lock) { deny all; }
### wp-includes直下のPHP実行は原則不要(WPコアの直接実行を抑止)
location ~* ^/wp-includes/.*\.php$ { deny all; }
### アップロードディレクトリ内のPHP実行は禁止(RCE対策)
location ~* ^/wp-content/uploads/.*\.php$ { deny all; }
### wp-cronは外部からの直叩きを抑止(systemd/cronでの内部実行を前提)
location = /wp-cron.php {
allow 127.0.0.1;
deny all;
include /etc/nginx/conf.d/php-fpm.conf;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
}
### --- 例外: フロントで必要なエンドポイントの許可 -----------------------
### admin-ajaxはフロントから利用される。制限より前で許可
location = /wp-admin/admin-ajax.php {
auth_basic off;
include /etc/nginx/conf.d/php-fpm.conf;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
1. 必要なら軽いレート制限を適用(limit_req_zoneはhttp{}側で定義)
1. limit_req zone=ajax burst=20 nodelay;
}
#### REST APIはテーマ/プラグイン依存で使われることが多い
location ^~ /wp-json/ {
auth_basic off;
try_files $uri $uri/ /index.php?$args;
}
### --- 通常ルーティング --------------------------------------------------
### author列挙対策:?author= をトップへ逃がす
location / {
if ($query_string ~* "author=") { return 301 /; }
try_files $uri $uri/ /index.php?$args;
}
#### PHPハンドオフ
location ~ \.php$ {
try_files $uri /index.php?$args;
include /etc/nginx/conf.d/php-fpm.conf;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
}
#### 管理画面: wp-login/wp-admin はIP許可 + BASIC(二重の摩擦で総当たりを抑止)
location ~* (?:/wp-login\.php|/wp-admin/(?!.*(?:admin-ajax\.php|css/|js/)).*)$ {
allow 192.168.10.1;
allow 127.0.0.1;
auth_basic "Restricted Area";
auth_basic_user_file /etc/nginx/.htpasswd;
client_max_body_size 1g; # 管理系アップロードは大きめ許容
include /etc/nginx/conf.d/php-fpm.conf;
fastcgi_pass unix:/var/run/php-fpm/php-fpm.sock;
}
}
/etc/nginx/conf.d/php-fpm.con
fastcgi_index index.php;
fastcgi_read_timeout 300;
fastcgi_split_path_info ^(.+\.php)(.*)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_pass は Unix socketを利用