web-dev-qa-db-fra.com

Configuration correcte d'un serveur nginx "par défaut" pour https

J'ai plusieurs serveurs fonctionnant sur la même machine, certains avec http uniquement, certains avec http et https. Il existe plusieurs blocs de serveur définis dans des fichiers séparés qui sont inclus à partir du fichier de configuration principal.

J'ai mis en place un serveur "par défaut" pour http qui servira de "page de maintenance" générique aux requêtes qui ne correspondent à aucun des autres noms de serveur dans les autres fichiers de configuration. Le serveur http par défaut fonctionne comme prévu, il utilise le nom_serveur "_" et il apparaît en premier dans la liste des inclusions (car j'ai observé que dans le cas de noms_serveurs en double sur les serveurs, celui qui apparaît en premier est utilisé). Cela fonctionne très bien.

Je m'attendrais au même bloc de serveur exact (en changeant seulement "listen 80 default_server" en "listen 443 default_server" et aussi au lieu de servir la page "return 444") mais ce n'est pas le cas. Au lieu de cela, il semble que le nouveau serveur https par défaut saisit réellement toutes les connexions https entrantes et les fasse échouer, bien que les autres blocs de serveur aient des noms de serveur plus appropriés pour les demandes entrantes. La suppression du nouveau serveur https par défaut entraînera la reprise d'un comportement semi-correct: les sites Web avec https se chargeront tous correctement; mais les sites Web sans https seront tous acheminés vers le premier serveur https dans les fichiers include (qui, selon les documents, si aucun "serveur_par défaut" n'apparaît, alors le premier bloc de serveur à apparaître sera "par défaut").

Donc ma question est, quelle est la bonne façon de définir un "serveur par défaut" dans nginx pour les connexions SSL? Pourquoi est-ce que lorsque je définit explicitement un "serveur_par défaut", il devient gourmand et saisit toutes les connexions alors que lorsque je laisse implicitement nginx décider du "serveur par défaut", cela fonctionne comme je m'y attendais (avec le serveur incorrect défini par défaut et les autres serveurs réels se comporter correctement)?

Voici mes "serveurs par défaut". Http fonctionne sans casser les autres serveurs. Https casse les autres serveurs et consomme tout.

server {
    listen 443 ssl default_server;
    server_name _;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    return 444;
}

server {
    listen *:80 default_server;
    server_name _;
    charset utf-8;

    access_log /var/log/nginx/maintenance.access.log;
    error_log /var/log/nginx/maintenance.error.log error;

    root /home/path/to/templates;

    location / {
        return 503;
    }

    error_page 503 @maintenance;

    location @maintenance {
        rewrite ^(.*)$ /maintenance.html break;
    }
}

L'un d'entre vous voit-il ce qui ne va pas ici?

84
Roar

Vous n'avez aucun ssl_certificate ou ssl_certificate_key défini dans votre bloc https "par défaut". Bien que vous ne disposiez pas ou ne souhaitiez pas de clé réelle pour ce scénario par défaut, vous devez toujours configurer un ou bien nginx aura le comportement indésirable que vous décrivez.

Créez un certificat auto-signé avec un nom commun de * et branchez-le dans votre configuration et il commencera à fonctionner comme vous le souhaitez.

Le comportement "par défaut" dans cette configuration serait qu'un navigateur recevrait un avertissement que le certificat ne peut pas être approuvé, si l'utilisateur ajoute le certificat à titre d'exception, la connexion sera abandonnée par nginx et il verra la valeur par défaut de son navigateur Message d'erreur "impossible de se connecter".

29
Radmilla Mustafa

J'ai réussi à configurer un hébergement dédié partagé sur une seule IP avec nginx. HTTP et HTTPS par défaut desservant un 404 pour les domaines inconnus entrants.

1 - Créer une zone par défaut

Comme nginx charge les vhosts dans l'ordre ascii, vous devez créer un 00-default fichier/lien symbolique dans votre /etc/nginx/sites-enabled.

