web-dev-qa-db-fra.com

Redirection Nginx via Proxy, Rewrite et Preserve 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 l'utilisateur redirigé, dites qu'il clique sur le lien vers /section/index.html, nous souhaitons 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 conserver l'URL d'origine.

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

  • Il n'effectue pas la réécriture correctement, en ce que l'URL de demande reçue par le serveur Web http://192.168.1.24 comprend /some/path et ne parvient donc pas à diffuser la page requise.
  • Lorsque vous survolez un lien une fois qu'une page a été diffusée, /some/path est absent de l'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;
        }
    }
    

Nous recherchons une solution qui implique uniquement de modifier la configuration du serveur Web sur example.com. Nous pouvons changer la configuration sur 192.168.1.24 (également Nginx), mais 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 mandaté via example.com.

77
robjohncox

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

Essayez d'ajouter un deuxième bloc d'emplacement:

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

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 vous en avez besoin.

62
Tero Kilkanen

Vous devez utiliser la partie URI dans proxy_pass directive. De plus, vous avez mélangé les arguments d'ordre de proxy_redirect directive, et vous n'en avez probablement 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/;
    # note this slash  -----------^
    proxy_set_header Host $Host;
}
67
Alexey Ten

Vous pouvez utiliser la configuration suivante pour avoir un mappage 100% transparent entre /some/path/ sur le front-end et / sur le backend.

Notez que c'est la seule réponse à ce jour qui prendrait également en charge de manière transparente les chemins absolus générant 404 Not Found erreurs, à 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 cher, 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/; # 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";
}

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

Voici un test pour confirmer que tous les cas Edge 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 souhaiterez peut-être utiliser à la place la directive map globale.

Notez également que les barres obliques de fin dans le proxy_pass, ainsi que le location dans lequel il est contenu, sont très importants selon une réponse connexe .

Références:

5
cnst

Lorsque cette barre oblique est ajoutée à un jenkins proxy Nginx, vous voyez s'afficher l'erreur "Il semble que la configuration de votre proxy inverse est rompue".

proxy_pass          http://localhost:8080/;

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

Il faut lire

proxy_pass          http://localhost:8080;
2
tomdunn