The WordPress .htaccess generally has the following rewrite rules:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

When I access a non-existent URL at my website, this rewrite rule gets hit, redirects to index.php, and serves up my custom 404.php template file. The status code that gets sent back to the client is the correct 404, as shown in this HTTP Live Headers output example:


GET /nothere/ HTTP/1.1
Host: www.borngeek.com

HTTP/1.1 404 Not Found

However, Apache reports the entire exchange with a 200 status code in my server log, as shown here in a log snippet (trimmed for simplicity):

{...} "GET /nothere/ HTTP/1.1" 200 2155 "-" {...}

This makes some sense to me, seeing as the original request was redirected to page that exists (index.php). Is there a way to force Apache to report the exchange as a 404?

My problem is that bogus requests coming from Bad Guys show up as "successful requests" in the various server statistics software I use (AWStats, Analog, etc). I'd love to have them show up on the Apache side as 404s so that they get filtered out from the stat reports that get generated.

I tried adding the following line to my .htaccess, but it had no effect (I'm guessing for the same reason as the previous redirect rules):

ErrorDocument 404 /index.php?error=404

Does anyone have a clever way to fix this annoyance?

Additional Info:

  • OS is Debian 6.0.4, and Apache version looks to be 2.2.22-3 (hosted on DreamHost)
  • The 404 being sent back to the client is being set by WordPress (i.e. I'm not manually calling header() anywhere)
  • Technically, no 404 occurs because the URLs that don't map directly to a file get routed through index.php which serves a custom 404 page. How would Apache even know what page doesn't exist within WordPress?
    – Robert K
    Jun 20, 2012 at 15:02
  • I thought Apache should register and log whatever status code gets thrown inside PHP, but my memory is hazy on the subject.
    – Pekka
    Jun 20, 2012 at 15:04
  • which version of Apache and PHP are you running? which operating system?
    – Kaii
    Jun 20, 2012 at 15:21
  • @Kaii It appears that I'm using Debian 6.0.4 as my OS. It also looks like Apache 2.2.22-3. Jun 20, 2012 at 15:25
  • 1
    Is FastCGI enabled on your Dreamhost instance?
    – anjunatl
    Jun 20, 2012 at 15:53

2 Answers 2


Try changing [L] to [R=404,L] on your RewriteRule line. This will send a 404 to the client and your server log. To avoid displaying the default error page, you can use ErrorDocument 404 /index.php?error=404 to render the attempt at an ErrorDocument that you said you tried before.

You can also use the WP htaccess Control plugin to help manage your htaccess files across upgrades.

  • 1
    With the two RewriteCond's before that rule, that is sending any failed request to a file or directory to index.php, where WordPress picks it up from there. This'll catch the error and use his specified ErrorDocument. Also, I tested R ranges on my Apache 2.2 environment and it appears to cover the everything I tested from the 200's to the 500's listed here: w3.org/Protocols/rfc2616/rfc2616-sec10.html
    – anjunatl
    Jun 20, 2012 at 17:23
  • interesting find. so you basically say that even if you explicitly set the [R=404] modifier in the rewrite rule, apache returns 200 (in both HTTP and server log) when wordpress (or something else) renders a normal page instead of returning a 404 header?
    – Kaii
    Jun 20, 2012 at 17:26
  • 1
    Sorry for not being clear, no - using [R=404] won't even show index.php - it will simply show the default or specified error page and send 404 to the client and server. His problem was that bogus requests were being shown as 200's in his logs, so even though this will cut WordPress' 404 handling out of the picture, he should have the desired result.
    – anjunatl
    Jun 20, 2012 at 17:31
  • i don't understand. index.php is the central bootstrap code of wordpress and does all the rendering. So: wouldn't this imply that no page is ever rendered at all? (except from real files which fall through the RewriteCond)
    – Kaii
    Jun 20, 2012 at 17:34
  • That is correct. However, if he uses the ErrorDocument specified earlier - whatever ?error=404 contains should be rendered properly through WordPress.
    – anjunatl
    Jun 20, 2012 at 17:36

If you can edit the template - you'r in luck - in that case - edit it as to output a 404 or whatever other code. As apache its logging happens (in most circumstances) post PHP - these status codes are picked up in the log in the general setup (plenty of exceptions though).

See http://php.net/manual/en/function.header.php


  • 1
    actually thats what the OP already does .. please review the question
    – Kaii
    Jun 20, 2012 at 15:17
  • right - but in the default WP instance it only tells the client - it does not pass the 404 back up to apache. Where the post logging hook can pick it up and do the logging. I.e. through get_404_template() -> xxx -> apply_filters(). And those need to call header()/status_header() to also let apache (and not just the client) know of the error code to log. Heck - if you wanted to not rely on the specific flavour/template - one could add a error_log(error,..) to the get_404_template() function and 'force' the issue.
    – Dirk-Willem van Gulik
    Jun 21, 2012 at 9:34

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .