Pourquoi nginx répond-il à n'importe quel nom de domaine?

139

J'ai nginx opérationnel avec une application Ruby / Sinatra et tout va bien. Cependant, j'essaye maintenant d'avoir une deuxième application fonctionnant à partir du même serveur et j'ai remarqué quelque chose de bizarre. Tout d'abord, voici mon nginx.conf:

pid /tmp/nginx.pid;
error_log /tmp/nginx.error.log;

events {
  worker_connections 1024;
  accept_mutex off;
}

http {
  default_type application/octet-stream;
  access_log /tmp/nginx.access.log combined;

  sendfile on;
  tcp_nopush on;
  tcp_nodelay off;

  gzip on;
  gzip_http_version 1.0;
  gzip_proxied any;
  gzip_min_length 500;
  gzip_disable "MSIE [1-6]\.";
  gzip_types text/plain text/xml text/css
             text/comma-separated-values
             text/javascript application/x-javascript
             application/atom+xml;

  upstream app {
    server unix:/var/www/app/tmp/sockets/unicorn.sock fail_timeout=0;
  }

  server {
    listen 80;
    client_max_body_size 4G;
    server_name FAKE.COM;

    keepalive_timeout 5;

    root /var/www/app/public;

    location / {
      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header Host $http_host;
      proxy_redirect off;

      if (!-f $request_filename) {
        proxy_pass http://app;
        break;
      }
    }

    error_page 500 502 503 504 /500.html;
    location = /500.html {
      root /var/www/app/public;
    }
  }
}
                                                          68,0-1        B

Remarquez comment server_nameest réglé sur FAKE.COMencore le serveur répond à tous les hôtes qui ont frappé ce serveur par l' intermédiaire d' autres noms de domaine. Comment puis-je faire en sorte que ce serveur particulier réponde uniquement aux demandes de FAKE.COM?

Martin
la source
la listen fake.com | something.com:80 commande filtre, non server_name.
Alexei Martchenko

Réponses:

202

Le premier bloc de serveur dans la configuration nginx est la valeur par défaut pour toutes les demandes qui atteignent le serveur pour lequel il n'y a pas de bloc de serveur spécifique.

Donc, dans votre configuration, en supposant que votre vrai domaine est REAL.COM, lorsqu'un utilisateur tape cela, il sera résolu sur votre serveur, et comme il n'y a pas de bloc de serveur pour cette configuration, le bloc de serveur pour FAKE.COM, étant le premier le bloc serveur (uniquement le bloc serveur dans votre cas), traitera cette demande.

C'est pourquoi les configurations Nginx appropriées ont un bloc de serveur spécifique pour les valeurs par défaut avant de suivre avec d'autres pour des domaines spécifiques.

# Default server
server {
    return 404;
}

server {
    server_name domain_1;
    [...]
}

server {
    server_name domain_2;
    [...]
}

etc

** ÉDITER **

Il semble que certains utilisateurs soient un peu confus par cet exemple et pensent qu'il est limité à un seul fichier de configuration, etc.

Veuillez noter que ce qui précède est un exemple simple pour le PO à développer selon les besoins.

J'utilise personnellement des fichiers de configuration vhost séparés avec ceci comme tel (CentOS / RHEL):

