Configurer correctement un serveur nginx «par défaut» pour https

71

J'ai plusieurs serveurs fonctionnant sur le même ordinateur, certains avec http uniquement, d'autres avec http et https. Plusieurs blocs de serveur sont définis dans des fichiers séparés, inclus dans le fichier de configuration principal.

J'ai mis en place un serveur "par défaut" pour http qui servira une "page de maintenance" générique aux demandes 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 inclus (car j'ai observé que, dans le cas de doublons de noms de serveur sur plusieurs 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 commutant seulement "listen 80 default_server" sur "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 récupère toutes les connexions https entrantes et les cause à leur échec, bien que les autres blocs du serveur aient des noms de serveur plus appropriés pour les demandes entrantes. La suppression du nouveau serveur https par défaut entraîne la reprise d'un comportement semi-correct: les sites Web dotés de https se chargeront tous correctement; mais les sites Web sans https seront tous routés vers le premier serveur https dans les fichiers d'inclusion (qui, selon la documentation, n'indique pas "default_server", le premier bloc de serveur à apparaître sera "default").

Ma question est donc la suivante: quelle est la bonne façon de définir un "serveur par défaut" dans nginx pour les connexions ssl? Pourquoi est-ce que quand je définis explicitement un "serveur_de_faut", il devient gourmand et saisit toutes les connexions alors que quand je laisse implicitement nginx décider du "serveur par défaut", il fonctionne comme je le pensais (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 d'autres serveurs. Https casse d'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;
    }
}

Quelqu'un parmi vous voit ce qui pourrait être faux ici?


la source

Réponses:

27

Vous n'avez pas de ssl_certificate ou ssl_certificate_key définis dans votre bloc https "par défaut". Bien que vous ne possédiez pas ou ne souhaitiez pas de clé réelle pour ce scénario par défaut, vous devez tout de même en configurer une, sinon 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 pour qu'il fonctionne comme vous le souhaitez.

Le comportement "par défaut" dans cette configuration serait qu'un navigateur recevrait un avertissement lui indiquant que le certificat ne pouvait pas être approuvé, si l'utilisateur ajoutait le certificat comme exception, la connexion serait abandonnée par nginx et ils verraient les valeurs par défaut de leur navigateur. Message d'erreur "Impossible de se connecter".

Radmilla Mustafa
la source
1
J'ai essayé cela, mais cela ne fonctionne toujours pas: toutes les demandes ssl adressées à l'IP sont envoyées à mon autre hôte ssl. Quelque chose d'autre que je pourrais essayer?
Michael Härtl
23

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

1 - Créer une zone par défaut

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

2 - Remplir la zone par défaut

Remplissez votre 00-defaultavec 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;
}

3 - Créer des certif, des tests et des recharges 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 ça aide.

Si non
la source
2
Ne résout pas le navigateur avertissant de visiter un site non sécurisé.
Gdbj
5
Ne peut pas être résolu car une fourre-tout doit correspondre à tous les domaines. Aucun SSL ne peut contenir tous les domaines. Imaginez que si vous usurper une adresse google.fr sur votre serveur, vous pourrez authentifier votre serveur en tant que google.fr. Ce serait un grave problème de sécurité :(
Si pas
Oui, je suppose que cela a du sens. Malheureusement, dans Chrome, un avertissement effrayant vous est présenté avant de voir la page 404, ce qui est pire que de simplement refuser le trafic par le serveur. Cela donne l'impression que le serveur est mal configuré.
Gdbj
Merci beaucoup. Cela a fonctionné pour moi, sauf que j'ai dû ajouter default_serverpour écouter 443 et que j'ai ajouté l'adresse IPv6 [::]: 80 et [::]: 443 avec default_server.
chmike
16

Nous voulons fondamentalement éviter à tout prix que la première définition de serveur de notre fichier de configuration serve de serveur fourre-tout pour les connexions SSL. Nous savons tous que c'est ce qui se produit (contrairement à http et à la configuration par défaut de default_server qui fonctionne bien).

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

La variable $hostest le nom d'hôte de la ligne de requête ou de l'en-tête http. La variable $server_nameest le nom du bloc de serveur dans lequel nous sommes en ce moment.

Par conséquent, si ces deux éléments ne sont pas égaux, vous avez servi ce blocage de serveur SSL à un autre hôte. Ce blocage doit donc ê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;
    }

    ...
Rolf
la source
pourriez-vous expliquer ce que listen [::]:443 ssl http2;fait le J'ai de la difficulté à trouver de la documentation à ce sujet.
Andrew Brown
Je pense que je l'ai trouvé, je voulais juste savoir quoi chercher. Directives IPV4 et IPV6.
Andrew Brown
7

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 une connexion SSL, ce qui revient à avoir un certificat / une clé. Le cert / clé peut être quelconque, par exemple auto-signé.

Voir la documentation

La solution est donc la suivante:

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
}
Andreycpp
la source
Je pense que cela devrait être la réponse acceptée. Merci beaucoup.
aggregate1166877
2

À tous ceux qui ont perdu autant de cheveux que moi (y ont passé presque toute la journée). J'ai presque tout essayé, et ce qui a finalement fonctionné correctement est cette stupide ligne:

ssl_session_tickets off;

En me basant sur la réponse de Ifnot , mon exemple de travail est le suivant:

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 c'était nécessaire, le seul principe que j'ai tiré de cela est que nginx se comporte très étrangement quand on ne lui donne pas ce qu'il veut.

Marek Lisý
la source
1
tu es une légende.
Nizar Blond
1

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 devraient. Cela résout également le problème de l'avertissement du navigateur "certificat non valide".

Michael Hampton
la source