•

How I Diagnosed a WordPress Site That Looked Down Even Though the Server Was Fine

It’s not a great start to a relationship managing a WordPress site when the very next day the client sends a message “Our website is down, can you get it back up quickly?”

I had just taken over the management of the WordPress site and had planned to get familiar with the setup that day since it was hosting on an AWS Lightsail instance with lots of customisation at the Linux level.

Normally a quick reboot on the Lightsail instance would sort things out, but life is rarely that easy, especially when you’re now fully responsible for the WordPress site.

Here’s what the symptoms were:

  1. The browser would time out
  2. The site was unreliable, up and then down, then up

At first glance it looked like a fairly standard hosting problem.

Except the server itself looked healthy.

That turned this into a much more interesting troubleshooting exercise, because the obvious explanation was wrong.

What followed was a useful reminder that when a WordPress site appears offline, the actual cause can sit anywhere across the stack: Apache, PHP, MySQL, firewall rules, security tools, bot traffic, or even your own IP address.

This is the route I took to diagnose it.

The initial symptom

The site was hosted on AWS Lightsail.

From the browser, it either failed to load or timed out entirely.

I logged into the server over SSH and started with the basic checks:

uptime
free -h
df -h

Nothing looked alarming.

The load average was low.

There was plenty of free disk space.

Memory usage was reasonable.

The server had swap available and wasn’t thrashing.

That immediately changed the nature of the problem.

If the server was genuinely overloaded, I would expect to see high load, memory exhaustion, disk issues, or obvious service failures.

I saw none of those.

Step 1: Is Apache actually serving anything?

The first useful test was to avoid the public internet altogether and ask the server to talk to itself.

I ran:

curl -I http://127.0.0.1

and:

curl -k -I https://127.0.0.1

Apache responded immediately.

WordPress was also redirecting correctly to the live domain.

That told me:

  • Apache was running
  • PHP was executing
  • WordPress was loading
  • the site wasn’t completely dead

I then tested the live domain from the server itself:

curl -I https://example.com

That also responded.

So the server could serve the site.

Why was I not able to access the website when apparently it should be up and running.

The problem was not as simple as “Apache has crashed”.

Step 2: Check Apache and MariaDB

Next I checked the service states.

Apache was up.

MariaDB was up.

Both had started cleanly after a recent reboot.

Nothing obvious there either.

At this point the site was responding quickly from inside the machine, while still appearing unreliable externally.

That usually means you need to stop looking only at WordPress.

Step 3: The logs showed a second problem

The Apache error logs were more interesting.

I found this:

AH00161: server reached MaxRequestWorkers setting

The server was running Apache with mpm_prefork, and the configuration allowed up to:

MaxRequestWorkers 150

On a 2 GB server, that immediately raised a red flag.

Apache prefork can be memory hungry because each worker is a separate process capable of handling PHP.

If enough requests hang or run slowly, you can exhaust all available workers without necessarily producing huge CPU usage.

The WordPress logs also contained database errors such as:

MySQL server has gone away

and:

Lock wait timeout exceeded; try restarting transaction

At first glance, that made the database look suspicious.

But the fact that so many unrelated plugins were throwing database errors suggested something broader.

The site had Elementor, Wordfence, WP-Optimize, AIOSEO, Instagram Feed and other plugins all reporting failures around the same time.

That looked less like a broken plugin and more like the whole stack getting congested.

Step 4: What was actually hitting the site?

I looked at the Apache access log around the time the server hit MaxRequestWorkers.

One IP was probing paths such as:

/.env
/.env.production
/.env.development
/admin/.env
/api/.env
/backend/.env
/laravel/.env

There were dozens of similar requests within seconds.

That is standard automated scanner behaviour.

The scanner wasn’t finding anything useful, but it was creating work for Apache.

I also saw several:

408 Request Timeout

responses.

That was important.

A slow or malformed request can occupy an Apache prefork worker for much longer than a normal page request.

You don’t necessarily need thousands of requests per second to cause trouble.

You just need enough requests to remain open long enough to consume all available workers.

