Allow internal redirect to URI x, but deny external request for x?

J. Lewis Muir jlmuir at imca-cat.org
Sat Aug 31 14:10:09 UTC 2019


On 08/31, Francis Daly wrote:
> On Fri, Aug 30, 2019 at 04:59:36PM -0500, J. Lewis Muir wrote:
> 
> Hi there,
> 
> > I was wishing for a way to specify a new root but with a modified
> > request URI.  So, I tried the alias directive, and I assumed that
> > $document_root and $realpath_root would refer to the aliased document
> > root, but obviously that can't be since nginx has no way of knowing what
> > the aliased document root should be when all it has is a location alias
> > which is the full path to the resource.  Sorry for the trouble.
> 
> It sounds like your desires are for requests:
> 
>  * starts with /my-app/current/ -> reject
>  * starts with /my-app/releases/ -> reject
>  * matches /my-app/something.php, or /myapp/something.php/anything ->
> fastcgi-process the file /srv/www/my-app/current/something.php
>  * matches /my-app/something -> just send the file
> /srv/www/my-app/current/something
> 
> Is that correct? If so -- do exactly that.

Yes!
 
> For example (but mostly untested):
> 
> ==
>   location ^~ /my-app/current/ { return 200 "nothing to see at /current/\n"; }
>   location ^~ /my-app/releases/ { return 200 "nothing to see at /releases/\n"; }
>   location ^~ /my-app/ {
>     location ~ \.php($|/) {
>       fastcgi_split_path_info ^/my-app(/.*php)(.*);
>       root /srv/www/my-app/current/;
>       include fastcgi.conf;
>       fastcgi_pass unix:php.sock;
>     }
>     alias /srv/www/my-app/current/;
>   }
> ==

Wow!  I had given up on getting this approach to work.  Honestly, I
don't think I would have thought of your solution.  Brilliant!

I tried it, and it worked after making a few tweaks!  Here's what
worked:

  location ^~ /my-app/current/ {
    return 404;
  }

  location ^~ /my-app/releases/ {
    return 404;
  }

  location ^~ /my-app/ {
    index index.php;
    location ~ [^/]\.php(?:/|$) {
      root /srv/www/my-app/current;
      fastcgi_split_path_info ^/my-app(/.+?\.php)(/.*)?$;
      include php-fpm-realpath.conf;
    }
    alias /srv/www/my-app/current/;
  }

I changed the root directive to come before the fastcgi_split_path_info,
but that was just aesthetic; it worked fine the other way
too.  Previously, I had the fastcgi_split_path_info call in
php-fpm-realpath.conf along with the following file-exists check after
it:

  if (!-f $realpath_root$fastcgi_script_name) {
    return 404;
  }

But I moved the fastcgi_split_path_info call out of
php-fpm-realpath.conf so that I could use the custom regex like in your
suggestion.

So, your solution solved my problem!  Thank you!

On a related note, while considering those return-404s for
/my-app/current/ and /my-app/releases/, I realized that those could, in
theory, conflict with the URIs of a web app if the web app actually used
those same URIs.  For example, maybe the web app is a GitLab-type app
and a URI of /my-app/releases/ might very well be part of the app's URI
set for displaying software releases or something.  This has nothing to
do with your solution and everything to do with my initial design choice
that I was trying to achieve, and it's something I hadn't considered
before.

For my current app, it doesn't use those URIs, so it's not a problem,
but as a general scheme, it's not perfect.  I think one solution would
be to move the app root directory to a different name so that it can't
conflict.  For example, have it live at

  /srv/www/my-app-deployment

or something like that.  Then I could just return a 404 for any request
on that, e.g.:

  location ^~ /my-app-deployment/ {
    return 404;
  }

Thanks again!

Lewis


More information about the nginx mailing list