How to remove both .php and .html extensions from url using NGINX?
Asked Answered
L

5

63

I want my nginx make display all url's clean.

With some research I've made the first case to work. It`s done by following configuration:

location / {
    root   html;
    index  index.html index.htm index.php;
    try_files $uri.html $uri/ =404; 
}

It works for indexhtml.html displaying as indexhtml, but nothing happens with .php. If I change $uri.html to $uri.php, it works neither for .html, neither .php. I`ve tried to put something similar in php location but without any success.

Any advices?

Lichen answered 20/2, 2014 at 14:51 Comment(2)
hold on, do you want the extension to be added without the dot ?Gonroff
No, I do not need extension at all. Thats only for example to understand, that Im not an weirdo, whos having both index.php and index.html files on my server. However, its already solved.Lichen
G
68

From what I've researched, if you append your /etc/nginx/conf.d/domain.tld.conf file to include:

location / {
    try_files $uri $uri.html $uri/ @extensionless-php;
    index index.html index.htm index.php;
}

location ~ \.php$ {
    try_files $uri =404;
}

location @extensionless-php {
    rewrite ^(.*)$ $1.php last;
}

Then restart nginx and give it a go. Hopefully this will help you! More information can be found (where I found it) here @ tweaktalk.net

Georgeannageorgeanne answered 20/2, 2014 at 15:4 Comment(5)
Funny. If I delete codetry_files $uri.html $uri/ =404;code from my previous configuration and add Yours, than everything works fine with php, but doesn`t work with html. If I do not remove previous line and add Yours, "Problem loading page" shows up. How can I combine them to work both?Lichen
Try changing your 'try_files' line under 'location' to: try_files $uri $uri.html $uri/ @extensionless-php; Or possibly: try_files $uri $uri.html $uri/ @extensionless-php $uri/ =404;Georgeannageorgeanne
Thanks a lot! I replaced try_files $uri $uri/ @extensionless-php; with try_files $uri.html $uri/ @extensionless-php; and it`s finally working both for html and php. Great!Lichen
Incase you have installed nginx on Windows n cant seem to find "/etc/nginx/conf.d/domain.tld", then this is actually the same as "nginx/conf/nginx.conf"Latham
Use this to your ddns server.Lalonde
G
65

No need for extra blocks and named locations and everything. Also move the index line outside the location block

server {
  index index.html index.php;
  location / {
    try_files $uri $uri/ $uri.html $uri.php$is_args$query_string;
  }
  location ~ \.php$ {
    try_files $uri =404;
    # add fastcgi_pass line here, depending if you use socket or port
  }
}

Keep in mind that if you have a folder and a file with the same name inside the same folder, like /folder/xyz/ and /folder/xyz.php you won't be able to run the php file if the folder xyz contains an index.php or index.html, just keep this in mind.

Gonroff answered 20/2, 2014 at 17:57 Comment(3)
@elbowlobstercowstand, just another addition, when using $query_string, I prefer using $is_args instead of a plain ? would be a tiny bit cleaner when there's no actual args by not having a trailing ? in the url.Gonroff
Just to add, the important bit in making this work is the =404 needs to be in the try_files in the .php block, not at the end of the location / one, otherwise you'll get 404 errors for URLs for which a .php file does exists.Eyrie
@elbowlobstercowstand was right, I rolled back his last edit, nginx will not see the _GET array if ?$query_string was not added.Gillead
C
14

To further Mohammad's answer, you might also want to offer redirects from .html and .php to the extensionless versions.

This can be accomplished due to the fact that $request_uri contains "full original request URI (with arguments)", and is not affected by the internal rewrites that are not visible to the user.

server {
  index index.html index.php;
  location / {
    if ($request_uri ~ ^/(.*)\.html$) {  return 302 /$1;  }
    try_files $uri $uri/ $uri.html $uri.php?$args;
  }
  location ~ \.php$ {
    if ($request_uri ~ ^/([^?]*)\.php($|\?)) {  return 302 /$1?$args;  }
    try_files $uri =404;
    # add fastcgi_pass line here, depending if you use socket or port
  }
}
Coexist answered 6/10, 2015 at 9:17 Comment(6)
"Directive if has problems when used in location context, in some cases it doesn’t do what you expect but something completely different instead. In some cases it even segfaults. It’s generally a good idea to avoid it if possible." nginx.com/resources/wiki/start/topics/depth/ifisevilDispenser
@Tag, sounds like there should be a separate page ifisevilisevil; it you actually read the ifisevil document you've linked, you'll note that doing a return from within if is explicitly advertised as always being 100% safe, and that's exactly what i'm doing in my answerCoexist
It may be safe, but it isn't the best practice. Please read Pitfalls and Common Mistakes.Dispenser
@Tag, since when is using a safe if is not the best practice? Also, why are you linking to a page that doesn't even claim that it's not the best practice, yet act as if it does claim that it's not?Coexist
As an SEO Expert, I say this should be the accepted answer.Floyfloyd
It can be done without IF: #31503021Groundwork
H
5

This has worked for me for more than 5 years going.

location / {
               
        try_files $uri/ $uri.html $uri.php$is_args$query_string;

}
Hydrogenolysis answered 28/8, 2021 at 20:11 Comment(0)
S
2

Perhaps this may be of use for you... It' Simple and gets the job done:

location / {
  rewrite ^/([^\.]+)$ /$1.html break;
}
Steatite answered 12/1, 2017 at 21:27 Comment(1)
it worked, but now php is not being processed...the php was downloaded!Insurgent

© 2022 - 2024 — McMap. All rights reserved.