Comment configurer plusieurs sous-domaines avec leur propre certificat en utilisant nginx?

8

À moins que chaque réponse que j'ai lue ne soit tout à fait fausse, SNI devrait permettre de faire ce que je veux, mais chaque guide me dit de faire exactement ce que je fais.

Et pourtant, nginx sert le mauvais certificat, donc je fais clairement quelque chose de mal.

❯ sudo nginx -V | grep SNI                                                                                                                                                                                                                                                            %1
nginx version: nginx/1.10.3
built with OpenSSL 1.1.0f  25 May 2017
TLS SNI support enabled
configure arguments: --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-qJwWoo/nginx-1.10.3=. -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-z,relro -Wl,-z,now' --prefix=/usr/share/nginx --conf-path=/etc/nginx/ngi
nx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fa
stcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-pcre-jit --with-ipv6 --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_reques
t_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_geoip_module=dynamic --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --wit
h-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=/build/nginx-qJwWoo/nginx-1.10.3/debian/modules/nginx-auth-pam --add-dynamic-module=/build/nginx-qJwWoo/nginx-1.10.3/debian/modules/nginx-dav-
ext-module --add-dynamic-module=/build/nginx-qJwWoo/nginx-1.10.3/debian/modules/nginx-echo --add-dynamic-module=/build/nginx-qJwWoo/nginx-1.10.3/debian/modules/nginx-upstream-fair --add-dynamic-module=/build/nginx-qJwWoo/nginx-1.10.3/debian/modules/ngx_http_substitutions_filter_m
odule

Voici à quoi ressemblent mes configurations:

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

  server_name one.example.com;

  ssl on;
  ssl_certificate       /etc/letsencrypt/live/one.example.com/fullchain.pem;
  ssl_certificate_key   /etc/letsencrypt/live/one.example.com/privkey.pem;

  index index.html;
  root /var/www/one.example.com/site;
}

server {
  #listen 443 ssl default_server;
  listen [::]:443 ssl;

  server_name two.example.com;

  ssl on;
  ssl_certificate       /etc/letsencrypt/live/two.example.com/fullchain.pem;
  ssl_certificate_key   /etc/letsencrypt/live/two.example.com/privkey.pem;

  index index.html;
  root /var/www/two.example.com/site;
}

Si j'ai la listen 443 ssl default_server;directive dans l'un ou l'autre des serveurs, elle renverra le certificat SSL pour ce serveur pour les DEUX domaines. Si je le supprime des deux domaines, je ne reçois rien du tout - les deux domaines de serveur refusent les connexions.

Qu'est-ce que je vais mal ici? Est-ce que je ne comprends tout simplement pas comment fonctionne SNI? Mon nginx a été construit avec le support SNI activé. Et pourtant ... je ne reçois le certificat SSL que pour un sous-domaine.

Wayne Werner
la source
Comment testez-vous? Si vous testez avec openssl s_clientassurez-vous d'ajouter l' -servername hostnameoption pour que le client utilise réellement SNI.
Steffen Ullrich
@SteffenUllrich Chrome est une façon dont je l'ai fait. Je viens d'essayer d'utiliser openssl s_client -servername two.example.com -connect two.example.com:443et cela me donne le CN pour one.example.com. Si j'échange lequel a le serveur par défaut, j'obtiens les choses dans l'autre sens.
Wayne Werner
Et pour les coups de pied et les sourires, je l'ai juste mélangé: -servername one -connect twoet vice versa. Openssl s_client et chrome observent le même comportement - la seule caractéristique de définition apparente est la ligne de serveur par défaut.
Wayne Werner
@SteffenUllrich, il semblerait que la syntaxe IPv6 pour l'écoute fasse quelque chose de différent? J'ai posté une réponse, mais si cela déclenche quelque chose pour vous, j'aimerais en savoir plus sur pourquoi
Wayne Werner
Lorsque j'ai plusieurs sites sur un même serveur, je préfère avoir un default_serverbloc complètement séparé qui ne renvoie aucun des sites.
Tero Kilkanen du

Réponses:

11
listen 443 ssl default_server;
listen [::]:443 ssl;

La première ligne permet d'écouter sur le port 443 sur IPv4. La deuxième ligne couvre uniquement IPv6. Puisque vous n'avez qu'une seule listen 443configuration (IPv4), c'est celle qui est utilisée si vous vous connectez avec IPv4. Si vous essayez de vous connecter avec IPv6, SNI devrait afficher le comportement attendu.

Au lieu de cela, vous pourriez probablement utiliser pour le serveur par défaut:

  listen 443 ssl default_server;
  listen [::]:443 ssl default_server;

Et pour l'autre serveur

  listen 443 ssl;
  listen [::]:443 ssl;
Steffen Ullrich
la source
2

Cela a apparemment quelque chose à voir avec la syntaxe d'écoute IPv6. Quand je change

listen [::]:443 ssl;

à

listen 443 ssl;

Alors ça marche.

Je ne sais pas pourquoi c'est et j'accueillerais volontiers d'autres réponses avec une explication plus / meilleure.

Wayne Werner
la source
Vous êtes-vous donc connecté avec IPv4 ou IPv6 au serveur? Si vous vous êtes connecté avec IPv4, cela est clair car vous n'aviez qu'une seule configuration IPv4 - le serveur par défaut. Pour que la configuration IPv6 couvre également IPv4, vous devez ajouteripv6only=off;
Steffen Ullrich