Como posso criar um local no nginx que funcione com AND sem uma barra final?

46

Agora eu tenho esta configuração:

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

No entanto, se eu visitar www.mysite.com/phpmyadmin(observe a falta de barra final), ele não encontrará o que estou procurando por um 404. Suponho que não inclua a barra final. Como posso consertar isso?

Roubar
fonte
2
Sei que essa pergunta é bastante antiga, mas gostaria de enfatizar a necessidade de alterar a resposta aceita. Usuários inexperientes (aqueles que pesquisam esse tipo de controle de qualidade) podem criar falhas de segurança usando a resposta atualmente aceita.
Bozzy

Respostas:

34

Pode estar na expressão regular que você está usando -

location ~ ^/phpmyadmin/(.*)$

O item acima corresponderá a / phpmyadmin /, / phpmyadmin / qualquer outra coisa / aqui / aqui, mas não corresponderá a / phpmyadmin porque a expressão regular inclui a barra final.

Você provavelmente quer algo assim:

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

O ponto de interrogação é um quantificador de expressão regular e deve dizer ao nginx para corresponder a zero ou a um dos caracteres anteriores (a barra).

Aviso: a comunidade viu esta solução, como é, como um possível risco de segurança

haymaker
fonte
Obrigado! E obrigado pela explicação também. Será útil no futuro.
Rob
15
O padrão não está correto. Também pode corresponder a um caminho como "/ phpmyadmin1234", obviamente não é isso que você deseja. A solução do @ kbec é a certa.
Miau
3
Sinto muito por votar explicitamente isso, mas o comentário do @Meow é muito importante para negligenciar. Isso pode levar a um servidor da Web configurado incorretamente, que pode conter falhas de segurança.
Daniel F
34

A melhor solução:

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

Verifique se o servidor tem permissões para /home/phpmyadminprimeiro.


Explicação da diferença com resposta aceita:

É tudo sobre expressões regulares .

Primeiro de tudo, o ^caractere significa que você deseja corresponder do início da string e não em algum lugar no meio. O $no final significa corresponder ao final da string.

O grupo (?:)significa não capturar - não queremos isso nos resultados da captura, mas queremos agrupar alguns caracteres. Nós o agrupamos assim, porque queremos que o /caractere seja uma parte não significativa do caminho filho e não uma parte significativa do caminho pai.

kbec
fonte
Porque é melhor?
Meekohi
2
@Meow respondeu isso em resposta aceita
kbec
2
Esta deve ser a resposta aceita
Yonn Trimoreau
@Meekohi eu escrevi explicação
kbec 4/18
8

Por que você não usaria

location /phpmyadmin {
    alias /home/phpmyadmin;
}

?

mulher
fonte
Porque isso não estava funcionando para mim. Veja aqui: serverfault.com/questions/375602/…
Rob
1
@Rob Você tentou sem a barra na aliasdiretiva?
Shane Madden
Esta é realmente a resposta correta e a maneira correta de fazê-lo. Simplesmente exclua a barra final e ela funciona para os URLs digitados com e sem a barra final. Não há necessidade de complicar nada no Nginx, mantenha-o simples, regex complicado e outras coisas engraçadas apenas tornarão o Nginx lento.
MitchellK
4
O problema com isso é que ele também corresponderá a /phpmyadminblahblahblahblahqualquer combinação
Gary Green
6

Sei que essa é uma pergunta antiga, mas para quem acaba aqui pelo Google, resolvi da seguinte maneira (variação da pergunta do @ kbec, que foi muito boa):

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

Isso capturará qualquer variação /fooe a redirecionará para /baroutro URL (incluindo parâmetros). Estou mostrando isso com uma proxy_passdiretiva, mas também funcionaria alias.

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

Funciona porque $1, opcionalmente, capturará os sub-recursos mais a barra principal, portanto não capturará coisas do tipo /fooextra/. Ele também redirecionará uma barra final presente ou não presente adequadamente.

dlouzan
fonte
1
Obrigado por considerar o caso de querer usar proxy_pass e, assim, se preocupar com os argumentos. Você tem o meu voto.
Daniel F
2

Esse redirecionamento reescreverá URLs apenas com e sem a barra final. Tudo o que vier após a barra não será substituído.

domain.com/location => redirecionado para domain.com/new/location
domain.com/location => redirecionado para domain.com/new/location
domain.com/location/other => não redirecionado

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

Você já tentou usar a try_filesdiretiva?

try_files $uri $uri/ =404;
Prasanth
fonte
0

Eu fiz assim

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

Por que não colocar duas reescritas simplesmente:

location ~ ^/phpmyadmin
{
    rewrite /phpmyadmin /home/phpmyadmin/ break;
    rewrite /phpmyadmin/(.*) /home/phpmyadmin/$1 break;
}
千 木 郷
fonte