89 votes

Redirection Nginx via Proxy, Réécrire et Préserver l'URL

Dans Nginx, nous avons essayé de rediriger une URL comme suit :

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

où l'utilisateur voit toujours l'URL d'origine dans son navigateur. Une fois que l'utilisateur est redirigé, s'il clique sur le lien /section/index.html, nous voudrions que cela fasse une demande qui mène à la redirection

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

et encore une fois préserver l'URL d'origine.

Nos tentatives ont impliqué diverses solutions utilisant des proxies et des règles de réécriture, et ci-dessous montre la configuration qui nous a le plus rapproché d'une solution (notez qu'il s'agit de la configuration du serveur web pour le serveur web example.com). Cependant, il reste deux problèmes avec ceci :

  • Cela ne réécrit pas correctement, en ce sens que l'URL de demande reçue par le serveur web http://192.168.1.24 inclut /some/path et échoue donc à servir la page requise.
  • Lorsque vous survolez un lien une fois qu'une page a été servie, /some/path est absent de l'URL

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

Nous recherchons une solution qui ne consiste qu'à modifier la configuration du serveur web sur example.com. Nous pouvons modifier la configuration sur 192.168.1.24 (également Nginx), cependant nous voulons essayer d'éviter cela car nous devrons répéter cette configuration pour des centaines de serveurs différents dont l'accès est proxifié via example.com.

81voto

Alexey Ten Points 7572

Vous devriez utiliser la partie URI dans la directive proxy_pass. De plus, vous avez inversé l'ordre des arguments de la directive proxy_redirect, et probablement vous n'en avez pas besoin du tout. Nginx a une valeur par défaut raisonnable pour cette directive.

Dans ce cas, votre bloc location pourrait être très simple :

location /some/path/ {
    proxy_pass http://192.168.1.24/;
    # notez ce slash ---------^
    proxy_set_header Host $host;
}

1 votes

