How to Harden WordPress (Beyond Plugins)

Security plugins operate inside WordPress. Attackers operate outside it. Real hardening happens at the server level where plugins have no reach.

WordPress laptop shielded for security, linked to icons for wp-config.php, .htaccess rules, file permissions and server hardening

What does it mean to harden WordPress?

Hardening reduces your attack surface. Every file, endpoint, user account, and server configuration that’s accessible to the outside world is a potential entry point. Hardening systematically closes the ones you don’t need and restricts the ones you do.

Most WordPress security advice starts and ends with “install a security plugin.” That’s like putting a lock on your front door while leaving every window open. Security plugins operate inside WordPress. They can’t protect against attacks that target the server, the database connection, or PHP itself. Real hardening works at layers the plugin never touches.

This guide covers what to do beyond plugins. If you haven’t already run through the basics (updates, strong passwords, 2FA), start with our WordPress security audit checklist first. This post assumes you’ve covered those fundamentals.

Lock down wp-config.php

Your wp-config.php file contains database credentials, authentication keys, and configuration constants. It’s the single most sensitive file in your WordPress installation.

Move it above the web root

WordPress automatically checks one directory above the web root for wp-config.php. Moving it there means it’s not accessible via any URL, even if your server misconfigures PHP processing:

/home/username/wp-config.php        ← moved here
/home/username/public_html/          ← web root
/home/username/public_html/wp-admin/
/home/username/public_html/wp-content/

Add security constants

// Disable file editing from wp-admin
define('DISALLOW_FILE_EDIT', true);

// Disable plugin/theme installation from wp-admin
define('DISALLOW_FILE_MODS', true);

// Force SSL for admin
define('FORCE_SSL_ADMIN', true);

// Limit post revisions
define('WP_POST_REVISIONS', 5);

// Disable WordPress debug display on production
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);

DISALLOW_FILE_MODS is aggressive. It prevents plugin and theme updates from wp-admin, meaning you’ll need to update via SFTP or WP-CLI. But it also means an attacker who gains admin access can’t install a malicious plugin through the dashboard.

Set correct permissions

chmod 600 wp-config.php

On shared hosting where your user and the web server user differ, use 640 instead. The file should be readable by PHP but not writable by the web process.

Server-level hardening with .htaccess

If you’re on Apache (most cPanel shared hosting), .htaccess rules execute before WordPress loads. They stop malicious requests at the server level.

Block access to sensitive files

# Block access to wp-config.php
<Files wp-config.php>
    Order Allow,Deny
    Deny from all
</Files>

# Block access to .htaccess itself
<Files .htaccess>
    Order Allow,Deny
    Deny from all
</Files>

# Block access to xmlrpc.php
<Files xmlrpc.php>
    Order Allow,Deny
    Deny from all
</Files>

# Block access to wp-cron.php from external requests
<Files wp-cron.php>
    Order Allow,Deny
    Deny from all
    Allow from 127.0.0.1
</Files>

Disable PHP execution in uploads

The wp-content/uploads/ directory should never execute PHP. If an attacker uploads a PHP backdoor disguised as an image, this rule prevents it from running:

# In wp-content/uploads/.htaccess
<Files "*.php">
    Order Allow,Deny
    Deny from all
</Files>

Create this file manually. WordPress doesn’t generate it by default.

Disable directory browsing

Options -Indexes

Without this, anyone can browse your directory structure by visiting /wp-content/plugins/ directly. That reveals exactly which plugins you run and their versions.

PHP configuration hardening

PHP settings control what WordPress can do at the language level. Restricting dangerous functions limits what malware can accomplish even if it gets uploaded.

Disable dangerous functions

In your php.ini or .user.ini:

disable_functions = exec, passthru, shell_exec, system, proc_open, popen, curl_multi_exec, parse_ini_file, show_source, eval

This breaks WP-CLI (which needs proc_open). If you use WP-CLI, remove proc_open from the list. The tradeoff is worth understanding: these functions let PHP execute system commands. Malware uses them to download additional payloads, send spam, or pivot to other services on the server.

Restrict file uploads

file_uploads = On
upload_max_filesize = 10M
max_file_uploads = 5

Keep upload size to what you actually need. A 256MB upload limit is an invitation for abuse.

