Redirigir no www a www sobre SSL con Nginx

25

Tengo un error al intentar redirigir https://example.com a https://www.example.com .

Cuando voy a https://example.com , no se redirige y devuelve el estado de la página / 200.

No quiero esto, quiero que redirija a https://www.example.com .

Cuando voy a http://example.com , redirige a https://www.example.com

¿Alguien puede decirme dónde me estoy equivocando?

Estos son mis archivos de configuración predeterminados y 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;
    }
}
Thomas V.
fuente
1
¿Cuál es el punto de crear 2 archivos conf?
Sandip Subedi
Separación de preocupaciones, la configuración no SSL era tan pequeña que parecía mejor separarla de la configuración solo SSL.
Thomas V.

Respuestas:

34

Te falta la listendirectiva en el archivo default-ssl.conf. Agregar listen 443;en esta directiva

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

Por omisión, si omite esta directiva, nginx asume que desea escuchar en el puerto 80. Aquí encontrará la documentación de este comportamiento predeterminado.


Editar: Gracias por el comentario de @TeroKilkanen.

Aquí la configuración completa para su 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;
}

Nota al margen : puede reemplazar la ssl on;directiva con una listen 443 ssl;recomendación de la documentación de nginx .

masegaloeh
fuente
44
También necesita configurar ssl_certificatey ssl_certificate_keydirectivas en este bloque, y usar listen 443 ssl;para que sea un vhost SSL.
Tero Kilkanen
Por favor, publique contenidos de actual default-ssl.conf. Tal vez algún error tipográfico o de reordenamiento causó eso.
masegaloeh
Esto es vergonzoso: \ El culpable era una configuración duplicada de nginx en / etc / nginx / sites-enabled, /etc/nginx/sites-enabled/default-ssl.backup estaba interfiriendo con cualquier redirección en default-ssl. Error tonto.
Thomas V.
así que tuve que emitir 2 certs: para www-domain y para no www
vladkras
¿Cómo se puede lograr esto en say port 5007: example.com:5007 to example.com:5007
CP3O
5

Simplemente agregue una declaración if y debería estar en camino. Verifiqué los resultados en curl.exe -I y todos los casos además de https://www.example.com se tratan como 301. SSL es complicado porque se verifica antes de obtener la redirección de URL 301. Por lo tanto, obtiene errores de certificado.

Personalmente, me gusta eliminar las www del dominio, pero escribí mi código a continuación para responder a su pregunta.

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;
}
Brian Lee
fuente
3

La forma en que lo hago es usar una declaración if dentro del bloque del servidor SSL que redirige a 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;
    }
}

Por supuesto, siempre que desee utilizar una instrucción if en un archivo de configuración nginx; deberías haber leído: https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/

Komu
fuente
La condición if ($host = 'www.example.com')no es necesaria.
Karl.S
2

Es 2018 ahora y pensé darle a esta una oportunidad renovada en caso de que alguien esté buscando una solución simple.

Mi opinión sobre esto como un recién llegado es hacer las cosas lo más simples posible. Básicamente, desea redirigir tanto http://example.com como https://example.com a https : // www .example.com. Y que solo logras redirigir http://example.com

Esta es una operación bastante sencilla que requiere solo dos bloques de servidor (lo demostraré brevemente en un solo archivo de configuración)

# 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à! 

Ahora tanto http://example.com como https://example.com deberían redirigir a https://www.example.com . Básicamente, esta configuración redirige todo lo que no sea www y / o no https a https: // www .

aaronlhe
fuente
-1

Para redirigir todas las solicitudes a https://www.example

cree un bloque de servidor para la redirección y el dominio primario en su puerto SSL (generalmente 443), así como el puerto HTTP predeterminado 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
}

guardar y seguir con sudo nginx -s reload

Esto redirigirá

http://example      301 -> https://www.example
https://example     301 -> https://www.example
http://www.example  301 -> https://www.example
https://www.example 200
lfender6445
fuente
Te falta un ;en el segundo bloque de servidor en la cláusula if. Debería serreturn 301 https://www.example.com$request_uri;
Lukas Oppermann
1
Sin embargo, ¿funcionaría eso? ¿Puede escuchar httpel 443?
Lukas Oppermann
tienes razón, me falta escuchar 80, lo he agregado.
lfender6445