← News
/PLAYBOOK · 2026-08-03

WordPress Security Hardening in Practice: Complete Site Protection Config Guide

Hardens WordPress across wp-config.php, Nginx rules, login security, file permissions, and backups. Includes copy-paste configs and curl checks for xmlrpc.php, wp-admin, and upload PHP execution.

Harden WordPress with least privilege and defense in depth: lock down wp-config.php, add Nginx deny rules, restrict logins, minimize file perms, and automate backups.

Use cases

WordPress is the most widely used CMS and a frequent attack target. This guide hardens WordPress across five layers—config file, web server, login, file permissions, and backup/restore—with steps and code you can apply on self-hosted, corporate, and ecommerce sites.

Prerequisites

How it works

WordPress hardening follows least privilege and defense in depth, in four layers:

Smaller attack surface, lower breach chance. That is the core logic.

Steps

Step 1: Harden wp-config.php

Disable file editing and debug output (add to wp-config.php) and change the table prefix:

define('DISALLOW_FILE_EDIT', true);      // Disable in-dashboard online editing of theme/plugin files
define('WP_DEBUG', false);               // Disable debug output in production
define('WP_DEBUG_DISPLAY', false);
$table_prefix = 'wp_9xK2';               // Change the database table prefix (ignore if already set at install)

Go to https://api.wordpress.org/secret-key/1.1/salt/ and generate new keys. Overwrite AUTH_KEY, SECURE_AUTH_KEY, and the other six constants so old login cookies are invalidated.

Step 2: Nginx protection rules

Add these rules to the site server block:

# Block XML-RPC (common entry for brute force and DDoS)
location = /xmlrpc.php { return 403; }

# Deny direct access to PHP files under wp-includes
location ~* ^/wp-includes/.*\\.php$ { deny all; }

# Deny PHP execution in uploads and cache directories
location ~* ^/wp-content/(?:cache|uploads)/.*\\.php$ { deny all; }

# Allow wp-admin only from specified IPs (replace with your admin IP)
location ^~ /wp-admin {
    allow 203.0.113.10;      # Admin entry IP, change as needed
    deny all;
    try_files $uri $uri/ /index.php?$args;
}

# Rate-limit admin logins: max 5 per IP per minute
location = /wp-login.php {
    limit_req zone=login burst=5 nodelay;
    try_files $uri /index.php?$args;
}

Matching Nginx rate-limit zone (inside the http block):

limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;

Run nginx -t && systemctl reload nginx to apply.

Step 3: Login security and 2FA

Install and enable Limit Login Attempts Reloaded (recommend: lock 30 minutes after 5 failed attempts). Enable WP 2FA or Google Authenticator on admin accounts. Delete the default admin username. Set a unique strong password for the admin (≥14 chars, mixed case, digits, specials).

Step 4: Minimize file permissions

chown -R root:www-data /var/www/your-site        # Owner root, group is the web user
find /var/www/your-site -type d -exec chmod 755 {} \;
find /var/www/your-site -type f -exec chmod 644 {} \;
chmod 640 /var/www/your-site/wp-config.php       # Config file readable only by root group
chown -R www-data:www-data /var/www/your-site/wp-content/uploads   # Uploads directory needs write permission

Step 5: Scheduled backups and updates

# Daily database backup
mysqldump -u wpuser -p wpdatabase | gzip > /backup/wp_$(date +%F).sql.gz
# Daily incremental site file backup
rsync -a --delete /var/www/your-site/ /backup/site_$(date +%F)/
# Update policy: back up first, then upgrade core/plugins/themes on the dashboard Updates page

Verify the configuration

# 1. XML-RPC should return 403
curl -s -o /dev/null -w "%{http_code}\n" https://your-domain/xmlrpc.php
# 2. Unauthorized IP access to wp-admin should return 403
curl -s -o /dev/null -w "%{http_code}\n" https://your-domain/wp-admin/
# 3. Response headers should not expose version information
curl -sI https://your-domain/ | grep -i x-powered-by
# 4. PHP files in the uploads directory should be blocked
curl -s -o /dev/null -w "%{http_code}\n" https://your-domain/wp-content/uploads/test.php

Expected results: 403 / 403 / no output / 403. Then check core file integrity with WP-CLI: wp core verify-checksums. Optionally rescan with WPScan to confirm the fixes.

FAQ

Q1: After IP-restricting wp-admin, I cannot log in from a new network. What now?

SSH in, comment out the allow/deny rules or add your current IP, then reload Nginx. If SSH is unavailable, use the cloud vendor VNC console. Extract the allow block into a separate file (e.g. admin_ip.conf) so it is easier to maintain.

Q2: Will theme/plugin updates fail after disabling file editing?

No. DISALLOW_FILE_EDIT only blocks in-dashboard editing. Uploads, WP-CLI, and FTP updates still work. If you need in-dashboard edits (e.g. a child theme), set it back to true during a maintenance window.

Q3: After hardening I get 404s or static assets fail to load?

Usually a too-broad Nginx rule. The uploads PHP deny only matches *.php; images/CSS/JS are unaffected. If it still fails, run nginx -t and check error.log for the blocked path.

Summary

This guide hardens WordPress on five axes: config, web, login, permissions, and backups. Lock down wp-config.php and disable file editing, block XML-RPC and restrict wp-admin in Nginx, add plugin-level login protection, set 755/644 perms, and run daily backups. Hardening is not a one-shot. Scan monthly with WPScan and keep core/plugins updated so you have a harden–scan–rescan loop.