Comment supprimer le chemin avec un nginx proxy_pass

77

J'ai une application Web en cours d'exécution sur http://example.com/et souhaite "monter" une autre application sur un serveur distinct http://example.com/en. Les serveurs en amont et proxy_passsemblent 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, mon application en amont revient 404 not found /en. Cela a du sens, car l’amont n’a pas le chemin /en.

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

Berkes
la source

Réponses:

134

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!
}
cnst
la source
1
Autant que je sache, la dernière partie transmettrait toujours "/ en" comme chemin d'accès au proxy, non?
Berkes
15
@berkes, non, ce ne sera pas le cas - le slash final proxy_passest ce qui fait la différence. En outre, cette réponse est plus correcte que celle que vous avez suggérée, car elle garantit également que le résultat proxy_redirectreste defaultinchangé. Vous pouvez donc toujours utiliser 302et autres dans votre backend et le faire fonctionner correctement partout.
Cnst
4
Ah, il me manquait la barre oblique suivante :(
Vanuan
3
AAARGH! SLASH DE TRAILING!
barrymac
4
3 heures de recherche, et ouais ... C'était la barre oblique. Merci mon pote!
Lucas P.
12

J'aimerais aborder une réponse plus récente basée sur les expressions rationnelles et dont la popularité augmente.

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

La solution peut sembler plus mignonne à première vue, mais elle est fausse pour plusieurs raisons.

  • La regex ci-dessus correspondrait à une requête uri of /enjoy, la redirigeant vers l' /joyamont. Est-ce vraiment destiné?

  • Une demande pour /enne donnera pas lieu à des redirections, desservant directement un en /amont (presque comme si une demande /en/était faite à la place, mais pas tout à fait). Si vous utilisez des URI relatifs dans votre page racine en amont (sinon, pourquoi n'auriez-vous pas le /en/préfixe directement dans les URI en amont?), Par exemple src="style.css"(qui pourrait faire référence à une langue spécifique url("menu.png"), par exemple), le navigateur demandera alors à ce que comme /style.cssau lieu de /en/style.css. (Ou même si vous utilisez des URI absolus partout, que se passera-t-il si une personne fait référence à une ressource semi-facultative obscure?) Oups, le site risque de ne pas fonctionner, mais seulement dans certains cas ou dans des cas extrêmes.

  • Comme je l' avais déjà dit à propos d'une autre question déjà mentionnée dans la propre réponse du PO , l'utilisation d'expressions régulières empêche la proxy_redirectdirective d'avoir la valeur par défaut default, mais de la baisser off. Cela signifie que si le flux amont répond Location: http://127.0.0.1:8080/en/dir/quand une demande /en/direst faite, c'est ce que le client verra, ce qui ne fonctionnera évidemment pas correctement. (Ce qui aurait été particulièrement ironique pour une /enrequête qui incite au départ à utiliser une expression rationnelle, mais cette implémentation spécifique souffre d'un autre problème, comme déjà mentionné ci-dessus.) De plus, si vous utilisez déjà leupstreamdirective, alors cela pourrait devenir très moche si vous essayez simplement d’utiliser un serveur personnalisé, surtout si vous avez plusieurs serveurs en amont - comment en avez-vous un proxy_redirectpour chacun d’eux? Vous pouvez également utiliser des expressions régulières proxy_redirect, peut-être même pour faire correspondre un hôte, mais que se passera-t-il si vous décidez de donner une redirection entre domaines à l'avenir?

Pour essayer de traiter certains des points ci-dessus avec un seul emplacement basé sur les expressions rationnelles, nous pourrions procéder comme suit (notez que proxy_passnous avons également dû supprimer la référence à un serveur d'une upstreamdirective -based, pour la rendre proxy_redirectplus 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, la solution originale avec les deux emplacements de premier niveau frères ou sœurs serait toujours une meilleure idée que de vous plonger dans un terrier de lapin en optant plutôt pour la route des regex.

cnst
la source
Cela provoque une exception:nginx: [emerg] location "/en" is outside location "^/en/?((?<=/).*
Athlan
1
@ Athlan, c'est parce que vous ne devriez pas vraiment utiliser ça en premier lieu! Si vous le souhaitez, vous pouvez placer cet emplacement en dehors de l'expression rationnelle.
cnst
mettre localiser = / en extérieur fonctionne vraiment bien! merci
Sebastian Webber
7

Donc, j'ai trouvé la 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;
  }
}

Fondamentalement: passer une expression rationnelle à l'emplacement et transmettre le backref le long de l'url proxy_pass.

Berkes
la source
Je pense "proxy_pass luscious / $ ;" devrait être "proxy_pass luscious / $ 2 "
Zafer
1
@Zafer a raison, la réponse ci-dessus me donnait une erreur
franck
J'ai changé la réponse, mais je n'ai pas de serveur sous la main où je peux essayer ceci, ATM, donc ce n'est pas vérifié.
Berkes
0

Comptabilité dans les documents Nginx

Pour transmettre une demande à un serveur proxy HTTP, la directive proxy_pass est spécifiée dans un emplacement. Par exemple:

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

Cet exemple de configuration entraîne la transmission de toutes les demandes traitées dans cet emplacement au serveur mandaté à l'adresse spécifiée. Cette adresse peut être spécifiée sous la forme d'un nom de domaine ou d'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 mandaté est suivie d'un URI, / link /. Si l'URI est spécifié avec l'adresse, il remplace la partie de l'URI de la demande qui correspond au paramètre location. Par exemple, ici la requête avec l'URI /some/path/page.html sera envoyée par proxy à http://www.example.com/link/page.html . Si l'adresse est spécifiée sans adresse URI ou s'il est impossible de déterminer la partie de l'URI à remplacer, l'adresse URI de requête complète est transmise (éventuellement modifiée).

Jeff
la source