11

I've seen a few ways to rewrite the $request_uri and add the index.html to it when that particular file exists in the file system, like so:

if (-f $request_filename/index.html) {
    rewrite (.*) $1/index.html break;
}

but i was wondering if the opposite is achievable:

i.e. when somebody requests http://example.com/index.html, they're redirected to http://example.com

Because the nginx regexp is perl compatible, i tried something like this:

if ( $request_uri ~* "index\.html$" ) {
    set $new_uri $request_uri ~* s/index\.html//
    rewrite $1 permanent;
}

but it was mostly a guesswork, is there any good documentation describing the modrewrite for nginx ?

Arpit
  • 6,212
  • 8
  • 38
  • 69
tjmc
  • 148
  • 1
  • 1
  • 6

7 Answers7

8

The following config allowed me to redirect /index.html to / and /subdir/index.html to /subdir/:

# Strip "index.html" (for canonicalization)
if ( $request_uri ~ "/index.html" ) {
    rewrite ^(.*)/ $1/ permanent;
}
Jackson
  • 9,188
  • 6
  • 52
  • 77
8

I use the following rewrite in the top level server clause:

rewrite ^(.*)/index\.html$ $1 permanent;

Using this alone works for most URLs, like http://example.com/bar/index.html, but it breaks http://example.com/index.html. To resolve this, I have the following additional rule:

location = /index.html {
  rewrite  ^ / permanent;
  try_files /index.html =404;
}

The =404 part returns a 404 error when the file is not found.

I have no idea why the first rewrite alone isn't sufficient.

Nicolas Wu
  • 4,805
  • 2
  • 25
  • 32
  • 1
    `^(.*)/index\.html$` for the (very unlikely) case you have `index/html` or `index2html` or something – Mark Aug 08 '21 at 12:58
2

This one works:

# redirect dumb search engines
location /index.html {
    if ($request_uri = /index.html) {
        rewrite ^ $scheme://$host? permanent;
    }
}
mgutt
  • 5,867
  • 2
  • 50
  • 77
2

For some reason most of the solutions mentioned here did not work. The ones that worked gave me errors with missing / in the url. This solution works for me.

Paste in your location directive.

if ( $request_uri ~ "/index.html" ) {
  rewrite ^/(.*)/ /$1 permanent;
}
Hendrik
  • 4,849
  • 7
  • 46
  • 51
1

For the root /index.html, the answer from Nicolas resulted in a redirect loop, so I had to search for other answers.

This question was asked on the nginx forums and the answer there worked better. http://forum.nginx.org/read.php?2,217899,217915

Use either

location = / {
  try_files /index.html =404;
}

location = /index.html {
  internal;
  error_page 404 =301 $scheme://domain.com/;
}

or

location = / {
  index index.html;
}

location = /index.html {
  internal;
  error_page 404 =301 $scheme://domain.com/;
}
Evgeny
  • 6,533
  • 5
  • 58
  • 64
1

This is working for me:

rewrite ^(|/(.*))/index\.html$ /$2 permanent;

It covers both the root instance /index.html and lower instances /bar/index.html

The first part of the regex basically translates as: [nothing] or /[something] - in the first case $2 is an empty string so you redirect to just /, in the second case $2 is [something] so you redirect to /[something]

I actually went a bit fancier to cover index.html, index.htm, and index.php

rewrite ^(|/(.*))/index\.(html?|php)$ /$2 permanent;
barryp
  • 126
  • 3
  • This puts me in an infinite redirect loop because it tries to redirect https to http and my load balancer then redirects that back to https – djsumdog Feb 11 '18 at 07:48
  • That's surprising, I'd think it'd just be a double redirect with nginx stripping off the index.html and switching to http, and then the load balancer redirecting back to https (but still without the index.html). Seems your nginx isn't aware it should be putting "https" in the absolute URLs, maybe you can do it manually in the rewrite statement, instead of just "/$2" maybe https://$host/$2 – barryp Feb 14 '18 at 15:30
0

The solutions quoting $scheme://domain.com/ assume that the domain is hard-coded. It was not in my case and so I used:

location / {
    ...

    rewrite index.html $scheme://$http_host/ redirect;

    ... }
  • Hi, this looks great, but can you also explain (for us newbies) why the new solution worked better? – Taryn East Jun 25 '13 at 00:12
  • 1
    It is a peculiarity in the nginx config. I discovered empirically (I might be wrong) that there is no way to refer to the root `/` page in a relative fashion. So I was consigned to referring to it in an absolute fashion and to that end we have to give its complete scheme and host name (domain name). This little hack allows us to refer to the domain name without having to hard-code it. I found it particularly useful since I was developing and working with separate staging and Vagrant (virtual machine) versions of the site. – Abid Mujtaba Jul 03 '13 at 21:03