.htaccess RewriteRules are giving a 404 error

Viewed 35

I've the following .htaccess file including these rewriting rules:

RewriteEngine On

RewriteCond %{REQUEST_URI} !(.html|.js|.css)
RewriteCond %{REQUEST_URI} !^(.*).(jpg|jpeg|png|gif|txt|ico|webp)
RewriteCond %{REQUEST_URI} !(.eot|.ttf|.woff)

RewriteRule ^(.*) talents/index.html [NC,L]

I want that users will get redirected to the index.html which is located inside a subdirectory with the use of a "rewrite rule".

At the moment the redirection doesn't work. I get a 404 "Page not found" error.

1 Answers
RewriteRule ^(.*) talents/index.html [NC,L]

The URLs look like that: https://xy.de/talents/classes/priest/7ebk-70us/discipline or https://xy.de/df-talents/classes/monk/7e9s-5m9s/mistweaver/7400

It's located inside the talents subdirectory.

The RewriteRule substitution string (2nd argument) is wrong if the .htaccess file is itself located in the /talents subdirectory. In this case the above RewriteRule will try to rewrite the request to /talents/talents/index.html, not /talents/index.html as intended, because a relative substitution string is (by default) relative to the directory that contains the .htaccess file.

There are 3 ways to resolve this, either:

  • Prefix the substitution string with a slash to make it root-relative. For example:

    :
    RewriteRule ^ /talents/index.html [L]
    

    (The regex ^(.*) is not necessary. The NC flag is not required either.)

OR,

  • Use a RewriteBase directive to set the URL-path that all relative substitution strings are relative to. For example, after the RewriteEngine directive:

    RewriteBase /
    

    The value of RewriteBase is effectively prefixed to relative substitution strings.

OR,

  • Remove talents/ from the substitution string altogether and remove the dependency on the parent directory name. This would be the preferred solution. For example:

    :
    RewriteRule ^ index.html [L]
    

    Since the .htaccess file is contained inside the /talents subdirectory then the above relative substitution string will rewrite the request to /talents/index.html.


https://xy.de/df-talents/classes/monk/7e9s-5m9s/mistweaver/7400

However, your second example references /df-talents, not /talents?


Aside:

RewriteCond %{REQUEST_URI} !(.html|.js|.css)
RewriteCond %{REQUEST_URI} !^(.*).(jpg|jpeg|png|gif|txt|ico|webp)
RewriteCond %{REQUEST_URI} !(.eot|.ttf|.woff)

The regex in your conditions are inconsistent and matching too much. They would, for instance, prevent a URL like /talents/icon-magic being routed to your front-controller since the file-extensions are not anchored at the end of the URL-path and the literal dots are not escaped (so match any character). In the second condition you are unnecessarily matching the entire URL-path and capturing this in a backreference.

The above conditions should be written like this instead:

RewriteCond %{REQUEST_URI} !\.(html|js|css)$
RewriteCond %{REQUEST_URI} !\.(jpg|jpeg|png|gif|txt|ico|webp)$
RewriteCond %{REQUEST_URI} !\.(eot|ttf|woff)$

You could also consider making the RewriteRule pattern more restrictive (it currently matches everything) and potentially removing the need for the preceding conditions altogether (that exclude URLs that include one of a set of known file extensions). For example, if your URLs do not contain dots (that ordinarily delimits the file extension) then simply excluding dots from the regex would allow you to omit all the preceding conditions. For example:

RewriteRule ^[^.]*$ index.html [L]

The above directive only rewrites the request when the URL-path does not contain a dot.

Related