176 votes

Comment supprimer le chemin avec un proxy_pass nginx

J'ai une application web en cours d'exécution à http://example.com/ et je veux "monter" une autre application, sur un serveur distinct sur le site de l'entreprise. http://example.com/en . Serveurs en amont et proxy_pass semblent fonctionner, mais pour un problème :

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

Lors de l'ouverture example.com/en ma demande en amont revient 404 not found /en . Ceci est logique, car l'amont n'a pas le chemin /en .

Est proxy_path la bonne solution ? Devrais-je réécrire "upstream" pour qu'il écoute /en à la place, comme chemin racine ? Ou existe-t-il une directive qui me permette de réécrire le chemin transmis en amont ?

322voto

cnst Points 12508

C'est probablement le moyen le plus efficace de faire ce que vous voulez, sans utiliser d'expressions régulières :

location = /en {
    return 302 /en/;
}
location /en/ {
    proxy_pass http://luscious/;  # note the trailing slash here, it matters!
}

1 votes

Pour autant que je sache, la dernière partie transmettrait toujours "/en" comme chemin au proxy, non ?

24 votes

@berkes, non, ce n'est pas le cas -- la barre oblique de fin de ligne dans proxy_pass est ce qui fait la différence. De plus, cette réponse est plus correcte que celle que vous avez proposée, car elle garantit également que proxy_redirect reste à default Ainsi, vous pouvez toujours utiliser 302 et autres dans votre backend, et que cela fonctionne correctement partout.

1 votes

On dirait que ça ne marche pas. Voici ce que luscious obtiendrait : "GET /fr/ HTTP/1.0" 404 C'est à dire que c'est envoyé par proxy avec un chemin d'accès.

22voto

cnst Points 12508

J'aimerais aborder une réponse plus récente basée sur les expressions rationnelles qui gagne en popularité.

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

Cette solution peut sembler plus mignonne à première vue, mais elle est fausse pour de multiples raisons.

  • L'expression rationnelle ci-dessus correspondrait à une requête uri de /enjoy et le redirige vers /joy en amont. Est-ce vraiment voulu ?

  • Une demande de /en ne donnera lieu à aucune redirection, en servant directement une / à partir de l'amont (presque comme si une demande de /en/ a été fait à la place, mais pas tout à fait). Si vous utilisez des URI relatifs dans votre page racine en amont (sinon, pourquoi n'auriez-vous pas la balise /en/ dans les URI en amont ?), par ex. src="style.css" (qui peut faire référence à un url("menu.png") par exemple), alors le navigateur le demandera en tant que /style.css au lieu de /en/style.css . (Ou même si vous utilisez des URI absolus partout, que se passe-t-il si quelqu'un fait référence à une obscure ressource semi-optionnelle de manière relative). Oups, le site peut soudainement ne pas fonctionner, mais seulement parfois ou dans des cas limites.

  • Selon mon un conseil antérieur à une autre question déjà mentionnée par la propre réponse du PO l'utilisation d'expressions régulières permet d'éviter que le proxy_redirect d'avoir la valeur par défaut de default en le réduisant à off à la place. Cela signifie que si l'amont répond avec Location: http://127.0.0.1:8080/en/dir/ lorsqu'une demande de /en/dir est faite, alors c'est ce que le client verra, ce qui évidemment ne fonctionnera pas correctement. (Ce qui aurait été particulièrement ironique pour une /en qui incite à utiliser les regex en premier lieu, pourtant cette implémentation spécifique souffre plutôt d'un autre problème comme déjà mentionné ci-dessus). De plus, si vous utilisez déjà le upstream alors cela peut devenir très laid si vous essayez d'en utiliser une personnalisée, surtout si vous avez plus d'un serveur en amont - comment avoir une directive proxy_redirect pour chacun d'entre eux ? Vous pourriez utiliser des expressions régulières dans proxy_redirect Mais que se passera-t-il si vous décidez de donner une redirection inter-domaine à l'avenir ?

Pour essayer de répondre à certains des points ci-dessus avec une seule localisation basée sur une expression rationnelle, nous pourrions faire ce qui suit (notez qu'en proxy_pass nous avons également dû abandonner la référence à un serveur d'une upstream -pour faire en sorte que les proxy_redirect plus simple) :

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

Donc, si vous me demandez, le solution originale avec les deux emplacements de premier niveau frères et soeurs serait toujours une meilleure idée que de s'enfoncer dans un trou de lapin en empruntant la voie des regex.

1 votes

Cela provoque une exception : nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*

1 votes

@Athlan, c'est parce que vous ne devriez pas vraiment l'utiliser en premier lieu ! Si vous voulez toujours le faire, vous pouvez mettre cet emplacement en dehors de la regexp.

0 votes

Mettre la localisation = /fr à l'extérieur fonctionne très bien ! merci.

11voto

rajavijayakanth Points 21

Alors, j'ai trouvé le réponse sur 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;
  }
}

En gros, il s'agit de passer une expression rationnelle dans le champ "location" et de transmettre la référence inverse à l'url du proxy_pass.

0 votes

Je pense que "proxy_pass luscious/$ ;" devrait être "proxy_pass luscious/$2 "

1 votes

@Zafer a raison, la réponse ci-dessus me donnait une erreur

0 votes

J'ai modifié la réponse, mais je n'ai pas de serveur sous la main où je peux essayer cela, ATM, donc ce n'est pas vérifié.

6voto

Jeff Points 51

Comptabilité à Documents sur Nginx

Pour transmettre une requête à un serveur HTTP mandataire, la directive proxy_pass est spécifiée à l'intérieur d'un emplacement. Par exemple :

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

Cet exemple de configuration a pour effet de transmettre toutes les demandes traitées dans cet emplacement au serveur mandataire à l'adresse spécifiée. Cette adresse peut être spécifiée comme un nom de domaine ou une adresse IP. L'adresse peut également inclure un port :

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

Notez que dans le premier exemple ci-dessus, l'adresse du serveur mandataire est suivie d'un URI, /link/. Si l'URI est spécifié avec l'adresse, il remplace la partie de l'URI de la requête qui correspond au paramètre d'emplacement. Par exemple, ici la requête avec l'URI /some/path/page.html sera proxiée vers http://www.example.com/link/page.html . Si l'adresse est spécifiée sans URI, ou s'il n'est pas possible de déterminer la partie de l'URI à remplacer, l'URI complet de la demande est transmis (éventuellement, modifié).

1 votes

Pourquoi n'est-ce pas la bonne réponse ? Elle fournit l'approche correcte en utilisant les outils intégrés de nginx au lieu de schémas regex maladroits.

0voto

kabadisha Points 161

J'ai essayé la solution acceptée ci-dessus, mais j'ai constaté qu'elle provoquait des redirections douteuses pour toutes les ressources CSS et JS. Finalement, je me suis inspiré de la façon dont les configurations Nginx de LinuxServer SWAG sont réalisées. Vous pouvez les trouver aquí . Jetez un coup d'œil à pihole.subfolder.conf.sample .

En conséquence, ma solution ressemble à ceci :

location /en {
    return 302 $scheme://$host/en/;
}

location ^~ /en/ {
    set $upstream_app lixxxx.members.linode.com;
    set $upstream_port 9001;
    set $upstream_proto http;
    proxy_pass $upstream_proto://$upstream_app:$upstream_port;

    rewrite /en(.*) $1 break;
}

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X