Rediriger non-www vers www via SSL avec Nginx


25

Je rencontre une erreur lorsque j'essaie de rediriger https://example.com vers https://www.example.com .

Lorsque je vais sur https://example.com , il ne redirige pas et renvoie le statut page / 200.

Je ne veux pas cela, je veux qu'il redirige vers https://www.example.com .

Lorsque je vais sur http://example.com , il redirige vers https://www.example.com

Quelqu'un peut-il me dire où je me trompe?

Voici mes fichiers de configuration par défaut et default-ssl:

default.conf

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

default-ssl.conf

upstream app_server_ssl {
    server unix:/tmp/unicorn.sock fail_timeout=0;
}

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

    listen 443;
    root /home/app/myproject/current/public;
    index index.html index.htm;

    error_log /srv/www/example.com/logs/error.log info;
    access_log /srv/www/example.com/logs/access.log combined;

    ssl on;
    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_certificate /srv/www/example.com/keys/ssl.crt;
    ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
    ssl_ciphers AES128-SHA:RC4-MD5:ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5:AES128-SHA;
    ssl_prefer_server_ciphers on;

    client_max_body_size 20M;


    try_files $uri/index.html $uri.html $uri @app;


    # CVE-2013-2028 http://mailman.nginx.org/pipermail/nginx-announce/2013/000112.html
    if ($http_transfer_encoding ~* chunked) {
            return 444;
        }

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server_ssl;
    }

    error_page 500 502 503 504 /500.html;

    location = /500.html {
        root /home/app/example/current/public;
    }
}

1
Quel est l'intérêt de créer 2 fichiers conf?
Sandip Subedi

Séparation des préoccupations, la configuration non SSL était si petite qu'il semblait préférable de la séparer de la configuration SSL uniquement.
Thomas V.15

Réponses:


34

Il vous manque une listendirective dans le fichier default-ssl.conf. Ajouter listen 443;dans cette directive

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

Par défaut, si vous omettez cette directive, nginx suppose que vous voulez écouter sur le port 80. Voici la documentation de ce comportement par défaut.


Edit: Merci pour le commentaire de @TeroKilkanen.

Voici la configuration complète de votre default-ssl.conf

server {
    listen 443 ssl;
    server_name example.com;

    ssl_certificate /srv/www/example.com/keys/ssl.crt;
    ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
    return 301 https://www.example.com$request_uri;
}

Sidenote : Vous pouvez remplacer ssl on;directive par listen 443 ssl;comme recommandation de la documentation nginx .


4
Vous devez également configurer ssl_certificateet ssl_certificate_keydirectives dans ce bloc, et utiliser listen 443 ssl;pour qu'il soit un vhost SSL.
Tero Kilkanen

Veuillez poster le contenu du courant default-ssl.conf. Peut-être qu'un problème de faute de frappe ou de commande a causé cela.
masegaloeh

C'est embarrassant: \ Le coupable était une configuration nginx en double dans / etc / nginx / sites-enabled, /etc/nginx/sites-enabled/default-ssl.backup interférait avec toutes les redirections dans default-ssl. Erreur idiote.
Thomas V.

j'ai donc dû émettre 2 certificats: pour www-domain et pour non-www one
vladkras

Comment cela peut-il être réalisé sur le port 5007 par exemple: example.com:5007 à example.com:5007
CP3O

5

Ajoutez simplement une instruction if et vous devriez être en route. J'ai vérifié les résultats dans curl.exe -I et tous les cas en dehors de https://www.example.com sont traités comme 301. SSL est délicat car il est vérifié avant d'obtenir la redirection d'URL 301. Par conséquent, vous obtenez des erreurs de certificat.

Personnellement, j'aime supprimer les www du domaine mais j'ai écrit mon code ci-dessous pour répondre à votre question.

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

server_name example.com www.example.com; # List all variations here

# If the domain is https://example.com, lets fix it!

if ($host = 'example.com') {
  return 301 https://www.example.com$request_uri;
}

# If the domain is https://www.example.com, it's OK! No changes necessary!

... # SSL .pem stuff
...
}

server {
listen 80;
listen [::]:80;

# If the domain is http://example.com or https://www.example.com, let's change it to https!

server_name example.com www.example.com;
return 310 https://www.example.com$request_uri;
}

3

La façon dont je le fais est d'utiliser une instruction if à l'intérieur du bloc serveur SSL qui redirige vers https de www

ssl_certificate /srv/www/example.com/keys/ssl.crt;
ssl_certificate_key /srv/www/example.com/keys/www.example.com.key;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers AES128-SHA:RC4-MD5:ECDH+AESGCM:ECDH+AES256:ECDH+AES128:DH+3DES:RSA+3DES:!ADH:!AECDH:!MD5:AES128-SHA;
ssl_prefer_server_ciphers on;
client_max_body_size 20M;

