Disable XML-RPC and Protect the WordPress Login Page with .htaccess Rules

XML-RPC is a legacy remote procedure call protocol that WordPress enables by default to support clients like the mobile app and Jetpack, but it is also one of the most frequently abused attack surfaces in any WordPress installation. Brute-force attacks through xmlrpc.php can test thousands of username-password combinations per request using the system.multicall method, bypassing the per-request limit that protects wp-login.php. Disabling XML-RPC at the application level with a xmlrpc_enabled filter is the clean WordPress-native approach, but it leaves the endpoint reachable for requests the filter cannot stop, such as HTTP-level DDoS floods. Adding a server-level Deny rule in .htaccess for Apache or a deny all location block for Nginx drops XML-RPC requests before PHP is invoked, eliminating the CPU overhead entirely. Limiting login attempts is complementary to XML-RPC disabling — brute-force attacks increasingly target wp-login.php directly, especially after XML-RPC is closed. Adding a Require ip directive to the login page Apache configuration restricts login access to a known IP range, which is feasible for single-developer sites or sites managed by a team using a VPN with a fixed egress IP. Moving the login URL with a rewrite rule adds another layer of obscurity, though it is not a security control by itself — obscurity always supplements but never replaces authentication controls. HTTP authentication (AuthType Basic) in front of wp-login.php forces an additional password prompt before WordPress’s own authentication, stopping automated scripts that do not know the HTTP auth credentials. The X-Frame-Options: SAMEORIGIN and X-Content-Type-Options: nosniff security headers should accompany these login protections in the server configuration. The AJAX nonce post covers the parallel concern of CSRF and input validation for application-layer endpoints. The WooCommerce access control guide demonstrates role-based access patterns that reduce the attack surface for authenticated endpoints. For high-traffic sites, combining these rules with a Web Application Firewall rule set at the CDN layer provides defence in depth with minimal origin server load. Review the list of active plugins that depend on XML-RPC before disabling it — WooCommerce mobile apps, some backup plugins, and third-party integrations may require it.

Problem: WordPress's enabled-by-default XML-RPC endpoint and unprotected login page are primary targets for brute-force and credential-stuffing attacks that put every installation at risk.

Solution: Disable XML-RPC via the xmlrpc_enabled filter, block xmlrpc.php at the server level in .htaccess, and add HTTP Basic Authentication in front of wp-login.php.

// functions.php — disable XML-RPC at application level
add_filter('xmlrpc_enabled', '__return_false');

# .htaccess — block xmlrpc.php before PHP is invoked
<Files xmlrpc.php>
    Require all denied
</Files>

# .htaccess — HTTP Basic Auth in front of wp-login.php
<Files wp-login.php>
    AuthType    Basic
    AuthName    "Admin area"
    AuthUserFile /path/to/.htpasswd
    Require valid-user
</Files>

# Generate the .htpasswd entry (run in terminal)
# htpasswd -c /path/to/.htpasswd yourusername

# .htaccess — security response headers
<IfModule mod_headers.c>
    Header always set X-Frame-Options "SAMEORIGIN"
    Header always set X-Content-Type-Options "nosniff"
    Header always set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

NOTE: If Jetpack or the WordPress mobile app is active and requires XML-RPC, whitelist only the Jetpack server IP range in the <Files xmlrpc.php> block with Require ip 192.0.80.0/20 instead of Require all denied.