Como remover o caminho com um proxy_pass nginx

77

Eu tenho um aplicativo da Web em execução http://example.com/e quero "montar" outro aplicativo, em um servidor separado http://example.com/en. Servidores upstream e proxy_passparecem funcionar, mas com um problema:

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location /en {
    proxy_pass http://luscious;
  }
}

Ao abrir example.com/en, meu aplicativo upstream retorna 404 not found /en. Isso faz sentido, pois o rio acima não tem o caminho /en.

É proxy_patha solução certa? Devo reescrever "upstream" para que ele ouça /en, como caminho raiz? Ou existe uma diretiva que me permita reescrever o caminho passado para o upstream?

berkes
fonte

Respostas:

134

Essa é provavelmente a maneira mais eficiente de fazer o que você deseja, sem o uso de expressões regulares:

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}
cnst
fonte
1
Até onde eu sei, a última parte ainda passaria "/ en" como caminho para o proxy, não?
Berkes
15
@berkes, não, não vai - a barra final proxy_passé o que faz a diferença. Além disso, essa resposta é mais correta do que a que você encontrou, porque também garante que proxy_redirectpermaneça em default, portanto, você ainda pode usar 302et al em seu back-end e fazê-lo funcionar corretamente em qualquer lugar.
CNST
4
Ah, estava faltando a barra final :(
Vanuan 2/16
3
AAARGH! TRAILING SLASH!
Barrymac # 26/17
4
3 horas de busca, e sim ... Era a barra final. Obrigado companheiro!
Lucas P.
12

Gostaria de abordar uma resposta mais recente baseada em regex que está crescendo em popularidade.

location ~ ^/en(/?)(.*)$ {  # OOPS!
  proxy_pass http://luscious/$2$is_args$args;  # OOPS!
}

A solução pode parecer mais atraente à primeira vista, mas está errada por vários motivos.

  • O regex acima corresponderia a uma solicitação de uri /enjoy, redirecionando-a para o /joyupstream. Isso é realmente pretendido?

  • Uma solicitação para /ennão resultará em redirecionamentos, servindo diretamente a /partir do upstream (quase como se uma solicitação /en/fosse feita, mas não totalmente). Se você usar URIs relativos dentro da sua página raiz a montante (caso contrário, por que você não teria o /en/prefixo ali dentro dos URIs upstream?), Por exemplo src="style.css"(que pode fazer referência a um idioma específico url("menu.png"), por exemplo), o navegador solicitará que como em /style.cssvez de /en/style.css. (Ou mesmo se você usar URIs absolutos em todos os lugares, e se alguém fizer referência relativamente a um recurso semi-opcional obscuro?) Opa, de repente o site pode não funcionar, mas apenas às vezes ou em casos extremos.

  • Conforme meu conselho anterior em outra pergunta já mencionada pela resposta do OP , o uso de expressões regulares evita que a proxy_redirectdiretiva tenha o valor padrão de default, diminuindo-o off. Isso significa que, se o upstream responder Location: http://127.0.0.1:8080/en/dir/quando um pedido /en/dirfor feito, é isso que o cliente verá, o que obviamente não funcionará corretamente. (O que seria especialmente irônico para uma /ensolicitação que solicita o uso de regex em primeiro lugar, mas essa implementação específica sofre com outro problema, como já mencionado acima.) Além disso, se você já estiver usando oupstreamdiretiva, pode ficar ainda mais feio se você tentar usar um personalizado, especialmente se você tiver mais de um servidor upstream - como você tem um separado proxy_redirectpara cada um deles? Você também pode usar expressões regulares proxy_redirect, talvez até para corresponder a qualquer host, mas e se você decidir redirecionar vários domínios no futuro?

Para tentar abordar alguns dos pontos acima com um único local baseado em regex, poderíamos fazer o seguinte (observe que proxy_passtambém tivemos que descartar a referência a um servidor de uma upstreamdiretiva baseada em, para tornar proxy_redirectmais simples):

location ~ ^/en/?((?<=/).*)?$ {
  location = /en { return 302 /en/; }
  proxy_pass http://127.0.0.1:8080/$1$is_args$args;
  proxy_redirect http://127.0.0.1:8080/ /en/;
}

Portanto, se você me perguntar, a solução original com os dois locais de nível superior de irmãos ainda seria uma idéia melhor do que se cavar em uma toca de coelho, seguindo a rota regex.

cnst
fonte
Isso causa uma exceção:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan
1
@ Athlan, isso é porque você realmente não deveria estar usando isso em primeiro lugar! Se você ainda deseja, pode colocar esse local fora do regexp.
CNT 5/07/16
colocar localização = / pt fora funciona muito bem! graças
Sebastian Webber
7

Então, eu encontrei a resposta no stackoverflow :

upstream luscious {
 server lixxxx.members.linode.com:9001;
}

server {
  root /var/www/example.com/current/public/;
  server_name example.com;

  location ~ ^/en(/?)(.*) {
    proxy_pass http://luscious/$2;
  }
}

Basicamente: passando um regex para o local e passando o backref para o URL proxy_pass.

berkes
fonte
Eu acho que "proxy_pass gostoso / $ ;" deve ser "proxy_pass luscious / $ 2 "
Zafer
1
@Zafer é certo, a resposta acima foi me dando um erro
franck
Eu mudei a resposta, mas não tenho um servidor em mãos onde eu possa tentar isso, ATM, para que não seja verificado.
Berkes
0

Contabilidade para documentos Nginx

Para passar uma solicitação para um servidor com proxy HTTP, a diretiva proxy_pass é especificada dentro de um local. Por exemplo:

location /some/path/ {
    proxy_pass http://www.example.com/link/;
}

Esta configuração de exemplo resulta na transmissão de todos os pedidos processados ​​neste local para o servidor em proxy no endereço especificado. Este endereço pode ser especificado como um nome de domínio ou um endereço IP. O endereço também pode incluir uma porta:

location ~ \.php {
    proxy_pass http://127.0.0.1:8000;
}

Observe que no primeiro exemplo acima, o endereço do servidor proxy é seguido por um URI, / link /. Se o URI for especificado junto com o endereço, ele substituirá a parte do URI da solicitação que corresponde ao parâmetro location. Por exemplo, aqui a solicitação com o /some/path/page.html URI será enviada por proxy para http://www.example.com/link/page.html . Se o endereço for especificado sem um URI ou não for possível determinar a parte do URI a ser substituída, o URI de solicitação completo será passado (possivelmente modificado).

Jeff
fonte