94 votes

Quelle est la différence entre les variables $host, $http_host et $server_name de Nginx?

Quelle est la différence entre les trois variables Nginx $host, $http_host et $server_name ?

J'ai une règle de réécriture où je ne suis pas sûr de laquelle je devrais utiliser :

location = /vb/showthread.php {
    # /vb/showthread.php?50271-What-s-happening&p=846039
    if ($arg_p) {
        return 301 $scheme://$host/forum/index.php?posts/$arg_p/;
        }

Je cherche une réponse qui ne se contente pas de dire 'utilisez la variable ____ dans votre règle de réécriture', mais qui explique également les différences théoriques entre elles.

0 votes

J'ai réalisé plus tard que je n'avais même pas besoin de spécifier $scheme et $host... return 301 /forum/index.php?posts/$arg_p/; fonctionne très bien.

0 votes

La plupart des navigateurs fonctionnent avec des URL relatives dans les redirections, mais la norme (w3.org/Protocols/rfc2616/rfc2616-sec14.html) requiert une URL absolue dans l'en-tête Location.

101voto

Michael Hampton Points 232226

Vous devriez presque toujours utiliser $host, car c'est le seul garanti d'avoir quelque chose de sensé quel que soit le comportement de l'agent utilisateur, sauf si vous avez spécifiquement besoin des sémantiques d'une des autres variables.

La différence est expliquée dans la documentation de nginx:

  • $host contient "dans cet ordre de priorité : le nom d'hôte à partir de la ligne de requête, ou le nom d'hôte du champ d'en-tête de requête 'Host', ou le nom du serveur correspondant à une requête"
  • $http_host contient le contenu du champ d'en-tête HTTP "Host", s'il était présent dans la requête
  • $server_name contient le server_name de l'hôte virtuel qui a traité la requête, tel qu'il a été défini dans la configuration nginx. Si un server contient plusieurs server_name, seul le premier sera présent dans cette variable.

Étant donné qu'il est légal pour les agents utilisateurs d'envoyer le nom d'hôte dans la ligne de requête plutôt que dans un en-tête Host:, bien que cela soit rarement fait sauf lors de la connexion à des proxies, vous devez en tenir compte.

Vous devez également tenir compte du cas où l'agent utilisateur n'envoie pas de nom d'hôte du tout, par exemple dans les requêtes HTTP/1.0 anciennes et les logiciels mal écrits modernes. Vous pourriez le faire en les redirigeant vers un hôte virtuel générique qui ne sert à rien, si vous servez plusieurs sites web, ou si vous n'avez qu'un seul site web sur votre serveur, vous pourriez tout traiter à travers un seul hôte virtuel. Dans ce dernier cas, vous devez également en tenir compte.

Seule la variable $host tient compte de toutes les choses possibles qu'un agent utilisateur peut faire lors de la formation d'une requête HTTP.

5 votes

D'autre part, le $server_name est sécurisé lorsque le champ Host: de l'UA peut contenir un contenu arbitraire.

1 votes

Est-ce que $http_host est renommé en $hostname ? Je ne trouve pas une telle variable dans la documentation de Nginx. $hostname est celui qui lui ressemble le plus, je suppose.

4 votes

@darkbaby123 Non, il n'a pas été renommé en quoi que ce soit. Voir la documentation.

6voto

TreDubZedd Points 2070

Je voudrais ajouter un point important qui n'a pas été mentionné dans la réponse acceptée.

$ host ne possède PAS de numéro de port, alors que $ http_host inclut le numéro de port.

edit: pas toujours.

J'ai mis en place un en-tête "add_header Y-blog-http_host "$ http_host" always;"

Ensuite, curl -I -L domain.com:80 (ou 443) et l'en-tête ne montre pas de numéro de port du tout. Vérifié avec nginx-extra 1.10.3. Est-ce parce que ce sont des ports http(s) courants ou une configuration nginx? Ce commentaire juste pour dire que les choses ne se comportent pas toujours comme vous le pensez.

0 votes

Est-ce parce que ce sont des ports http(s) courants ou la configuration nginx? Oui, curl ne ajoutera pas le numéro de port commun à l'en-tête Host même si vous l'invoquez de cette manière. Cependant, il n'y a aucune garantie qu'un autre programme n'ajoutera pas ce numéro s'il est invoqué de manière similaire. Et bien sûr, vous pouvez écraser manuellement l'en-tête Host par défaut en utilisant curl -I -H 'Host: domain.com:80'...

2voto

XTL Points 189

TL;DR: Si vous n'utilisez pas d'expressions régulières dans server_name, vous pouvez ignorer cette réponse.

Comme cet aspect n'a pas du tout été mentionné dans les autres réponses, mais c'est quelque chose que j'ai trouvé un peu ennuyeux : j'utilise $host dans la création des noms de mes fichiers journaux, comme ceci :

access_log /var/log/nginx/access_$host.log

Hélas, si vous utilisez une expression régulière dans votre section server_name comme ceci :

server_name ~^(?foo|bar|baz)\.example.net;

Votre $host contiendra en fait l'expression régulière comme ceci (oui, y compris le backslash et tout le reste) :

access_~^(?foo|bar|baz)\.example.net.log

Pour ma part, j'ai trouvé cela très ennuyeux et j'ai fini par modifier mon expression régulière en :

server_name ~^(?(?foo|bar|baz)\.example.net);

pour capturer le nom complet afin de le réutiliser dans le nom du fichier journal. La section respective a alors été modifiée en :

access_log /var/log/nginx/access_$fulldomain.log

1voto

Steely Wing Points 261

$http_host

$http_host équivaut toujours au champ d'en-tête de requête Host

Host: example.org

$host

$host est dans cet ordre de prépondérance (du plus élevé au plus bas) :

  • Nom d'hôte de la ligne de requête

    GET http://example.org/test/ HTTP/1.1
  • Champ d'en-tête de requête Host

  • Le server_name (dans la configuration Nginx) correspondant à une requête, même si server_name est générique (Ex: server_name *.example.org;)

$server_name

$server_name est égal à server_name (dans la configuration Nginx), même si server_name est générique (Ex: server_name *.example.org;)

Nom d'hôte de la ligne de requête

Lorsque l'URL ouvert est http://host.name/test/ ...

La plupart des navigateurs envoient la requête de cette manière

GET /test/ HTTP/1.1
Host: host.name

La plupart des navigateurs n'envoient pas la requête de cette manière

GET http://host.name/test/ HTTP/1.1

Ref: ngx_http_core_module, Validation du $host Nginx

1voto

luison Points 273

J'ai également eu du mal avec cela pendant un certain temps. Tout est devenu clair quand j'ai compris que $http_XXXXX fait référence à toutes les variables d'en-tête déclarées.

Ainsi, $http_user_agent, $http_referer sont "USER AGENT", "REFERER" référencés en minuscules et avec un underslash. Cela m'a expliqué d'où venait $http_upgrade dans de nombreux exemples de configuration NGINX.

Lisez-le sur https://stackoverflow.com/questions/15414810/whats-the-difference-of-host-and-http-host-in-nginx

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