Using try_files while forcing a trailing-slash in the URL

Francis Daly francis at
Tue Jun 18 21:55:00 UTC 2013

On Tue, Jun 18, 2013 at 03:22:04PM -0400, Ben Johnson wrote:

Hi there,

> The try_files directive is brilliant. The only problem I'm having is
> that I would like to be able to force a trailing-slash, a la "rewrite",
> on the fallback URL.

> This works well, but I have a need to eliminate duplicate URLs (for SEO
> ["duplicate-content penalty"] reasons) by forcing a trailing slash on
> all virtual URLs (that is, URLs that do not point to a real file or
> directory).
> Am I missing something obvious?

try_files decides which file to serve, with a single fallback option. If
that fallback option is something complicated, it is probably best to
use a named location and put the complications in there.

> I was able to cook-up a "working solution", but it will probably bristle
> a few peoples' hair:

If it works, it works. If you can measure the load on your test server,
you may be interested in trying other things too and comparing.

For example:

  location / {
    try_files $uri $uri/ @virtual;
  location @virtual {
    if ($uri !~ '/$') {
      return 301 $uri/$is_args$args;
    fastcgi_pass unix:php.sock;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    include fastcgi_params;

as well as a location for handling /index.php or any similar things

(Depending on what exactly your php script does, you may also want to
set QUERY_STRING explicitly.)

> Ultimately, I'm wondering if there's a means by which to achieve the
> above with try_files, and if not, if there's a better means than what
> I've employed on my own.

The above uses try_files, and uses "if" within "location" with only
"return", which is a safe thing to do.

> A related "problem" (more an inconvenience, really) is that using
> try_files in the manner described in the cited documentation causes the
> trailing ampersand ("&") to be appended to "q" even when there are no
> $args. Is this behavior intentional? Maybe there's an RFC of which I"m
> unaware that lead to this decision.

You asked for $uri, then &, then $args.

You should be surprised if you get anything other than $uri, then &,
then $args.

I suspect it was done because the php script it feeds is known to ignore
the unnecessary &.

nginx does provide the variable $is_args, but that is intended for other
circumstances where it is more useful. You could do more "if" things on
$is_args or on $args to decide whether to add the &, if you want to.

Good luck with it,

Francis Daly        francis at

More information about the nginx mailing list