81 votes

Supprimer "www" et rediriger vers "https" avec nginx

Je veux créer une règle dans nginx qui fait deux choses :

  1. Supprime le "www." de l'URI de la demande.
  2. Redirige vers "https" si l'URI de la demande est "http".

Il existe de nombreux exemples de la façon de faire chacune de ces choses individuellement, mais je n'arrive pas à trouver une solution qui fasse les deux correctement (c'est-à-dire qui ne crée pas de boucle de redirection et qui traite tous les cas correctement).

Il doit traiter tous ces cas :

1. http://www.example.com/path
2. https://www.example.com/path
3. http://example.com/path
4. https://example.com/path

Ils devraient tous finir à https://example.com/path (#4) sans faire de boucle. Avez-vous des idées ?

129voto

kolbyjack Points 7644

La meilleure façon d'y parvenir est d'utiliser trois blocs de serveur : un pour rediriger http vers https, un pour rediriger le nom www de https vers no-www, et un pour traiter réellement les demandes. La raison de l'utilisation de blocs de serveurs supplémentaires au lieu de ifs est que la sélection des serveurs est effectuée à l'aide d'une table de hachage, et est très rapide. L'utilisation d'un if au niveau du serveur signifie que le if est exécuté pour chaque requête, ce qui est un gaspillage. De même, la capture de l'url demandé dans la réécriture est un gaspillage, car nginx dispose déjà de cette information dans les variables $uri et $request_uri (sans et avec la chaîne de requête, respectivement).

server {
    server_name www.example.com example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.cert;
    ssl_certificate_key /path/to/server.key;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}

server {
    listen 443 ssl;
    ssl_certificate /path/to/server.cert;
    ssl_certificate_key /path/to/server.key;
    server_name example.com;

    <locations for processing requests>
}

12voto

e18r Points 221

Cela fonctionne pour moi :

server {
    listen              80;
    server_name         www.yourdomain.com yourdomain.com;
    return              301 https://yourdomain.com$request_uri;
}

server {
    listen              443 ssl;
    server_name         www.yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;
    return              301 https://yourdomain.com$request_uri;
}

server {
    listen              443 ssl;
    server_name         yourdomain.com;
    ssl_certificate     /path/to/certificate.crt;
    ssl_certificate_key /path/to/private/key.pem;
    ssl_protocols       TLSv1 TLSv1.1 TLSv1.2;

    # do the proper handling of the request
}

Gardez à l'esprit que les deux yourdomain.com y www.yourdomain.com doit être dans votre certificat SSL. Cela est possible avec un certificat de type "wildcard" ou avec un nom alternatif de serveur, comme expliqué ci-dessous. aquí . Vérifier https://www.startssl.com pour des certificats agréables et gratuits qui font cela. ( Edith A partir de la version 56 de Chrome, les certificats startssl ne seront plus fiables. Essayez https://letsencrypt.org/ à la place).

9voto

emyller Points 191

Après avoir passé beaucoup de temps avec des centaines de cas similaires, j'ai trouvé que l'extrait suivant. Il est court et peut être facilement modifié pour s'adapter à tout.

server {
    listen 80;
    listen 443 ssl;
    server_name example.com www.example.com;
    ssl_certificate /path/to/my/certs/example.com/fullchain.pem;
    ssl_certificate_key /path/to/my/certs/example.com/privkey.pem;

    # Redirect to the correct place, if needed
    set $https_redirect 0;
    if ($server_port = 80) { set $https_redirect 1; }
    if ($host ~ '^www\.') { set $https_redirect 1; }
    if ($https_redirect = 1) {
        return 301 https://example.com$request_uri;
    }

    location / {
    # ...
}

Oh, mais if c'est le mal ¡!

Oui. peut être. Mais il existe pour une raison, et ne devrait pas faire de mal à ceux qui savent l'utiliser correctement. qui savent l'utiliser correctement ;)

3voto

user189624 Points 1

Je préfère retourner avec un code de réponse pour que le navigateur sache que vous le redirigez vers une autre URL.

server {
    listen   80;
    server_name  www.example.com;

    return 301 https://example.com$request_uri;
}

puis un autre bloc de configurations de serveur pour le https

server {
        listen   443 ssl;
        server_name  example.com;
        ...
    }

1voto

Frank Wallace Points 1

Si vous avez plusieurs domaines et que vous cherchez une solution plus approche générique sans perdre de performance et sans lister tous les domaines tout le temps, vérifiez ceci.

Comment cela fonctionne-t-il ?

  1. écouter sur 80 et rediriger tous les http vers https - y compris http://www. qui ira à https://www.
  2. écouter 433, mais seulement sur www et rediriger vers des noms de serveurs non www en utilisant une expression régulière
  3. écoutez 433 pour chacun de vos non www nom du serveur - c'est là que tout le trafic aboutira

Est-il rapide ?
Oui ! Même si nous utilisons RegExp, c'est seulement dans la section www -versions qui renvoie 301. Ainsi, tout le trafic normal sera traité sans coût de traitement supplémentaire.

  # Redirect everything to HTTPS (including "www")
  server {
    listen 80 default_server;
    listen [::]:80 default_server;
    return 301 https://$host$request_uri;
  }

  # Redirect away from "www" versions:
  server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    server_name www.example-1.com
                www.example-2.com
                www.example-3.com;
    # using generic "www" removal      // https://stackoverflow.com/questions/11323735/nginx-remove-www-and-respond-to-both/45676731#45676731
    if ( $host ~ ^www\.(.+)$ ) {
      set $without_www $1;
      rewrite ^ $scheme://$without_www$uri permanent;
    }
    # SSL settings:
    ssl_certificate /etc/letsencrypt/live/example/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example/privkey.pem; # managed by Certbot
  }

  # And finally one "server" block for each of your domains
  server {
    listen [::]:443 ssl http2;
    listen 443 ssl http2;
    server_name example-1.com;
    # SSL settings, etc...
  }
  server {
    server_name example-2.com;
    # ... listen, ssl, etc...
  }
  server {
    server_name example-3.com;
    # ... etc
  }

PS : si vous avez besoin d'aide pour la configuration de SSL, vérifiez Générateur de configuration SSL de Mozilla :
https://ssl-config.mozilla.org/

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