Use FallbackResource for WordPress instead of mod_rewrite

FallBackResourceUse FallBackResource as a great alternative to using mod_rewrite to direct Apache to send all requests for non-existing files/directories to a script in WordPress. Htaccess and Server Config enabled.

WordPress Default .htaccess Rewrite Rules

This is the default WordPress .htaccess that says, if request is not already for /index.php and the requested file is NOT an existing directory or file, than internally rewrite requests to /index.php which is how WP enables pretty-permalinks and other features such as db-enabled 404 detection.

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

# END WordPress

Use FallBackResource instead

For WordPress, this works faster, especially when placed in server config context and disabling per-directory htaccess configs.

FallbackResource /index.php

Fallback Resource

FallBackResource

Description:
You want a single resource (say, a certain file, like index.php) to handle all requests that come to a particular directory, except those that should go to an existing resource such as an image, or a css file.
Solution:

As of version 2.2.16, you should use the FallbackResource directive for this:

<Directory "/home/askapache.com/htdocs">
FallbackResource /index.php
</Directory>

Changes with Apache 2.4.4 - Add support for the value 'disabled' in FallbackResource. [Vincent Deffontaines]

Apache 2.3.3 - add FallbackResource directive, to enable admin to specify an action to happen when a URL maps to no file, without resorting to ErrorDocument or mod_rewrite. PR 47184 [Nick Kew]

However, in earlier versions of Apache, or if your needs are more complicated than this, you can use a variation of the following rewrite set to accomplish the same thing:

<Directory "/home/askapache.com/htdocs">
  RewriteBase "/"

  RewriteCond "/home/askapache.com/htdocs/%{REQUEST_FILENAME}" !-f
  RewriteCond "/home/askapache.com/htdocs/%{REQUEST_FILENAME}" !-d
  RewriteRule "^" "index.php" [PT]
</Directory>

If, on the other hand, you wish to pass the requested URI as a query string argument to index.php, you can replace that RewriteRule with:

RewriteRule "(.*)" "index.php?$1" [PT,QSA]

FallBackResource in .htaccess

Note that these rulesets can be used in a .htaccess file, as well as in a <Directory> block.

FallBackResource

FallbackResource Directive

Description:Define a default URL for requests that don't map to a file
Syntax:FallbackResource disabled | <var>local-url</var>
Default:disabled - httpd will return 404 (Not Found)
Context:server config, virtual host, directory, .htaccess
Override:Indexes
Status:Base
Module:mod_dir
Compatibility:The disabled argument is available in version 2.4.4 and later

Use this to set a handler for any URL that doesn't map to anything in your filesystem, and would otherwise return HTTP 404 (Not Found). For example

FallbackResource /not-404.php

will cause requests for non-existent files to be handled by not-404.php, while requests for files that exist are unaffected.

It is frequently desirable to have a single file or resource handle all requests to a particular directory, except those requests that correspond to an existing file or script. This is often referred to as a 'front controller.'

In earlier versions of httpd, this effect typically required mod_rewrite, and the use of the -f and -d tests for file and directory existence. This now requires only one line of configuration.

FallbackResource /index.php

Existing files, such as images, css files, and so on, will be served normally.

Use the disabled argument to disable that feature if inheritance from a parent directory is not desired.

In a sub-URI, such as http://www.askapache.com/ this sub-URI has to be supplied as local-url:

<Directory "/home/askapache.com/htdocs">
    FallbackResource /index.php
</Directory>
<Directory "/home/askapache.com/htdocs/images">
    FallbackResource disabled
</Directory>

FallbackResource in mod_dir.c

Like Rich Bowen says, there is a lot of bad info out on the web for Apache, specifically for htaccess. So you need to get in the habit of reading the C source code for any software you care about. Here is the latest mod_dir.c code taken straight from Apache. Obviously much easier to read in vim or SublimeText, emacs, etc., but for the rest of you: ./modules/mappers/mod_dir.c

static const command_rec dir_cmds[] =
{
    AP_INIT_TAKE1("FallbackResource", ap_set_string_slot,
                  (void*)APR_OFFSETOF(dir_config_rec, dflt),
                  DIR_CMD_PERMS, "Set a default handler"),

static int fixup_dflt(request_rec *r)
{
    dir_config_rec *d = ap_get_module_config(r->per_dir_config, &dir_module);
    const char *name_ptr;
    request_rec *rr;
    int error_notfound = 0;

    name_ptr = d->dflt;
    if ((name_ptr == NULL) || !(strcasecmp(name_ptr,"disabled"))){
        return DECLINED;
    }
    /* XXX: if FallbackResource points to something that doesn't exist,
     * this may recurse until it hits the limit for internal redirects
     * before returning an Internal Server Error.
     */

    /* The logic of this function is basically cloned and simplified
     * from fixup_dir below.  See the comments there.
     */
    if (r->args != NULL) {
        name_ptr = apr_pstrcat(r->pool, name_ptr, "?", r->args, NULL);
    }
    rr = ap_sub_req_lookup_uri(name_ptr, r, r->output_filters);
    if (rr->status == HTTP_OK
        && (   (rr->handler && !strcmp(rr->handler, "proxy-server"))
            || rr->finfo.filetype == APR_REG)) {
        ap_internal_fast_redirect(rr, r);
        return OK;
    }
    else if (ap_is_HTTP_REDIRECT(rr->status)) {

        apr_pool_join(r->pool, rr->pool);
        r->notes = apr_table_overlay(r->pool, r->notes, rr->notes);
        r->headers_out = apr_table_overlay(r->pool, r->headers_out,
                                           rr->headers_out);
        r->err_headers_out = apr_table_overlay(r->pool, r->err_headers_out,
                                               rr->err_headers_out);
        error_notfound = rr->status;
    }
    else if (rr->status && rr->status != HTTP_NOT_FOUND
             && rr->status != HTTP_OK) {
        error_notfound = rr->status;
    }

    ap_destroy_sub_req(rr);
    if (error_notfound) {
        return error_notfound;
    }

    /* nothing for us to do, pass on through */
    return DECLINED;
}

static int dir_fixups(request_rec *r)
{
    if (r->finfo.filetype == APR_DIR) {
        /* serve up a directory */
        return fixup_dir(r);
    }
    else if ((r->finfo.filetype == APR_NOFILE) && (r->handler == NULL)) {
        /* No handler and nothing in the filesystem - use fallback */
        return fixup_dflt(r);
    }
    return DECLINED;
}

More Reading

Apache httpd 2.4 FallbackResource Htaccess mod_dir mod_rewrite RewriteBase RewriteRule wordpress

Comments