Redirecionamento Nginx via proxy, reescrever e preservar URL

71

No Nginx, tentamos redirecionar um URL da seguinte maneira:

http://example.com/some/path -> http://192.168.1.24

onde o usuário ainda vê o URL original no navegador. Depois que o usuário é redirecionado, digamos que ele clica no link /section/index.html, gostaríamos de fazer uma solicitação que leve ao redirecionamento

http://example.com/some/path/section/index.html -> http://192.168.1.24/section/index.html

e novamente preservar o URL original.

Nossas tentativas envolveram várias soluções usando proxies e regras de reescrita, e abaixo mostra a configuração que nos aproximou de uma solução (observe que esta é a configuração do servidor da example.comweb para o servidor da web). No entanto, ainda existem dois problemas com isso:

  • Ele não executa a reescrita corretamente, na medida em que a URL de solicitação recebida pelo servidor da Web http://192.168.1.24inclui /some/pathe, portanto, falha ao veicular a página necessária.
  • Quando você passa o mouse em um link depois que uma página é veiculada, /some/pathfalta o URL

    server {
        listen          80;
        server_name     www.example.com;
    
        location /some/path/ {
            proxy_pass http://192.168.1.24;
            proxy_redirect http://www.example.com/some/path http://192.168.1.24;
            proxy_set_header Host $host;
        }
    
        location / {
            index index.html;
            root  /var/www/example.com/htdocs;
        }
    }
    

Estamos procurando uma solução que envolva apenas a alteração da configuração do servidor da web example.com. Podemos alterar a configuração 192.168.1.24(também Nginx), no entanto, queremos tentar evitar isso porque precisaremos repetir essa configuração para centenas de servidores diferentes cujo acesso é feito através de proxy example.com.

robjohncox
fonte

Respostas:

59

Primeiro, você não deve usar a rootdiretiva dentro do bloco de localização, é uma prática ruim. Nesse caso, não importa.

Tente adicionar um segundo bloco de localização:

location ~ /some/path/(?<section>.+)/index.html {
    proxy_pass http://192.168.1.24/$section/index.html;
    proxy_set_header Host $host;
}

Isso captura a parte após / some / path / e before index.html em uma variável de seção $, que é usada para definir o destino proxy_pass. Você pode tornar a regex mais específica, se necessário.

Tero Kilkanen
fonte
11
Desculpas pela resposta tardia - isso está muito próximo de alcançar o que estamos procurando. A única falha é que, depois que a página de destino é veiculada, os URLs dos links no navegador não incluem '/ some / path /' neles, o que significa que eles não funcionam se um usuário clicar neles. Se conseguirmos descobrir como superar isso, atualizarei e aceitarei esta resposta, pois ela está quase lá.
robjohncox
8
Os links que o navegador vê são gerados pelo software que está sendo executado no servidor 192.168.1.24. Você deve modificar esse software para conseguir o que deseja.
Tero Kilkanen
Não tenho certeza se sigo seu aviso sobre raiz dentro do bloco de localização. lendo a documentação do nginx, é o caminho certo para fazer as coisas. eles apenas alertam as práticas inadequadas de não terem uma raiz padrão fora de todos os locais. nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/...
cara Mograbi
Bem, é mais fácil ter uma regra de ouro para não usar rootdentro de um locationbloco, então você não terá nenhum comportamento inesperado nos locais padrão. Somente se você precisar alterar o padrão rootpara cada local, poderá usá-lo.
Tero Kilkanen 19/01
11
O que você quer dizer com recebe o host $ como nome ? Qual é o cabeçalho HTTP exato que foi enviado e o que exatamente você deseja que ele envie?
Tero Kilkanen
65

Você deve usar a parte URI na proxy_passdiretiva. Além disso, você misturou argumentos de ordem de proxy_redirectdiretiva e provavelmente não precisa disso. O Nginx possui um padrão razoável para esta diretiva.

Nesse caso, seu locationbloco pode ser realmente simples:

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # note this slash  -----------^
    proxy_set_header Host $host;
}
Alexey Ten
fonte
11
Desculpas pela resposta tardia - tentei isso e infelizmente não funciona no nosso caso de uso. O problema é que, quando a solicitação é feita no servidor de destino, a /some/path/parte da URL é preservada na solicitação que não é uma URL válida (precisamos reescrever a URL também para removê-la).
precisa saber é o seguinte
@robjohncox o que exatamente você tentou?
Alexey Ten
9
a barra fez o truque para mim. Agora mydomain.com/some/path/* está com proxy corretamente para 192.168.1.24/* e não para 192.168.1.24/some/path/*
Vadimo
7
Posso fazer um voto positivo no comentário "# note this slash" nesta resposta? Três aplausos por esse comentário!
usar o seguinte comando
Não tenho certeza de como isso está funcionando para todos vocês. É isso que estou tentando alcançar. No entanto, quando um usuário clica em um link que redirecionaria, por exemplo, para 192.168.1.24/login no serviço local, ele é redirecionado para mydomain.com/login em vez de mydomain.com/login/some/path/login
mueslo
4

Você pode usar a seguinte configuração para ter um mapeamento 100% contínuo entre /some/path/o front-end e /o back-end.

Observe que esta é a única resposta até o momento que também cuidaria perfeitamente de caminhos absolutos que geram 404 Not Founderros, desde que o Referercabeçalho HTTP correto seja enviado pelo navegador. Portanto, todos esses gifs devem continuar carregando sem a necessidade de modificar o HTML subjacente (que não é apenas caro, mas também não é suportado sem módulos adicionais não compilados por padrão).

location /some/path/ {
    proxy_pass http://192.168.1.24/; # note the trailing slash!
}
location / {
    error_page 404 = @404;
    return 404; # this would normally be `try_files` first
}
location @404 {
    add_header Vary Referer; # sadly, no effect on 404
    if ($http_referer ~ ://[^/]*(/some/path|/the/other)/) {
        return 302 $1$uri;
    }
    return 404 "Not Found\n";
}

Você pode encontrar a prova de conceito completa e o produto mínimo viável no repositório https://github.com/cnst/StackOverflow.cnst.nginx.conf .

Aqui está uma execução de teste para confirmar que todos os casos extremos parecem funcionar:

curl -v -H 'Referer: http://example.su/some/path/page.html' localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
> Referer: http://example.su/some/path/page.html
< HTTP/1.1 302 Moved Temporarily
< Location: http://localhost:6586/some/path/and/more.gif
< Vary: Referer

curl -v localhost:6586/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location
> GET /and/more.gif HTTP/1.1
< HTTP/1.1 404 Not Found

curl -v localhost:6586/some/path/and/more.gif | & fgrep -e HTTP/ -e Referer -e Location -e uri
> GET /some/path/and/more.gif HTTP/1.1
< HTTP/1.1 200 OK
request_uri:    /and/more.gif

PS Se você tiver muitos caminhos diferentes para mapear, em vez de fazer uma comparação de regex de $http_refererdentro para ifdentro location @404, convém usar a mapdiretiva baseada em global .

Observe também que as barras finais proxy_pass, tanto quanto as locationque estão contidas, são muito importantes conforme uma resposta relacionada .

Referências:

cnst
fonte
2

Quando essa barra é adicionada a um jenkins com proxy nginx, você recebe o erro "Parece que sua configuração de proxy reverso está com defeito".

proxy_pass          http://localhost:8080/;

Remove this -----------------------------^

Deve ler

proxy_pass          http://localhost:8080;
tomdunn
fonte
Acho que não acho que isso esteja relacionado à pergunta do OP nem resolve nenhum dos problemas mencionados.
Cory Robinson