Search code examples
apachehttp-redirectmod-rewritehttp-status-code-404custom-error-pages

Apache redirect existing page to a "page not found" preserving HTTP 404 code


What I want to do is to issue a 404 error on some location that exists in such a way so that it is indistinguishable from a real 404 error for a location which does not exist.

I want the following to occur:

  • If I go to https:\mywebsite.com/private/something I want the Apache to show its standard not found message:
Not Found
The requested URL was not found on this server.
  • The URL should remain the same, e.g. https:\\mywebsite.com/private/something.
  • It should give a 404 HTTP error code, and all other headers such as it is indistinguishable from a normal "not found" response, whether "something" exists or not.

Is there a way to achieve this using mod_rewrite?

Next step would be to make it work with a custom "not found" page, e.g. something like

ErrorDocument 404 /errors/404.html

but so that the URL still remains the same and the criteria above are satisfied, except for having a custom .html instead of just text as an error message.

Note that ErrorDocument directive does redirect and replaces 404 error code by 301 (moved permanently), which is not the desired behavior.

Also, if there is some other way not using mod_rewrite - I'm curious to know how to do that. I could not find how to "fake" a non-existent page in apache documentation.

Edit 1: As suggested by MrWhite,

RewriteRule ^/?(?:php|private)(/?|/.*)$ - [L,R=404]

Solves the problem. The remaining question (improvement) is how to serve a custom "Not Found" page using

ErrorDocument 404 /my-custom-404-page.php

and to "preserve" the original URL and 404 HTTP error code. I've tried the latter and it does give a 301 redirect on Apache 2.4.


Solution

  • Using mod_rewrite:

    RewriteRule ^private/something$ - [R=404]
    

    This will trigger the default Apache 404 (with a 404 response code), unless you have defined a custom 404 ErrorDocument as you have mentioned, then that will be served instead (with a 404 response code).

    If you are not using mod_rewrite for anything else then you can do the same with a mod_alias Redirect (or RedirectMatch) directive. For example:

    Redirect 404 /private/something
    

    But note that you should not mix mod_rewrite and mod_alias directives in the same context as you can get unexpected results. (Different modules are processed at different times during the request.)

    Note also that the Redirect directive is prefix-matching, so /private/something/foo would also trigger a 404.

    Despite the use of the R flag (mod_rewrite) or Redirect directive (mod_alias) there is no external "redirect" here. The 404 is served as an internal subrequest. (The URL does not change.)

    HOWEVER...

    ErrorDocument 404 \errors\404.html
    

    You should be using (forward) slashes / throughout, not backslashes \. ie. It should be /errors/404.html.

    (The same applies to every other backslash in your question!)

    Note that ErrorDocument directive does redirect and replaces 404 error code by 301 (moved permanently), which is not the desired behavior.

    No it doesn't! If, however, you have used an absolute URL (ie. with a scheme+hostname) in the ErrorDocument directive then it will trigger a 302 (temporary) redirect. (Maybe the backslashes would also cause this, although I would perhaps expect this to be output as literal text instead?) It never triggers a 301 redirect. (If you are seeing a 301 then something else is doing that.)

    This isn't really "faking" a 404. A 404 is a 404.