WordPress runs a huge share of the world's websites, which makes it the first target for anyone writing a bot. Many "DDoS attacks" against WordPress aren't even targeted: they are programs roaming the Internet trying the same pages on millions of sites. The problem is that a few hundred requests per second to the right pages are enough to take down a shared hosting account.
Why WordPress suffers so much
An uncached WordPress page means starting PHP, loading every plugin and running dozens of database queries. An ordinary server handles a few dozen per second. If a bot asks for hundreds, PHP processes run out, requests queue up and the site stops answering everyone.
The targeted pages are almost always the same.
wp-login.php
The login page can't be cached and makes the database and PHP work on every attempt. Bots use it to try passwords in bulk (brute force): even when they don't guess, trying thousands of times a minute is enough to slow everything down.
xmlrpc.php
It's an old interface for publishing from external apps. It has two well-known flaws:
- it lets you try hundreds of passwords in a single request (the
system.multicallfunction), bypassing many login attempt limits; - the pingback function can be abused to make your site send requests to other sites, turning it into an unwitting accomplice in attacks.
If you don't use the WordPress mobile app, Jetpack or services that explicitly require it, you can switch it off.
Site search
A search (/?s=word) queries the database every time, and every different word is a new page no cache has ready. A bot searching random words is a simple, effective way to overwhelm a site.
admin-ajax.php and wp-cron.php
Many plugins use admin-ajax.php for dynamic features, and wp-cron.php runs on every visit to execute scheduled tasks. Under attack, both multiply the server's workload.
Defences, from the simplest
1. Switch off xmlrpc.php if you don't need it
With Nginx:
location = /xmlrpc.php { deny all; }
With Apache, in the .htaccess file:
<Files xmlrpc.php>
Require all denied
</Files>
Plugins can also disable it, but blocking it at the web server is more effective: the request is refused before PHP even starts.
2. Protect the login
- use long passwords and two-factor authentication for every administrator;
- limit login attempts with a dedicated plugin or with fail2ban on the server;
- if you always work from the same places, you can restrict
/wp-adminand/wp-login.phpto your IP addresses or to the countries you work from.
3. Cache your pages
A cached page doesn't start PHP or touch the database: the server delivers it like a file. A caching plugin (or your host's cache) cuts the load ten- or a hundredfold for public pages, and often that alone is enough to survive a spike that used to take the site down.
Caching doesn't protect dynamic pages (login, search, cart), though, and that's exactly where attacks aim.
4. Move cron to a real scheduled task
In wp-config.php:
define('DISABLE_WP_CRON', true);
then add a scheduled task on the server that calls wp-cron.php every five minutes. Cron no longer runs on every visit.
5. Put WordPress behind a CDN with bot protection
All the previous measures run on your server: they help, but requests still reach it. A CDN moves the defence in front of the server.
With 1PrimeCDN:
- public pages and files (images, CSS, JavaScript) are served by the nodes, and the server only sees a fraction of the visits;
- every IP address has a requests-per-second limit: anyone exceeding it is slowed down and then stopped;
- Shield scores every IP based on how it behaves: anyone trying passwords in bulk, requesting ever-different pages to dodge the cache or introducing itself as an automated tool goes through a check or is blocked for a while, with the reason shown in the panel;
- during an attack, «under attack» mode sends everyone through a one-second check, while verified Google and Bing crawlers keep getting in.
Logged-in WordPress users aren't served from the cache: pages requested with a session cookie always reach the site, so the admin area and the editor work as before.
6. Let WordPress see visitors' real IP
Behind a CDN, WordPress sees every visit coming from the node addresses. Security plugins, statistics and login attempt limits need to read the real IP, which 1PrimeCDN nodes pass in the X-Forwarded-For header (and in X-PrimeCDN-Client-IP). In the panel, under Pull Zone → Origin, you'll find ready-made lines to paste into wp-config.php, with the node list already included.
Summary
| Problem | Server-side defence | CDN defence |
|---|---|---|
| Brute force on wp-login.php | Attempt limits, 2FA | Per-IP limits, scoring and automatic blocking |
| xmlrpc.php | Block it if unused | Per-IP limits and scoring on the nodes |
| Site search | Limit searches | Per-IP limits, check under attack |
| Spikes on public pages | Caching plugin | Caching on the nodes |
| Attack hitting the server's IP | Firewall | Server open only to the nodes |
If WordPress is already down right now, start from website under DDoS attack: what to do right now or write to us from the emergency page.
Want a site that holds up even under attack?
1PrimeCDN puts your site behind 8 European nodes with caching, HTTPS and Shield against bots and attacks. Fixed monthly price from €9.90.