nginx – hiding index.html and index.htm (redirect)

Here’s a breakdown of what I wanted redirects for the sites in question to do: —-> —-> —->

So *just* dropping index.htm (and index.html) in the URL to avoid the situation where you end up with duplicate URLs that point to the same thing (and look clunky/ugly). It had to behave this way BOTH in the ROOT as well as in other DIRECTORIES.


After trying quite a few iterations and eating numerous redirect loops, I finally came across something nice and simple that seemed to work with nginx:

if ( $request_uri ~ "/index.htm" ) {
 rewrite (.*)/ /$1 permanent;
index index.htm index.html

The “request_uri” line will take care of anything that starts with index.htm – so index.html, index.htmaaaaa, etc. If you’ve done something really wonky like calling your files index.htm1, index.htm2, index.html1, index.html2, etc, note that ALL of those will now redirect, so you’ll probably have to mod the request_uri line to be more specific if you have an edge case like that.

While it works well functionally, there’s a caveat… While behavior at the root works as expected, it doesn’t leave a trailing slash on directories, so you’ll end up with a 2nd 301 redirect as nginx takes care of that. Because my goal was mainly to keep search engines from finding/using the index.html versions, I’m not terribly concerned. However, if your site originally had a bunch of index.html files that people may have linked to, you’ll probably want to split it into 2 versions (one to handle the root and a version to handle everything else).

Other important things to note:

  • You want that in a server block, NOT in a location block. An “if” in a location block is one of the pitfalls the nginx site says to watch for and avoid.
  • Web browsers like to “cache” the old redirects you were using – even the broken ones. I ended up at the point where I was clearing all the browser data, then exiting/restarting Firefox after each change because sometimes a change would take and other times it wouldn’t. So if it doesn’t seem to do anything, try clearing your browser data and restarting it.
  • Chances are you’ve already got the “index index.htm index.html” line somewhere already (or something equivalent), but if not, you’ll end up with 403 errors in each directory unless you add it. The redirect will work without it – it’ll just be kinda useless if the end result is a 403 page.


Anyway, if you’ve been trying to do something similar, hopefully that helps you. Feel free to leave a comment if it works for you (or doesn’t). If someone finds a way to make it work without any “if” statements at all, I’d definitely love to hear how you did it – personally, my first attempts were via try_files and they all ended up with redirect loops in certain situations.