Step 5: The server looked fine, but my browser still couldn’t connect

At this stage there were clearly server-side issues worth fixing:

  • bot traffic
  • Apache prefork
  • an excessive worker limit
  • database contention under load

But something still didn’t make sense.

My browser couldn’t load the site even when the server was healthy.

So I tested whether Apache was listening publicly:

sudo ss -ltnp | grep -E ':80|:443'

It was listening on:

*:80
*:443

So Apache was not bound only to localhost.

I also tested the server’s public IP from the server itself:

curl -I http://SERVER-IP

and:

curl -k -I https://SERVER-IP

Both worked.

The web server was responding.

That meant the problem had to be somewhere between my browser and Apache.

Step 6: The real cause of my apparent outage

I checked iptables.

That was the breakthrough.

There was a fail2ban chain called:

f2b-wordpress-bots

and my own public IP address was listed as:

REJECT

Fail2ban had banned me from ports 80 and 443.

That explained everything.

SSH still worked because the fail2ban rule only covered HTTP and HTTPS.

The server could talk to itself.

Apache was fine.

MariaDB was fine.

But my browser traffic was being rejected before it ever reached WordPress.

The site looked completely offline from my perspective, while still being technically operational.

Why Fail2ban banned me

The jail configuration was:

[wordpress-bots]
enabled = true
port = http,https
filter = wordpress-auth
logpath = /var/log/apache2/access.log
maxretry = 3
findtime = 300
bantime = 604800

That means:

  • 3 matches
  • within 5 minutes
  • result in a 7 day ban

The filter itself was:

failregex = ^<HOST> .* "(GET|POST) .*(wp-login.php|xmlrpc.php)

That is the real problem.

It didn’t match failed logins.

It matched any request to wp-login.php or xmlrpc.php.

Simply loading the login page a few times could get you banned.

Which is exactly what had happened.

I had tried to log in using credentials supplied by the previous IT provider.

The login failed.

I tried again a few times.

Fail2ban interpreted those requests as hostile activity and blocked my IP from the site.

The immediate fix

The first step was to unban my IP:

sudo fail2ban-client set wordpress-bots unbanip YOUR.IP.ADDRESS

Then, while troubleshooting, I added my IP to the jail’s ignore list:

sudo fail2ban-client set wordpress-bots addignoreip YOUR.IP.ADDRESS

The site immediately became accessible again.

The bigger lesson

There were actually two issues.

The first was a genuine server resilience problem.

Scanner traffic was hitting the site.

Apache had reached MaxRequestWorkers.

The server was running prefork on a relatively small instance.

That deserves attention.

But the immediate reason I personally could not access the website was completely different.

I had been blocked by fail2ban.

It is very easy to spend hours troubleshooting PHP, MySQL and Apache while your own IP is simply sitting in a firewall rule.

What I changed permanently

I made several changes.

First, I fixed the fail2ban rule so it detects genuine failed authentication rather than every visit to wp-login.php.

Second, I reviewed whether a 7 day ban after 3 requests is appropriate.

Third, I am moving away from:

Apache prefork + mod_php

towards:

Apache event MPM + PHP-FPM

for better concurrency handling.

Fourth, I would put better filtering in front of the origin server so obvious scanner traffic is dealt with before it reaches WordPress.

A useful troubleshooting checklist

If a WordPress site looks down but the server load looks normal, I would now check things in this order:

uptime
free -h
df -h

Then:

curl -I http://127.0.0.1
curl -k -I https://127.0.0.1

Then:

sudo ss -ltnp | grep -E ':80|:443'

Then:

sudo iptables -L -n -v
sudo fail2ban-client status

Then inspect:

Apache access logs
Apache error logs
MariaDB logs

The important thing is to keep narrowing the scope.

Is the server unhealthy?

Is Apache unhealthy?

Is WordPress unhealthy?

Is the public network path blocked?

Is your own IP being rejected?

That methodical approach is what eventually led to the answer.

If you’ve inherited a WordPress site that nobody quite understands anymore, I help businesses untangle hosting, security, plugins and performance issues without jumping straight to a rebuild.