Cómo eliminar la ruta con un nginx proxy_pass

77

Tengo una aplicación web en ejecución en http://example.com/, y quiero "montar" otra aplicación, en un servidor separado http://example.com/en. Servidores ascendentes y proxy_passparecen funcionar, pero por un 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;
  }
}

Al abrir example.com/en, vuelve mi aplicación aguas arriba 404 not found /en. Esto tiene sentido, ya que el río arriba no tiene el camino /en.

¿Es proxy_pathla solución correcta? ¿Debo reescribir "aguas arriba" para que escuche en su /enlugar, como ruta raíz? ¿O hay una directiva que me permite reescribir la ruta que se pasa a la parte superior?

Berkes
fuente

Respuestas:

134

Esta es probablemente la forma más eficiente de hacer lo que quiere, sin el uso de expresiones regulares:

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}
cnst
fuente
1
Hasta donde yo sé, la última parte aún pasaría "/ en" como camino hacia el proxy, ¿no?
Berkes
15
@berkes, no, no lo hará: la barra diagonal proxy_passes lo que marca la diferencia. Además, esta respuesta es más correcta que la que se le ocurrió, ya que también garantiza que proxy_redirectpermanezca defaultasí, por lo que aún puede usar 302et al en su back-end y hacer que funcione correctamente en todas partes.
cnst
44
Ah, me faltaba la barra diagonal :(
Vanuan
3
AAARGH! BARRA DIAGONAL !
barrymac
44
3 horas de búsqueda, y sí ... Fue el corte final. ¡Gracias amigo!
Lucas P.
12

Me gustaría abordar una nueva respuesta basada en expresiones regulares que ha ido aumentando en popularidad.

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

La solución puede parecer más linda a primera vista, pero está mal por varias razones.

  • La expresión regular anterior coincidiría con una solicitud uri de /enjoy, redirigiéndola a /joyupstream. ¿Es esto realmente intencionado?

  • Una solicitud de /enno dará lugar a ninguna redirección, y servirá directamente a un servidor /ascendente (casi como si se hubiera realizado una solicitud /en/, pero no del todo). Si usa URI relativos dentro de su página raíz en sentido ascendente (de lo contrario, ¿por qué no tendría el /en/prefijo allí dentro de los URI en sentido ascendente?), Por ejemplo src="style.css"(que podría hacer referencia a un idioma específico url("menu.png"), por ejemplo), entonces el navegador solicitará que como /style.csslugar de /en/style.css. (O incluso si usa URI absolutos en todas partes, ¿qué pasa si alguien hace referencia a un recurso semi-opcional oscuro relativamente?) Vaya, de repente el sitio puede no funcionar, pero solo a veces o en casos extremos.

  • Según mi consejo anterior en otra pregunta ya mencionada por la propia respuesta del OP , el uso de expresiones regulares evita que la proxy_redirectdirectiva tenga el valor predeterminado de default, convirtiéndola en su offlugar. Esto significa que si el upstream responde Location: http://127.0.0.1:8080/en/dir/cuando se realiza una solicitud /en/dir, entonces eso es lo que verá el cliente, que obviamente no funcionará correctamente. (Lo que habría sido especialmente irónico para una /ensolicitud que solicita el uso de expresiones regulares en primer lugar, sin embargo, esta implementación específica sufre otro problema como ya se mencionó anteriormente). Además, si ya está utilizando elupstreamdirectiva, entonces podría volverse más feo si solo trata de elegir uno personalizado, especialmente si puede tener más de un servidor en sentido ascendente. ¿Cómo tiene un servidor separado proxy_redirectpara cada uno de ellos? También podría usar expresiones regulares dentro proxy_redirect, tal vez incluso para que coincida con cualquier host, pero ¿y si decide dar una redirección de dominio cruzado en el futuro?

Para tratar de abordar algunos de los puntos anteriores con una única ubicación basada en expresiones regulares, podríamos hacer lo siguiente (tenga en cuenta que proxy_passtambién tuvimos que eliminar la referencia a un servidor desde una upstreamdirectiva basada en, para hacer proxy_redirectmás sencillo):

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

Entonces, si me preguntas, la solución original con las dos ubicaciones de nivel superior para hermanos aún sería una mejor idea que cavarte en una madriguera de conejos siguiendo la ruta de expresiones regulares.

cnst
fuente
Esto causa una excepción:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan
1
@Athlan, ¡eso es porque realmente no deberías estar usando eso en primer lugar! Si aún así lo desea, puede colocar esa ubicación fuera de la expresión regular.
cnst
poner localation = / en fuera funciona realmente bien! gracias
Sebastian Webber
7

Entonces, encontré la respuesta en 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;
  }
}

Básicamente: pasar una expresión regular a la ubicación y pasar la referencia a la URL proxy_pass.

Berkes
fuente
Creo que "proxy_pass luscious / $ ;" debería ser "proxy_pass luscious / $ 2 "
Zafer
1
@Zafer tiene razón, la respuesta anterior me estaba dando un error
franck,
He cambiado la respuesta, pero no tengo un servidor a mano donde pueda probar esto, ATM, por lo que no está verificado.
Berkes
0

Contabilidad para documentos Nginx

Para pasar una solicitud a un servidor proxy HTTP, la directiva proxy_pass se especifica dentro de una ubicación. Por ejemplo:

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

Este ejemplo de configuración hace que todas las solicitudes procesadas en esta ubicación pasen al servidor proxy en la dirección especificada. Esta dirección se puede especificar como un nombre de dominio o una dirección IP. La dirección también puede incluir un puerto:

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

Tenga en cuenta que en el primer ejemplo anterior, la dirección del servidor proxy va seguida de un URI, / link /. Si el URI se especifica junto con la dirección, reemplaza la parte del URI de solicitud que coincide con el parámetro de ubicación. Por ejemplo, aquí la solicitud con el /some/path/page.html URI se enviará a http://www.example.com/link/page.html . Si la dirección se especifica sin un URI, o no es posible determinar la parte del URI que se va a reemplazar, se pasa el URI de solicitud completo (posiblemente, modificado).

Jeff
fuente