Clean-URL rewrite rule with nested "location" and alias directive

Francis Daly francis at
Wed Nov 20 09:10:38 UTC 2013

On Tue, Nov 19, 2013 at 05:48:59PM -0500, Ben Johnson wrote:
> On 11/19/2013 3:39 PM, Francis Daly wrote:

Hi there,

> :) I'm using nginx-1.1.19, because that's what's bundled with Ubuntu

It's good to know that this configuration works on older versions too.

> > I think that the problem may be due to the interaction between "alias"
> > and "$document_root" being not-always-obvious.
> > 
> > And $document_root is used in try_files, which is probably what you
> > want for "clean URLs" -- serve the file if present, else hand it to
> > a controller.
> I think that you're exactly right. I had tried try_files first, but was
> unable to get it to work given that this site a) must be accessed via a
> "subdirectory" relative to the domain-root URL, and b) is comprised of
> files that live in a "private" directory that is outside of the
> server-root on the filesystem.

Generally it shouldn't be a problem -- file space and url space are
different, and one of the main points of web server configuration is to
map between them.

If you do have free choice in the matter, some things work more easily
within nginx if you can use "root" and not "alias" -- so if you want
files to be accessible below the url /stage/, having them directly in
a directory called /stage/ is convenient.

(So if you can either get rid of the web/ directory and move all contents
up one, or add a stage/ below web/ and move all contents down one,
then set "root" appropriately and the remaining configuration may become

> > ===
> >       location ^~ /stage/ {
> >         alias /var/www/;
> >         index index.php index.html index.htm;
> >         try_files $uri $uri/ /stage//stage/index.php?q=$uri;
> > 
> >         location ~ ^/stage/(.+\.php)$ {
> >                 alias /var/www/$1;
> >                 try_files "" / /stage/index.php?q=$uri;
> >                 fastcgi_pass unix:/var/run/php5-fpm.sock;
> >                 fastcgi_param HTTPS on;
> >                 fastcgi_param SCRIPT_FILENAME $request_filename;
> >                 include /etc/nginx/fastcgi_params;
> >         }
> >       }
> > ===

> had read at : "Note that
> there is a longstanding bug that alias and try_files don't work
> together" (with link to ).

> Is the implication here that "alias" does indeed work with "try_files"
> (even in my stale nginx-1.1.19 version)? At least in this particular
> use-case?

I'd say rather that this configuration works with the current
implementation of the defect.

So if the defect is fixed, this configuration will start to fail, but a
more obvious working configuration will be available; but if the defect
is changed or partly fixed, this configuration may start to fail without
an equivalent workaround.

The ticket-#97 page currently (last modified date 2013-08-23) lists
three aspects in the description.

The second aspect is, as I understand it, that in a prefix location with
alias, if the fallback contains a $variable and begins with the location
prefix, then the location prefix is stripped before the internal rewrite
is done. In this configuration, that's why the extra /stage/ is in the
first try_files.

The third aspect is, as I understand it, that in a regex location
with alias, $document_root is set to the alias, which in this case is
equivalent to the wanted filename. That's why an argument of "" finds
the file, if it is present, in the second try_files.

I strongly suspect that the second argument there, /, can safely be
dropped -- it can only apply if there is a directory called something.php;
and in that case, I see no difference with the / there or not (in 1.5.7).

> There is one last trick to pull-off, which is to add very similar
> clean-URL functionality for two other files (in addition to index.php),
> but I am hoping that I will be able to adapt your working sample myself.

I don't fully follow what you mean there; but once you can isolate your
requests in a location, then you should be able to set the fallback to
whatever you want.

It may get to the point that it is clearer to use a @named location as
the fallback, and just hardcode SCRIPT_FILENAME in them. You'll see when
you do it, no doubt.

> > You may want to use something other than $uri in the last argument to
> > try_files, depending on how you want /stage/my-account/?key=value to
> > be processed.

The usual caveats apply here regarding url escaping -- you've copied
an unescaped string directly into query string, so if there were any
characters like % or + or & involved, they may cause confusion.


Francis Daly        francis at

More information about the nginx mailing list