So, I found an answer to removing the .html extension on my page, that works fine with this code:
server {
listen 80;
server_name _;
root /var/www/html/;
index index.html;
if (!-f "${request_filename}index.html") {
rewrite ^/(.*)/$ /$1 permanent;
}
if ($request_uri ~* "/index.html") {
rewrite (?i)^(.*)index\.html$ $1 permanent;
}
if ($request_uri ~* ".html") {
rewrite (?i)^(.*)/(.*)\.html $1/$2 permanent;
}
location / {
try_files $uri.html $uri $uri/ /index.html;
}
}
But if I open mypage.com it redirects me to mypage.com/index
Wouldn't this be fixed by declaring index.html as index? Any help is appreciated.
This has often come up for me as well and due to the configuration at work, location blocks are iffy at best and the / & .php blocks are locked down. Which means that most of the solutions don't work for me.
So here is one that I simplified from the Accepted answer above.
Works great for CMSs, where the underlying framework is generating the pages
The "Holy Grail" Solution for Removing ".html" in NGINX:
UPDATED ANSWER: This question piqued my curiosity, and I went on another, more in-depth search for a "holy grail" solution for
.html
redirects in Nginx. Here is the link to the answer I found, since I didn't come up with it myself: https://stackoverflow.com/a/32966347/4175718However, I'll give an example and explain how it works. Here is the code:
What's happening here is a pretty ingenious use of the
if
directive. Nginx runs a regex on the$request_uri
portion of incoming requests. The regex checks if the URI has an .html extension and then stores the extension-less portion of the URI in the built-in variable$1
.From the docs, since it took me a while to figure out where the
$1
came from:The regex both checks for the existence of unwanted .html requests and effectively sanitizes the URI so that it does not include the extension. Then, using a simple
return
statement, the request is redirected to the sanitized URI that is now stored in$1
.The best part about this, as original author cnst explains, is that
Unlike the rewrites, which operate on any
.html
request (including the invisible internal redirect to/index.html
), this solution only operates on external URIs that are visible to the user.What does "try_files" do?
You will still need the
try_files
directive, as otherwise Nginx will have no idea what to do with the newly sanitized extension-less URIs. Thetry_files
directive shown above will first try the new URL by itself, then try it with the ".html" extension, then try it as a directory name.The Nginx docs also explain how the default
try_files
directive works. The defaulttry_files
directive is ordered differently than the example above so the explanation below does not perfectly line up:UPDATE: What does the regex do?
The above answer touches on the use of regular expressions, but here is a more specific explanation for those who are still curious. The following regular expression (regex) is used:
This breaks down as:
^
: indicates beginning of line./
: match the character "/" literally. Forward slashes do NOT need to be escaped in Nginx.(.*)
: capturing group: match any character an unlimited number of times\.
: match the character "." literally. This must be escaped with a backslash.html
: match the string "html" literally.$
: indicates end of line.The capturing group
(.*)
is what contains the non-".html" portion of the URL. This can later be referenced with the variable$1
. Nginx is then configured to re-try the request (return 302 /$1;
) and thetry_files
directive internally re-appends the ".html" extension so the file can be located.UPDATE: Retaining the query string
To retain query strings and arguments passed to a
.html
page, thereturn
statement can be changed to:This should allow requests such as
/index.html?test
to redirect to/index?test
instead of just/index
.Note that this is considered safe usage of the `if` directive.
From the Nginx page If Is Evil:
Also, note that you may swap out the '302' redirect for a '301'.
A
301
redirect is permanent, and is cached by web browsers and search engines. If your goal is to permanently remove the.html
extension from pages that are already indexed by a search engine, you will want to use a301
redirect. However, if you are testing on a live site, it is best practice to start with a302
and only move to a301
when you are absolutely confident your configuration is working correctly.