Redireccionamiento de Nginx a través de Proxy, reescribir y preservar URL

71

En Nginx hemos estado intentando redirigir una URL de la siguiente manera:

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

donde el usuario todavía ve la URL original en su navegador. Una vez que se redirige al usuario, digamos que hace clic en el enlace /section/index.html, nos gustaría que esto haga una solicitud que conduzca a la redirección

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

y nuevamente conserva la URL original.

Nuestros intentos han involucrado varias soluciones usando proxies y reglas de reescritura, y a continuación se muestra la configuración que nos ha acercado más a una solución (tenga en cuenta que esta es la configuración del servidor web para el example.comservidor web). Sin embargo, todavía hay dos problemas con esto:

  • No realiza la reescritura correctamente, ya que la URL de solicitud recibida por el servidor web http://192.168.1.24incluye /some/pathy, por lo tanto, no sirve la página requerida.
  • Cuando pasa el cursor sobre un enlace una vez que se ha publicado una página, /some/pathfalta en la 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 buscando una solución que solo implique cambiar la configuración del servidor web example.com. Podemos cambiar la configuración en 192.168.1.24(también Nginx), sin embargo, queremos intentar evitar esto porque tendremos que repetir esta configuración para cientos de servidores diferentes cuyo acceso se realiza mediante proxy example.com.

robjohncox
fuente

Respuestas:

59

Primero, no debes usar rootdirectivas dentro del bloque de ubicación, es una mala práctica. Sin embargo, en este caso no importa.

Intente agregar un segundo bloque de ubicación:

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

Esto captura la parte después de / some / path / y before index.html en una variable $ section, que luego se usa para establecer el destino proxy_pass. Puede hacer que la expresión regular sea más específica si lo requiere.

Tero Kilkanen
fuente
1
Disculpas por la respuesta tardía: esto está muy cerca de lograr lo que estamos buscando. El único inconveniente es que, una vez que se ha servido la página de destino, las URL de los enlaces en el navegador no incluyen '/ some / path /' en ellas, lo que significa que no funcionan si un usuario hace clic en ellas. Si podemos averiguar cómo superar esto, actualizaré y aceptaré esta respuesta, ya que está casi allí.
robjohncox
8
Los enlaces que ve el navegador son generados por el software que se ejecuta en el servidor 192.168.1.24. Debe modificar ese software para lograr lo que desea.
Tero Kilkanen
No estoy seguro de seguir su advertencia sobre la raíz dentro del bloque de ubicación. leer la documentación de nginx es la forma correcta de hacer cosas. solo advierten sobre las malas prácticas de no tener una raíz predeterminada fuera de todas las ubicaciones. nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/…
guy mograbi
Bueno, es más fácil tener una regla general para no usar rootdentro de un locationbloque, entonces no obtendrá ningún comportamiento inesperado para las ubicaciones predeterminadas. Solo si necesita cambiar el valor predeterminado rootpara cada ubicación, puede usarlo.
Tero Kilkanen
1
¿Qué quieres decir con recibir el host $ como nombre ? ¿Cuál es el encabezado HTTP exacto que se envió y qué desea que se envíe exactamente?
Tero Kilkanen
65

Debe usar la parte URI en la proxy_passdirectiva. Además, mezcló argumentos de orden de proxy_redirectdirectivas, y probablemente no lo necesite en absoluto. Nginx tiene un valor predeterminado razonable para esta directiva.

En este caso, su locationbloqueo podría ser realmente simple:

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # note this slash  -----------^
    proxy_set_header Host $host;
}
Alexey Ten
fuente
1
Disculpas por la respuesta tardía: probé esto y desafortunadamente no funciona para nuestro caso de uso. El problema es que, cuando la solicitud se realiza en el servidor de destino, la /some/path/parte de la URL se conserva en la solicitud que no es una URL válida (también necesitamos reescribir la URL para eliminarla).
robjohncox
@robjohncox, ¿qué intentaste exactamente?
Alexey Ten
10
El corte me sirvió. Ahora mydomain.com/some/path/* se representa correctamente a 192.168.1.24/* y no 192.168.1.24/some/path/*
Vadimo
8
¿Puedo votar el comentario "# note this slash" en esta respuesta? ¡Tres hurras por ese comentario!
8one6
No estoy seguro de cómo funciona esto para todos ustedes. Esto es lo que estoy tratando de lograr. Sin embargo, cuando un usuario hace clic en un enlace que redirigiría, por ejemplo, a 192.168.1.24/login en el servicio local, se lo redirige a mydomain.com/login en lugar de mydomain.com/some/path/login
mueslo
4

Puede usar la siguiente configuración para tener una asignación 100% perfecta entre /some/path/el front-end y /el back-end.

Tenga en cuenta que esta es la única respuesta hasta ahora que también se encargaría sin problemas de las rutas absolutas que generan 404 Not Founderrores, siempre que Refererel navegador envíe el encabezado HTTP correcto , por lo que todos esos gifs deben continuar cargándose sin necesidad de modificar el HTML subyacente (que no solo es costoso, sino que tampoco es compatible sin módulos adicionales no compilados de forma predeterminada).

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

Puede encontrar la prueba de concepto completa y el producto mínimamente viable en el repositorio https://github.com/cnst/StackOverflow.cnst.nginx.conf .

Aquí hay una prueba para confirmar que todos los casos límite parecen 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

PD: si tiene muchas rutas diferentes para mapear, en lugar de hacer una comparación de expresiones regulares $http_refererdentro de un ifinterior location @404, es posible que desee utilizar la mapdirectiva basada en global en su lugar.

También tenga en cuenta que las barras diagonales finales tanto en el proxy_passcomo en el locationque está contenido son bastante importantes según una respuesta relacionada .

Referencias

cnst
fuente
2

Cuando esa barra se agrega a un jenkins proxy nginx, aparece el error "Parece que su configuración de proxy inverso está rota".

proxy_pass          http://localhost:8080/;

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

Debería leer

proxy_pass          http://localhost:8080;
tomdunn
fuente
No creo que esto sea con lo que se relacionó la pregunta del OP ni resuelva ninguno de los problemas mencionados.
Cory Robinson