http {
    [...]
    # Default server
    server {
        return 404;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

/etc/nginx/conf.d/ contiendra domain_1.conf, domain_2.conf ... domain_n.conf qui sera inclus après le bloc serveur dans le fichier principal nginx.conf qui sera toujours le premier et sera toujours la valeur par défaut sauf s'il est remplacé par le default_server directive ailleurs.

L'ordre alphabétique des noms de fichiers des fichiers de configuration pour les autres serveurs devient sans importance dans ce cas.

De plus, cette disposition offre une grande flexibilité dans la mesure où il est possible de définir plusieurs valeurs par défaut.

Dans mon cas spécifique, Apache écoute sur le port 8080 sur l'interface interne uniquement et je proxy les scripts PHP et Perl vers Apache.

Cependant, je lance deux applications distinctes qui renvoient toutes les deux des liens avec ": 8080" dans le code HTML de sortie joint car ils détectent qu'Apache ne fonctionne pas sur le port standard 80 et essaient de "m'aider".

Cela provoque un problème en ce que les liens deviennent invalides car Apache ne peut pas être atteint à partir de l'interface externe et les liens doivent pointer vers le port 80.

Je résous ceci en créant un serveur par défaut pour le port 8080 pour rediriger ces demandes.

http {
    [...]
    # Default server block for undefined domains
    server {
        listen 80;
        return 404;
    }
    # Default server block to redirect Port 8080 for all domains
    server {
        listen my.external.ip.addr:8080;
        return 301 http://$host$request_uri;
    }
    # Other servers
    include /etc/nginx/conf.d/*.conf;
}

Comme rien dans les blocs de serveur normaux n'écoute sur le port 8080, le bloc de serveur par défaut de redirection traite de manière transparente de telles demandes en vertu de sa position dans nginx.conf.

J'ai en fait quatre de ces blocs de serveur et il s'agit d'un cas d'utilisation simplifié.

Dayo
la source
1
Nginx requiert le respect de la casse - «Serveur» doit être serveur et «Retour» doit être renvoyé. J'espère que cela évite quelques problèmes lors de la copie de ce code.
Capaj
2
statique, voir la réponse d'Oleg Neumyvkin - si vous avez plusieurs fichiers de configuration dans les sites disponibles, le premier serveur du premier fichier par ordre alphabétique est votre valeur par défaut. Je soupçonne que cela pourrait être un problème. De plus, de nombreuses distributions exécutent un 'nginx -t' pour tester la configuration avant de redémarrer - vous pouvez avoir une erreur empêchant un redémarrage.
jwhitlock
2
Ceci est incomplet et ne devrait pas être la réponse acceptée. Pour que cela fonctionne, vous devez également supprimer default_server de toutes les directives d'écoute.
Ben
@ben Premièrement, l'OP n'avait pas "default_server" dans son exemple de problème et la réponse est adaptée aux spécificités de cette question. Deuxièmement, pourquoi quiconque définirait default_server sur un emplacement de serveur distinct en suivant les instructions pour faire du premier serveur défini le serveur par défaut me dépasse. Dans tous les cas, si un default_server a été spécifiquement défini, alors cet ensemble de questions / réponses n'est pas ce qu'il faut examiner pour résoudre les problèmes qu'ils peuvent rencontrer.
Dayo du
1
@Dayo Vous avez raison de dire que vous avez adressé la configuration spécifique publiée par l'OP. Mais pour une réponse complète à la question posée, je pense qu'il faut mentionner le default_server. Il est très possible de lire votre réponse et de ne pas réaliser comment default_server l'interférerait. C'est encore plus probable parce que certaines distributions sont livrées avec default_server défini dans un fichier qui peut ne pas être évident pour l'utilisateur.
Ben le
62

Vous devriez avoir un serveur par défaut pour fourre-tout , vous pouvez revenir 404ou mieux ne pas répondre du tout (économisera de la bande passante) en renvoyant la 444réponse HTTP spécifique à nginx qui ferme simplement la connexion et ne renvoie rien

server {
    listen       80  default_server;
    server_name  _; # some invalid name that won't match anything
    return       444;
}
iTech
la source
A travaillé pour moi pour nginx 1.8.0. leserver_name _; je n'avais pas dans les versions précédentes pour nginx, mais cela a fonctionné. Maintenant, pour les nouvelles versions de nginx, il semble que vous ayez besoin du server_name _;. Merci
Daniel
Résolu. J'ai oublié un point-virgule; _;
user1201917
2
@iTech: Pour une raison quelconque, il renvoie 444 pour toutes les demandes. Des indices?
Divick
Un bon conseil sur le 444, et à mon avis une solution beaucoup plus propre que de renvoyer un code d'erreur.
qqilihq
1
Il est important de spécifier un certificat / clé, sinon toutes les connexions SSL correspondront et échoueront, comme indiqué par @AndreyT dans sa réponse ci-dessous.
Mark Fletcher
35

Je n'ai pas pu résoudre mon problème avec aucune des autres réponses. J'ai résolu le problème en vérifiant si l'hôte correspondait et en renvoyant un 403 si ce n'était pas le cas. (J'ai eu un site Web aléatoire pointant vers le contenu de mes serveurs Web. Je suppose que je détourne le rang de recherche)

server {
    listen 443;
    server_name example.com;

    if ($host != "example.com") {
        return 403;
    }

    ...
}
Matt Carrier
la source
1
S'il y a une mauvaise pratique: nginx.com/resources/wiki/start/topics/depth/ifisevil
Esolitos
1
Il y a des cas où vous ne pouvez tout simplement pas éviter d'utiliser un if, par exemple, si vous devez tester une variable qui n'a pas de directive équivalente.
Edward
4
@Esolitos Littéralement, la troisième ligne de cet article indique que ce cas d'utilisation est correct. Je comprends la nécessité d'être prudent, mais ne remuons pas les doigts dans des cas d'utilisation raisonnables.
mpowered le
À mon avis, la solution la plus simple et la plus concise, car elle ne nécessite que 3 lignes de code, vous pouvez volontiers coller dans n'importe quel fichier vhost, en ne changeant que le $ host comparé, par la suite.
Akito
28

Pour répondre à votre question - nginx choisit le premier serveur s'il n'y a pas de correspondance. Voir documentation :

Si sa valeur ne correspond à aucun nom de serveur, ou si la demande ne contient pas du tout ce champ d'en-tête, alors nginx acheminera la demande vers le serveur par défaut pour ce port. Dans la configuration ci-dessus, le serveur par défaut est le premier ...

Maintenant, si vous vouliez avoir un serveur fourre-tout par défaut qui, disons, répond par 404 à toutes les demandes, alors voici comment le faire:

server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_certificate <path to cert>
    ssl_certificate_key <path to key>
    return 404;
}

Notez que vous devez spécifier le certificat / la clé (qui peut être auto-signé), sinon toutes les connexions SSL échoueront car nginx essaiera d'accepter la connexion en utilisant ce serveur par défaut et ne trouvera pas cert / key.

andreycpp
la source
3
Je n'ai aucune idée pourquoi cette réponse est si loin dans la liste. C'est celui qui répond à la question sans se laisser distraire par des choses brillantes en cours de route.
mmc
Cela m'a aidé à résoudre un problème où j'essayais une redirection de non-www vers www que je devais inclure mon certificat ssl dans cette route de redirection, sinon j'essayais de récupérer mon certificat ssl par défaut qui était un pour un domaine différent.
endyourif
1
Cela semble être la meilleure réponse pour la plupart des configurations ... je ne sais pas qui utilise nginx sans SSL ces jours-ci, mais le fait que ce soit la seule qui couvre SSL est extrêmement révélateur.
mpowered le
Il semble que ce server_name _;ne soit même pas nécessaire.
Julien Salinas
26

Il existe plusieurs façons de spécifier le serveur par défaut.

Première voie - Spécifiez le serveur par défaut en premier dans la liste, si vous conservez vos configurations de serveur dans un seul fichier de configuration, comme Dayo l'a montré ci-dessus.

Deuxième méthode (meilleure) Plus flexible - fournissez un default_serverparamètre pour l' listeninstruction, par exemple:

server {
    listen  *:80 default_server;
    root /www/project/public/;
}

Plus d'informations ici: Nginx doc / Listen

Cette méthode est plus utile lorsque vous conservez les configurations de serveur dans des fichiers séparés et que vous ne souhaitez pas nommer ces fichiers par ordre alphabétique.

Pavel
la source
3
Cela devrait être la bonne réponse. La réponse acceptée est trompeuse. Le simple fait d'ajouter un autre serveur à la configuration ne résoudra pas le problème si un autre serveur est configuré pour être le serveur par défaut.
Ben
1
@Pavel il n'y a aucune raison pour laquelle la réponse fournie ne peut pas fonctionner avec plusieurs fichiers vhost séparés. De plus, avec cela, je sais que mon serveur par défaut est toujours dans le fichier principal nginx.conf et que je n'ai pas à me rappeler lequel de mes nombreux fichiers vhost séparés le contient.
Dayo du
N'oubliez pas d'écouter également 443 pour ssl (voir la réponse de @ AndreyT ci-dessous).
Constantinos
8

Petit commentaire pour répondre:

si vous avez plusieurs hôtes virtuels sur plusieurs adresses IP dans plusieurs fichiers de configuration dans sites-available /, le domaine "par défaut" pour IP sera extrait du premier fichier par ordre alphabétique.

Et comme Pavel l'a dit, il existe un argument "default_server" pour la directive "listen" http://nginx.org/en/docs/http/ngx_http_core_module.html#listen

Oleg Neumyvakin
la source