80

Right now I have this config:

location ~ ^/phpmyadmin/(.*)$
{
        alias /home/phpmyadmin/$1;
}

However, if I visit www.mysite.com/phpmyadmin (note the lack of trailing slash), it won't find what I'm looking for a 404. I assume because I don't include the trailing slash. How can I fix this?

1
  • 2
    I know this question is quite old, nonetheless I'd like to emphasize on the need to change the accepted answer. Unexperienced users (the ones who'll search for this kind of QAs) might create security holes by using the currently accepted answer.
    – Bozzy
    Mar 5, 2019 at 11:58

11 Answers 11

47

It might be in the regular expression that you're using --

location ~ ^/phpmyadmin/(.*)$

The above will match /phpmyadmin/, /phpmyadmin/anything/else/here, but it won't match /phpmyadmin because the regular expression includes the trailing slash.

You probably want something like this:

location ~ /phpmyadmin/?(.*)$ {
    alias /home/phpmyadmin/$1;
}

The question mark is a regular expression quantifier and should tell nginx to match zero or one of the previous character (the slash).

Warning: The community seen this solution, as is, as a possible security risk

4
  • Thank you! And thank you for the explanation, as well. Will come in handy in the future.
    – Rob
    Apr 3, 2012 at 6:08
  • 25
    The pattern isn't quite correct. It can also match path like "/phpmyadmin1234", obviously that's no what you want. @kbec's solution is the right one.
    – Meow
    Aug 20, 2015 at 12:10
  • 4
    I'm sorry for explicitly downvoting this, but @Meow comment is way to important to neglect. This can lead to a misconfigured webserver which could contain security holes.
    – Daniel F
    Jan 25, 2019 at 20:50
  • 1
    does not work for proxy_pass
    – gdm
    Jun 25, 2020 at 10:39
70

The better solution:

location ~ ^/phpmyadmin(?:/(.*))?$ {
    alias /home/phpmyadmin/$1;
}

Ensure that server has permissions to /home/phpmyadmin first.


Explanation of difference with accepted answer:

It's all about regular expressions.

First of all, the ^ char means that you want to match from beginning of string and not somewhere in the middle. The $ at the end means matching to the end of the string.

The (?:) means non-capturing group - we don't want it in the capturing results, but we want to simple group some chars. We group it like this, because we want the / char to be a nonsignificant part of the child path, and not a significant part of the parent path.

5
12

Why wouldn't you just use

location /phpmyadmin {
    alias /home/phpmyadmin;
}

?

4
  • Because that wasn't working for me. See here: serverfault.com/questions/375602/…
    – Rob
    Apr 3, 2012 at 5:35
  • 1
    @Rob Did you try it without the trailing slash on the alias directive? Apr 3, 2012 at 17:04
  • This is actually the correct answer and correct way of doing it. Simply exclude the trailing slash and it works for urls typed both with and without the trailing slash. No need for complicating anything on Nginx keep it simple, complicated regex and other funny things will only slow Nginx down.
    – MitchellK
    Jun 30, 2018 at 8:52
  • 10
    The problem with this is that it will also match on /phpmyadminblahblahblahblah or any other combination
    – Gary Green
    Jun 29, 2019 at 15:04
9