Désolé pour la réponse tardive - J'ai essayé cela, mais malheureusement cela ne fonctionne pas pour notre cas d'utilisation. Le problème est que, lors de la demande envoyée au serveur cible, la partie /some/path/ de l'URL est conservée dans la demande, ce qui n'est pas une URL valide (nous devons aussi réécrire l'URL pour supprimer cela).

0 votes

@robjohncox qu'as-tu exactement essayé?

11 votes

Le slash a fait l’affaire pour moi. Maintenant, mondomaine.com/some/path/* est correctement proxyé vers 192.168.1.24/* et non pas 192.168.1.24/some/path/*

68voto

Tero Kilkanen Points 32968

Tout d'abord, vous ne devriez pas utiliser la directive root à l'intérieur du bloc location, c'est une mauvaise pratique. Dans ce cas, cependant, cela n'a pas d'importance.

Essayez d'ajouter un deuxième bloc location :

location ~ /some/path/(?

Cela capture la partie après /some/path/ et avant index.html dans une variable $section, qui est ensuite utilisée pour définir la destination proxy_pass. Vous pouvez rendre l'expression régulière plus spécifique si nécessaire.

1 votes

Désolé pour la réponse tardive - c'est tellement proche de ce que nous recherchons. Le seul inconvénient est que, une fois que la page cible a été servie, les URL des liens dans le navigateur n'incluent pas '/some/path/' dedans, ce qui signifie qu'ils ne fonctionnent pas si un utilisateur clique dessus. Si nous pouvons trouver comment surmonter cela, je mettrai à jour et accepterai cette réponse, car elle est presque là.

9 votes

Les liens que voit le navigateur sont générés par le logiciel qui s'exécute sur le serveur 192.168.1.24. Vous devez modifier ce logiciel afin d'obtenir ce que vous voulez.

1 votes

Pas sûr de suivre votre avertissement à propos de root à l'intérieur du bloc location. En lisant la documentation de nginx, c'est la bonne façon de faire les choses. Ils ne font que mettre en garde contre la mauvaise pratique de ne pas avoir d'élément root par défaut en dehors de toutes les localisations. nginx.com/resources/wiki/start/topics/tutorials/config_pitfa‌​lls/…

6voto

cnst Points 12508

Vous pouvez utiliser la configuration suivante pour avoir une correspondance 100% transparente entre /some/path/ côté client et / côté serveur.

Notez que c'est la seule réponse jusqu'à présent qui traiterait également automatiquement les chemins absolus générant des erreurs 404 Not Found, à condition que l'en-tête HTTP Referer correct soit envoyé par le navigateur, donc, tous ces gifs devraient continuer à se charger sans avoir besoin de modifier le HTML sous-jacent (ce qui est non seulement coûteux, mais n'est pas non plus pris en charge sans modules supplémentaires non compilés par défaut).

location /some/path/ {
    proxy_pass http://192.168.1.24/; # notez le slash final !
}
location / {
    error_page 404 = @404;
    return 404; # normalement, cela serait d'abord `try_files`
}
location @404 {
    add_header Vary Referer; # malheureusement, pas d'effet sur le 404
    if ($http_referer ~ ://[^/]*(/some/path|/the/other)/) {
        return 302 $1$uri;
    }
    return 404 "Not Found\n";
}

Vous pouvez trouver la preuve de concept complète et le produit minimal viable dans le référentiel https://github.com/cnst/StackOverflow.cnst.nginx.conf.

Voici un test pour confirmer que tous les cas limites semblent fonctionner:

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

P.S. Si vous avez beaucoup de chemins différents à mapper, au lieu de faire une comparaison regex de $http_referer dans un if dans location @404, vous voudrez peut-être utiliser la directive map basée sur le contexte global à la place.

Remarquez également que les slashes finaux dans à la fois le proxy_pass, ainsi que le location dans lequel il est contenu, sont assez importants selon une réponse connexe.

Références:

0 votes

Qu'est-ce que | & et comment cela fonctionne-t-il?

2voto

tomdunn Points 21

Lorsque cette barre oblique est ajoutée à un jenkins proxifié par nginx, vous êtes présenté avec l'erreur "Il semble que votre configuration de reverse proxy est incorrecte".

proxy_pass          http://localhost:8080/;

Retirez ceci -----------------------------^

Il devrait être lu

proxy_pass          http://localhost:8080;

1 votes

Je ne pense pas que cela soit lié à la question de l'OP ni que cela résolve l'un des problèmes mentionnés.

1voto

adospace Points 171

Nous pouvons simplifier la réponse de cnst à cela :

server {
    listen          80;
    server_name     www.example.com;

    location /some/path/ {
        # Comme expliqué dans les autres réponses, c'est suffisant pour que nginx
        # réécrive les URLs des requêtes.
        proxy_pass http://192.168.1.24/;
    }

    location / {
        # Rediriger les liens, expliqué ci-dessous
        if ($http_referer ~ ^http://www\.example\.com/some/path) {
            return 302 /some/path/$request_uri;
        }

        index index.html;
        root  /var/www/example.com/htdocs;
    }
}

Le problème avec le reverse proxy d'un serveur web ignorant (192.168.1.24) vers un sous-chemin (/some/path/) est que nginx renvoie généralement tous les contenus de réponse du serveur reverse proxy sans les modifier, ce qui inclut souvent des URLs absolus comme /index.html. Quand un navigateur visite /some/path/, cet exemple d'URL pointerait alors vers http://www.example.com/index.html, mais la ressource n'est disponible qu'à http://www.example.com/some/path/index.html !

Cependant, il existe une solution : L'en-tête "Referer" est envoyé par le navigateur pour indiquer au serveur d'où vient l'utilisateur. En le faisant correspondre avec notre "URL proxy", nous pouvons rediriger toutes les requêtes faites depuis /some/path/ vers la bonne URL.

if ($http_referer ~ ^http://www\.example\.com/some/path) {

~ est l'opérateur regex sensible à la casse, et comme nous utilisons regex ici, nous devons échapper les points avec \. Le caractère ^ au début de l'URL signifie que la chaîne doit commencer par l'expression qu'il précède.

return 302 /some/path/$request_uri;

HTTP 302 signifie "Trouvé" (à l'origine "Temporairement déplacé"). Cela dit au navigateur : "Hé, j'ai trouvé ce que vous avez demandé, mais c'est en réalité à /some/path/[...]." Le navigateur effectue ensuite la requête vers la bonne URL.

Évidemment, cette solution suppose et nécessite que le serveur web à 192.168.1.24 ne connaisse rien du reverse proxy et ne préfixe /some/path/ à ses liens. Sinon, la partie de redirection n'est pas nécessaire. Ces liens pourraient ressembler à ceci : /abc, qui serait alors redirigé par nginx vers /some/path/abc, si l'en-tête Referer est défini sur http://www.example.com/some/path.

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