Hide PHP version

expose_php = Off

No reason to advertise your PHP version in response headers. It helps attackers identify which exploits apply to your server.

File permission hardening

Incorrect file permissions are one of the most common security gaps on WordPress sites, especially after migrations or manual file uploads.

Path Correct Permission Why
Directories 755 Owner can read/write/execute. Group and others can read/execute only.
Files 644 Owner can read/write. Group and others can read only.
wp-config.php 600 or 640 Only the owner (or owner + group) can read. Nobody can write.
.htaccess 644 Readable by Apache, writable only by owner.
wp-content/uploads/ 755 Writable by the web server for media uploads.

To fix permissions in bulk via SSH:

find /path/to/wordpress -type d -exec chmod 755 {} \;
find /path/to/wordpress -type f -exec chmod 644 {} \;
chmod 600 /path/to/wordpress/wp-config.php

On cPanel shared hosting without SSH, use File Manager’s permission settings or ask your host to run these commands.

Disable XML-RPC

XML-RPC (xmlrpc.php) is a legacy API that allows external applications to communicate with WordPress. It’s also the most common brute-force vector after wp-login.php. Attackers use the system.multicall method to test hundreds of password combinations in a single request, bypassing login attempt limits.

Unless you use the WordPress mobile app, Jetpack, or a service that specifically requires XML-RPC, disable it completely. The .htaccess rule above blocks it at the server level. You can also add this to your theme’s functions.php:

add_filter('xmlrpc_enabled', '__return_false');

The .htaccess approach is better because it stops the request before PHP even loads. The filter approach still lets PHP process the request before returning a denial.

Security headers

HTTP security headers instruct browsers on how to handle your site’s content. They prevent entire classes of attacks (clickjacking, XSS, MIME sniffing) with zero performance cost.

Add these to your .htaccess or server configuration:

<IfModule mod_headers.c>
    Header set X-Content-Type-Options "nosniff"
    Header set X-Frame-Options "SAMEORIGIN"
    Header set X-XSS-Protection "1; mode=block"
    Header set Referrer-Policy "strict-origin-when-cross-origin"
    Header set Permissions-Policy "camera=(), microphone=(), geolocation=()"
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
</IfModule>

Test your headers at securityheaders.com after implementing. Aim for an A grade minimum.

What plugins can’t do

Security plugins like Wordfence, Sucuri, and iThemes Security add value. They monitor file changes, limit login attempts, and scan for known malware signatures. But they have fundamental limitations:

  • They can’t modify server configuration (Apache/Nginx rules, PHP settings)
  • They can’t set file permissions below what PHP’s user has access to
  • They can’t protect against attacks that bypass PHP entirely (direct file access, SSH brute force)
  • They add processing overhead to every request (the plugin itself runs on every page load)
  • They can be disabled by an attacker who gains admin access

Think of security plugins as a monitoring layer, not a protection layer. The actual protection comes from the server-level hardening described above. The plugin tells you when something goes wrong. The hardening prevents things from going wrong in the first place.

Next step

Start with wp-config.php. Add DISALLOW_FILE_EDIT and FORCE_SSL_ADMIN today. Then create the .htaccess file in wp-content/uploads/ to block PHP execution. These two changes take five minutes and close the most commonly exploited gaps on WordPress sites.

After that, check your file permissions and disable XML-RPC. Run securityheaders.com against your domain and add any missing headers. The full hardening process takes about an hour for a standard WordPress site on cPanel hosting.

Frequently asked

Partially. You can lock down file permissions, add .htaccess rules, configure wp-config.php, and disable dangerous PHP functions. But you can't control server-level firewall rules, PHP handler configuration, or process isolation. Shared hosting limits your hardening ceiling.

WordPress core is well-maintained and patches quickly. A properly hardened WordPress install with strong passwords, 2FA, correct file permissions, and up-to-date software is secure without any security plugin. Plugins add convenience (login limiting, file monitoring) but aren't strictly required if you handle those at the server level.

Keep everything updated. Core, plugins, themes, PHP version. The vast majority of WordPress hacks exploit known vulnerabilities in outdated software. All other hardening measures are secondary to this.

Need your WordPress site hardened properly?

Request a Security Hardening