112 votes

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, d'autres avec http et https. Plusieurs blocs de serveurs sont définis dans des fichiers séparés qui sont 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 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 de serveur "_" et apparaît en premier dans la liste des inclusions (car j'ai observé qu'en cas de doublons de noms de serveur entre serveurs, celui qui apparaît en premier est utilisé). Cela fonctionne parfaitement.

Je m'attendrais à un blocage identique du serveur (en remplaçant simplement "listen 80 default_server" par "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 fait échouer, bien que les autres blocs de serveurs aient des noms de serveurs plus appropriés pour les requêtes entrantes. En supprimant le nouveau serveur https par défaut, le comportement semi-correct sera rétabli : les sites web avec https se chargeront tous correctement ; mais les sites web sans https seront tous dirigés vers le premier serveur https dans les fichiers include (qui, selon la documentation, si aucun "default_server" n'apparaît, alors le premier bloc serveur à apparaître sera "default").

Ma question est donc la suivante : quelle est la manière correcte de définir un "serveur par défaut" dans nginx pour les connexions ssl ? Comment se fait-il que lorsque je définis explicitement un "serveur par défaut", il devient gourmand et s'empare de toutes les connexions alors que lorsque je laisse implicitement nginx décider du "serveur par défaut", il fonctionne comme je m'y attendais (avec le serveur incorrect défini comme serveur par défaut et les autres serveurs réels se comportant 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 pourrait clocher ici ?

54voto

jcoffland Points 199

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

1 - Créer une zone par défaut

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

2 - Remplir la zone par défaut

Remplissez votre 00-default avec les 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 un certificat auto-signé, tester, et recharger

Vous devrez créer un certificat auto-signé dans le fichier /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
  • Rechargez un plaisir : sudo service nginx reload

J'espère que cela vous aidera.

3 votes

Cela ne résout pas l'avertissement du navigateur concernant la visite d'un site non sécurisé.

7 votes

Ne peut être résolu car un fourre-tout doit correspondre à tous les domaines. Aucun SSL ne peut utiliser des caractères génériques pour tous les domaines. Imaginez que vous usurpiez l'adresse google.fr sur votre serveur, vous serez en mesure d'authentifier votre serveur comme étant google.fr. Ce serait un sérieux problème de sécurité :(

2 votes

Oui, je suppose que ça a du sens. Malheureusement, dans Chrome, on vous présente un avertissement effrayant avant de voir la page 404, ce qui est pire que le fait que le serveur rejette simplement le trafic. Cela donne l'impression que le serveur est mal configuré.

30voto

Radmilla Mustafa Points 419

Vous n'avez pas de ssl_certificate ou ssl_certificate_key défini dans votre bloc https "par défaut". Bien que vous n'ayez pas ou ne vouliez pas de clé réelle pour ce scénario par défaut, vous devez quand 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 insérez-le dans votre configuration pour qu'il fonctionne comme vous le souhaitez.

Si l'utilisateur ajoute le certificat en tant qu'exception, la connexion sera abandonnée par nginx et il verra le message d'erreur par défaut de son navigateur "impossible de se connecter".

1 votes

J'ai essayé ceci mais ça ne fonctionne toujours pas : Toutes les demandes ssl vers l'IP vont vers mon autre hôte ssl. Y a-t-il autre chose que je puisse essayer ?

20voto

Rolf Points 291

Nous voulons essentiellement éviter à tout prix que la première définition de serveur dans notre fichier de configuration serve de serveur fourre-tout pour les connexions SSL. Nous savons tous que c'est ce qu'il fait (contrairement à http et à l'utilisation de la configuration default_server 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 de serveurs dans lequel nous nous trouvons actuellement.

Si les deux ne sont pas égaux, alors vous avez servi ce bloc de serveur SSL à un autre hôte, qui 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;
    }

    ...

0 votes

Pourriez-vous expliquer ce que le listen [::]:443 ssl http2; J'ai du mal à trouver de la documentation à ce sujet.

0 votes

Je pense que je l'ai trouvé, j'avais juste besoin de savoir quoi chercher. Les directives IPV4 et IPV6.

18voto

andreycpp Points 649

Pour développer davantage la réponse de Radmilla Mustafa :

Nginx utilise l'en-tête "Host" pour faire correspondre le nom du serveur. Il n'utilise pas le SNI de TLS. Cela signifie que pour un serveur SSL, nginx doit être en mesure d'accepter une connexion SSL, ce qui revient à avoir un certificat/une clé. Le certificat/la clé peut être quelconque, par exemple auto-signé.

Voir documentation

La solution est donc :

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
}

0 votes

Je pense que cela devrait être la réponse acceptée. Merci beaucoup.

0 votes

Configuration simple et propre et fonctionne parfaitement. Merci.

9voto

hyperknot Points 641

Si vous voulez simplement vous assurer qu'aucune donnée n'est renvoyée, vous pouvez utiliser le snippet suivant sans certificats :

map "" $empty {
        default "";
}

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

        server_name _;

        ssl_ciphers aNULL;
        ssl_certificate data:$empty;
        ssl_certificate_key data:$empty;

        return 444;
}

0 votes

Merci, cela a parfaitement fonctionné pour moi.

0 votes

Malheureusement, cela me donne BIO_new_file("/etc/nginx/data:$empty") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/etc/nginx/data:$empty','r') error:2006D080:BIO routines:BIO_new_file:no such file) .

2 votes

Apparemment, le map … peut être remplacé par un simple set $empty "" juste avant le ssl_certificate . Cela fonctionne pour moi avec Nginx 1.18.0.

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