4

I have an old site ported from WordPress to basic HTML (don't ask why) and every page is ending in the subdirectory/index.html.

This is causing some funky indexing issues, so I wanted to 301 all the index.html to its parent subdirectory.

So for instance, I would like my pages:

  • example.com/index.html to 301 to example.com/
  • example.com/service/index.html to 301 to example.com/service/
  • example.com/about-us/index.html to 301 to example.com/about-us

etc, etc.

2
  • 2
    What do you mean "every page is ending in the subdirectory/index.html" ? That is what internal links look like? – Steve Jun 11 '17 at 23:15
  • Every URL in WordPress often ends in a / (depending on the permalink settings). If you copy a WordPress website to static files using something like wget, you often get a ton of directories, each containing exactly one file: index.html. Depending on your download crawler, the links may or may not actually point to index.html. – Stephen Ostermiller Jun 12 '17 at 23:09
4

First, a couple of assumptions:

  1. All your internal links must already point to the non-index.html URL, eg. example.com/service/. (However, since you state that "every page is ending in the subdirectory/index.html" and you are experiencing some "funky indexing issues, I wonder if this is the case?)
  2. You are using .htaccess on Apache.

Try something like the following near the top of your .htaccess file:

RewriteEngine On
RewriteCond %{THE_REQUEST} /index\.html
RewriteRule (.*)index\.html$ /$1 [R=301,L]

The check against THE_REQUEST in the RewriteCond directive ensures that only direct requests from the client, that contain index.html, get redirected. THE_REQUEST server variable contains the first line of the request headers and does not get modified when the URL is rewritten. This avoids a potential redirect loop when mod_dir later issues a subrequest for index.html (the DirectoryIndex document) - although this shouldn't be an issue on Apache 2.2+.

However, this could be "simplified" further. The RewriteCond directive could be omitted if using the NS (nosubreq) flag on the RewriteRule directive. The NS flag prevents the rule being processed on "subrequests". As mentioned above, when mod_dir rewrites the URL, it is considered a subrequest. So, by simply including the NS flag, we again avoid a redirect loop. So, the above directives could be replaced with a single RewriteRule directive:

RewriteRule (.*)index\.php$ /$1 [NS,R=301,L]

If you also have a canonical www to non-www redirect then it may be optimal to include the above rule first and specify the canonical absolute domain in the RewriteRule substitution (thus avoiding a potential double redirect). For example:

:
RewriteRule (.*)index\.html$ https://example.com/$1 [R=301,L]

example.com/about-us/index.html to 301 to example.com/about-us

I assume the missing trailing slash on your last example was a typo? The above rule includes a trailing slash (which is required). Omitting the trailing slash introduces additional complexity.

6
  • Have you tested that the rewrite rule is compatible with Apache's DirectoryIndex? The rewrite rule looks like it could work, but I've found that you usually have to use environment variables in similar situations to avoid infinite loops: How to rewrite to a script and also redirect away from that script using .htaccess while avoiding infinite loops – Stephen Ostermiller Jun 12 '17 at 13:50
  • 1
    @StephenOstermiller Yes, this does seem to work OK in my testing. It does require the DirectoryIndex to be set correctly (which I assume it must be if URLs like example.com/service/ are already working ok). The check against THE_REQUEST ensures it should only match the initial request (not the subsequent subrequest that results when mod_dir rewrites back to index.html - the DirectoryIndex) thus avoiding a redirect loop. This is a bit like your environment variable check. This example could even be "simplified" further into a one-liner by using the NS flag. I'll update my answer. – MrWhite Jun 12 '17 at 20:12
  • @StephenOstermiller However, this example is a bit different to your question over on SO. You are manually rewriting all requests to a single file (this isn't considered a "subrequest", it's simply an "internal rewrite"), so you wouldn't be able to make use of the NS flag, unlike in the example above. When mod_dir internally rewrites the request to the directory index (as opposed to you manually rewriting the request with mod_rewrite) then it is a "subrequest" and can be trapped with the NS (nosubreq) flag. – MrWhite Jun 12 '17 at 20:23
  • This is where your technical knowledge of Apache's internals well surpasses mine. :) I'll have to keep your THE_REQUEST trick in mind next time I need something like this. It sounds easier than the environment variable. – Stephen Ostermiller Jun 12 '17 at 20:25
  • 1
    Yes, thanks. I accepted your answer there because it is much more thorough and actually contains enough code. – Stephen Ostermiller Jun 12 '17 at 23:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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