Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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]
</IfModule>

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:

http://www.borngeek.com/nothere/

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)
share|improve this question

migrated from stackoverflow.com Jun 22 '12 at 14:52

This question came from our site for professional and enthusiast programmers.

    
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 '12 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 '12 at 15:04
    
which version of Apache and PHP are you running? which operating system? –  Kaii Jun 20 '12 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. –  Jonah Bishop Jun 20 '12 at 15:25
1  
Is FastCGI enabled on your Dreamhost instance? –  anjunatl Jun 20 '12 at 15:53
show 1 more comment

2 Answers

up vote 1 down vote accepted

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.

share|improve this answer
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 '12 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 '12 at 17:26
    
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 '12 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 '12 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 '12 at 17:36
show 9 more comments

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

Dw.

share|improve this answer
    
actually thats what the OP already does .. please review the question –  Kaii Jun 20 '12 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 '12 at 9:34
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.