82

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?

Vladimir
  • 103
Rob
  • 2,513

11 Answers11

75

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.

kbec
  • 1,063
49

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

yagmoth555
  • 17,495
haymaker
  • 1,290
12

Why wouldn't you just use

location /phpmyadmin {
    alias /home/phpmyadmin;
}

?

womble
  • 98,245
10

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.

dlouzan
  • 201
4

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;
}
Oriol
  • 411
3

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; }

2

Have you tried using try_files directive?

try_files $uri $uri/ =404;
Prasanth
  • 129
  • 3
1

I did it like that

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

Why not put two rewrites simply:

location ~ ^/phpmyadmin
{
    rewrite /phpmyadmin /home/phpmyadmin/ break;
    rewrite /phpmyadmin/(.*) /home/phpmyadmin/$1 break;
}
千木郷
  • 291
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)

gdm
  • 479
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/ {