2 - Remplissez la zone par défaut

Remplissez votre 00-default avec des vhosts par défaut. Voici la zone que j'utilise:

server {
    server_name _;
    listen       80  default_server;
    return       404;
}


server {
    listen 443 ssl;
    server_name _;
    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    return       404;
}

- Créer un certificat, un test et un rechargement auto-signés

Vous devrez créer un certificat auto-signé dans /etc/nginx/ssl/nginx.crt.

Créez un certificat auto-signé par défaut:

Sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Juste un rappel:

  • Testez la configuration de nginx avant de recharger/redémarrer: nginx -t
  • Recharger un plaisir: Sudo service nginx reload

J'espère que cela aide.

25
Ifnot

Nous voulons essentiellement éviter à tout prix que la première définition de serveur dans notre fichier de configuration soit utilisée comme un fourre-tout pour les connexions SSL. Nous savons tous que c'est le cas (contrairement à http et à l'utilisation de la configuration par défaut du serveur qui fonctionne bien).

Cela ne peut pas être réalisé de manière déclarative pour SSL (encore), nous devons donc le coder avec un IF ...

La variable $Host est le nom d'hôte de la ligne de demande ou de l'en-tête http. La variable $server_name est le nom du bloc serveur dans lequel nous nous trouvons actuellement.

Donc, si ces deux ne sont pas égaux, vous avez servi ce bloc de serveur SSL pour un autre hôte, ce qui devrait être bloqué.

Le code ne contient pas de références spécifiques aux adresses IP de votre serveur, il peut donc être facilement réutilisé pour d'autres configurations de serveur sans modification.

Exemple:

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;

    ###
    ### Section: SSL

    #
    ## Check if this certificate is really served for this server_name
    ##   http://serverfault.com/questions/578648/properly-setting-up-a-default-nginx-server-for-https
    if ($Host != $server_name) {
        #return 404 "this is an invalid request";
        return       444;
    }

    ...
17
Rolf

Pour en savoir plus sur la réponse de Radmilla Mustafa:

Nginx utilise l'en-tête "Host" pour la correspondance nom_serveur. Il n'utilise pas TLS SNI. Cela signifie que pour un serveur SSL, nginx doit pouvoir accepter la connexion SSL, ce qui revient à avoir un certificat/clé. Le certificat/clé peut être n'importe lequel, par ex. auto-signé.

Voir documentation

Par conséquent, la solution est:

server {
    server_name _;
    listen 80 default_server;
    listen 443 ssl default_server;

    ## To also support IPv6, uncomment this block
    # listen [::]:80 default_server;
    # listen [::]:443 ssl default_server;

    ssl_certificate <path to cert>;
    ssl_certificate_key <path to key>;
    return 404; # or whatever
}
8
andreycpp

À tous ceux qui ont perdu autant de cheveux que moi (j'ai passé presque toute la journée là-dessus aujourd'hui). J'ai essayé presque tout, et ce qui l'a finalement fait fonctionner correctement était cette ligne stupide:

ssl_session_tickets off;

En s'appuyant sur la réponse de Ifnot , mon exemple de travail est:

server {
    listen 443 ssl http2 default_server;
    listen [::]:443 ssl http2 default_server;
    server_name _;

    ssl_certificate /etc/nginx/ssl/nginx.crt;
    ssl_certificate_key /etc/nginx/ssl/nginx.key;
    ssl_session_tickets off;

    return 404;
}

Je ne sais pas pourquoi cela était nécessaire, le seul principe que j'en ai tiré est que nginx se comporte très étrangement quand on ne lui donne pas ce qu'il veut.

4
Marek Lisý

Si vous voulez être absolument sûr, utilisez des adresses IP distinctes pour les hôtes qui ne devraient pas répondre sur HTTPS et les hôtes qui le devraient. Cela résout également le problème d'avertissement du navigateur "certificat non valide".

1
Michael Hampton