upstream app_server_ssl {
    server unix:/tmp/unicorn.sock fail_timeout=0;
}

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

server {
    listen 443 default_server ssl;
    server_name www.example.com;

    # redirect https://example.com to https://www.example.com
    # mainly for SEO purposes etc
    #we will use a variable to do that
    set $redirect_var 0;

    if ($host = 'example.com') {
      set $redirect_var 1;
    }
    if ($host = 'www.example.com') {
      set $redirect_var 1;
    }

    if ($redirect_var = 1) {
      return 301 https://www.example.com$request_uri;
    } 

    try_files $uri/index.html $uri.html $uri @app;

    # CVE-2013-2028 http://mailman.nginx.org/pipermail/nginx-announce/2013/000112.html
    if ($http_transfer_encoding ~* chunked) {
            return 444;
        }

    location @app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://app_server_ssl;
    }

    error_page 500 502 503 504 /500.html;

    location = /500.html {
        root /home/app/example/current/public;
    }
}

Bien sûr, chaque fois que vous souhaitez utiliser une instruction if dans un fichier de configuration nginx; vous devriez avoir lu: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/


la condition if ($host = 'www.example.com')n'est pas nécessaire.
Karl.S

2

C'est 2018 maintenant et j'ai pensé donner à celui-ci un coup de feu renouvelé au cas où quelqu'un chercherait une solution simple.

Mon point de vue en tant que nouveau venu est de rendre les choses aussi simples que possible. Fondamentalement, vous souhaitez rediriger à la fois http://example.com et https://example.com vers https : // www .example.com. Et que vous ne réussissez qu'à rediriger http://example.com

C'est une opération assez simple ne nécessitant que deux blocs serveur (je vais le démontrer brièvement dans un seul fichier de configuration)

# 1. Server block to redirect all non-www and/or non-https to https://www
server {
    # listen to the standard http port 80
    listen 80; 

    # Now, since you want to route https://example.com to http://www.example.com....
    # you need to get this block to listen on https port 443 as well
    # alternative to defining 'ssl on' is to put it with listen 443
    listen 443 ssl; 

    # define server_name
    server_name example.com *.example.com; 

    # DO NOT (!) forget your ssl certificate and key
    ssl_certificate PATH_TO_YOUR_CRT_FILE;
    ssl_certificate_key PATH_TO_YOUR_KEY_FILE; 

    # permanent redirect
    return 301 https://www.example.com$request_uri;  
    # hard coded example.com for legibility 
}
# end of server block 1. nearly there....

# 2. Server block for the www (primary) domain
# note that this is the block that will ultimately deliver content
server {
    # define your server name
    server_name www.example.com; 

    # this block only cares about https port 443
    listen 443 ssl;

    # DO NOT (!) forget your ssl certificate and key
    ssl_certificate PATH_TO_YOUR_CRT_FILE;
    ssl_certificate_key PATH_TO_YOUR_KEY_FILE; 

    # define your logging .. access , error , and the usual 

    # and of course define your config that actually points to your service
    # i.e. location / { include proxy_params; proxy_pass PATH_TO_SOME_SOCKET; }
}
# End of block 2.
# voilà! 

Maintenant, http://example.com et https://example.com doivent rediriger vers https://www.example.com . Fondamentalement, cette configuration redirige tout ce qui n'est pas www et / ou non https vers https: // www .


-1

Pour rediriger toutes les demandes vers https://www.example

créer un bloc serveur pour la redirection et le domaine principal sur votre port SSL (généralement 443) ainsi que le port http par défaut 80

# non-www to ssl www redirect
server {
  listen 80; 
  listen 443 ssl;
  server_name example.com;
  return 301 https://www.example.com$request_uri;
  # ... ssl certs
}

# ssl setup for www (primary) domain
server {
  listen 80;
  listen 443 ssl;
  server_name www.example.com;
  if ($scheme = http) {
    return 301 https://www.example.com$request_uri;
  }
  # ... the rest of your config + ssl certs
}

enregistrer et suivre avec sudo nginx -s reload

Cela redirigera

http://example      301 -> https://www.example
https://example     301 -> https://www.example
http://www.example  301 -> https://www.example
https://www.example 200

Il vous manque un ;dans le deuxième bloc serveur de la clause if. Ça devrait êtrereturn 301 https://www.example.com$request_uri;
Lukas Oppermann

1
Cependant, cela fonctionnerait-il même? Peut - on écouter httpsur 443?
Lukas Oppermann

vous avez raison, il me manque écouter 80, ive l'a ajouté.
lfender6445
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.