I know this is an old question, but for anybody that ends up here via Google, I solved it the following way (variation of @kbec's one, which was quite good):

location ~ ^/foo(/.*)?$ {
  proxy_pass http://$backend$1$is_args$args;
}

This will capture any variation of /foo and redirect it to /bar on another url (including parameters). I am showing it with a proxy_pass directive but it would also work with alias.

  • /foo -> /bar
  • /foo/ -> /bar/
  • /foo/sub -> /bar/sub
  • /foo/sub1/sub2/?param=value -> /bar/sub1/sub2/?param=value

It works because $1 will optionally capture the subresources plus the leading slash, so it won't capture things like /fooextra/. It will also redirect a present or non-present ending slash properly.

EDIT: Check comments for caveats about this approach.

5
  • 2
    Thanks for considering the corner case of wanting to use proxy_pass and thus caring about the arguments. You have my upvote.
    – Daniel F
    Jan 25, 2019 at 21:26
  • The problem I see with this answer is that if you request /foo, you wont get an uri appended to the backend, which means you fall in the specific case documented as follow in nginx : "If the address is specified without a URI, or it is not possible to determine the part of URI to be replaced, the full request URI is passed (possibly, modified)." in other word you will pass /foo to the backend. (source: docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy). @kbec answer is better at this. Jan 24, 2021 at 9:08
  • @martin-mystere iirc that only applies when using a prefix string on the location part, but not when using a regex nginx.org/en/docs/http/ngx_http_core_module.html#location
    – dlouzan
    Mar 12, 2021 at 15:42
  • Hi @dlouzan, I'm afraid that after testing, my original guess has verified. I spined up two nginx containers, one to emulate the frontend with the configuration you shared (btw it misses a final ; on the proxy_pass line) and the other one as upstream. With request /foo/ on the frontend, upstream get a request to /. With /foo it gets a request to /foo Mar 15, 2021 at 9:09
  • @martin-mystere Thanks for the hint! I learned something :-)
    – dlouzan
    Mar 16, 2021 at 10:09
3

This redirect will only rewrite URLs with and without the trailing slash. Anything that comes after the slash won't be overwritten.

domain.com/location => redirected to domain.com/new/location
domain.com/location => redirected to domain.com/new/location
domain.com/location/other => not redirected

server {
  # 301 URL Redirect
  rewrite ^/location/?$ /new/location permanent;
}
2

Have you tried using try_files directive?

try_files $uri $uri/ =404;
2

When using proxy_pass with a location given by a prefix string rather than a regular expression Nginx will take care of the trailing slash for you, as described in the docs:

If a location is defined by a prefix string that ends with the slash character, and requests are processed by one of proxy_pass, fastcgi_pass, uwsgi_pass, scgi_pass, memcached_pass, or grpc_pass, then the special processing is performed. In response to a request with URI equal to this string, but without the trailing slash, a permanent redirect with the code 301 will be returned to the requested URI with the slash appended. If this is not desired, an exact match of the URI and location could be defined like this:

location /user/ {
   proxy_pass http://user.example.com;
}

location = /user {
    proxy_pass http://login.example.com;
}
1

Why not put two rewrites simply:

location ~ ^/phpmyadmin
{
    rewrite /phpmyadmin /home/phpmyadmin/ break;
    rewrite /phpmyadmin/(.*) /home/phpmyadmin/$1 break;
}
0

I did it like that

rewrite ^/promo/?$     http://example.com/promo/page43902.html;
location /promo/ {
    root /var/www;
}
0

If you need also proxy_pass it is better to pass arguments too:

location ~/phpmyadmin/?(.*)$ {                                                                                           
         proxy_pass http://server/$1$is_args$args;

That said, my personal suggestions is to NEVER use phpmyadmin in production. You will understand why by checking the access logs of your public web-server... (lot of bots trying to exploit phpmyadmin)

0

I have added another stackoverflow answer here.

It is summarized here:

  • My setup has a couple of apps sitting behind nginx. I want to redirect /appx-uri/bla/blo/bli to /appx-uri/bla/blo/bli/ instead of /bla/blo/bli/ which is the default nginx behavior.
  • Also, all my static files (for an app) are gathered for nginx to serve /repairapp/static/.

Adding the directive rewrite ^/repairapp/([^static].*[^/])$ /repairapp/$1/ permanent; in the server block fixes it.

I then have

  • To fix the issue: rewrite ^/repairapp/([^static].*[^/])$ /repairapp/$1/ permanent;
  • To have nginx serve resources location /repairapp/static/ {
  • To access an app location /repairapp/ {

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .