Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

redirect /foo.html to /foo but not / to /index in nginx

Tags:

redirect

nginx

My files on disk have extensions: index.html, a.html. I want a request for http://example.com/a to load /var/www/a.html and http://example.com/ to load /var/www/index.html. I want any other url to redirect to a canonical url, so http://example.com/a.html should redirect to http://example.com/a.

My configuration looks like:

rewrite ^(/.+)\.html$ $scheme://$host$1 permanent;
location / {
    root   /var/www;
    try_files $uri.html $uri $uri/ =404;
}

This does redirect /a.html to /a and succeed at loading a.html from disk:

$ curl -D- -s http://www.jefftk.com/food.html | grep ^Location
Location: http://www.jefftk.com/food
$ curl -s http://www.jefftk.com/food | grep ^Location

But it sends / to /index:

$ curl -s -D- http://www.jefftk.com/pictures/ | grep ^Location
Location: http://www.jefftk.com/pictures/index
$ curl -s -D- http://www.jefftk.com | grep ^Location
Location: http://www.jefftk.com/index

If I remove the rewrite rule it stops redirecting from /a.html to /a but also stops sending / to /index:

$ curl -D- -s http://www.jefftk.com/food.html | grep ^Location
$ curl -D- -s http://www.jefftk.com/food | grep ^Location
$ curl -D- -s http://www.jefftk.com/ | grep ^Location
$ curl -D- -s http://www.jefftk.com/pictures/ | grep ^Location

Why would this happen? Can I make nginx to both things I want (no .html extension, no index in url) at the same time?

like image 373
Jeff Kaufman Avatar asked Dec 19 '12 21:12

Jeff Kaufman


1 Answers

I think your rewrite rule might be backwards. Maybe simply this (no rewrite rule):

location / {
    try_files $uri.html $uri $uri/ =404;
}

location = / {
    index index.html;
}

EDITED VERSION:

Sorry, I wasn't understanding your description completely. I reread it several times and tested this and it might be closing to what you are looking to do:

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

location = /index {
    return 301 $scheme://$host;
}

location ~* \.html$ {
    rewrite ^(.+)\.html$ $scheme://$host$1 permanent;
}

location / {
    try_files $uri.html $uri/ @backend;
}

location @backend {
    # rewrite or do whatever is default for your setup
    rewrite ^ /index.html last;
    // or return 404;
}

CODE EXAMPLE (REVISION 3):

I'm hoping the third time is a charm. Maybe this will solve your problem?

# example.com/index gets redirected to example.com/

location ~* ^(.*)/index$ {
    return 301 $scheme://$host$1/;
}

# example.com/foo/ loads example.com/foo/index.html

location ~* ^(.*)/$ {
    try_files $1/index.html @backend;
}

# example.com/a.html gets redirected to example.com/a

location ~* \.html$ {
    rewrite ^(.+)\.html$ $scheme://$host$1 permanent;
}

# anything else not processed by the above rules:
# * example.com/a will load example.com/a.html
# * or if that fails, example.com/a/index.html

location / {
    try_files $uri.html $uri/index.html @backend;
}

# default handler
# * return error or redirect to base index.html page, etc.

location @backend {
    return 404;
}
like image 74
kchan Avatar answered Nov 15 '22 07:11

kchan