Pregunta En Nginx, ¿cómo puedo reescribir todas las solicitudes http a https mientras mantengo un subdominio?


Quiero volver a escribir todas las solicitudes http en mi servidor web para que sean solicitudes https. Comencé con lo siguiente:

servidor {
    escucha 80;

    ubicación / {
      reescribir ^ (. *) https: //misitio.com$1 permanente;
    }
...


Un problema es que esto elimina cualquier información de subdominio (por ejemplo, node1.mysite.com/folder), ¿cómo podría reescribir lo anterior para redirigir todo a https y mantener el subdominio?


495
2017-09-21 14:04


origen


Por favor considere mover la 'respuesta aceptada' a serverfault.com/a/171238/90758. Esa es la correcta. - olafure
Simplemente use $ server_name en lugar de mysite.com codificado - Fedir RYKHTIK


Respuestas:


Manera correcta en las nuevas versiones de nginx.

En un momento dado, mi primera respuesta a esta pregunta fue correcta, pero se convirtió en otra trampa: para estar al día, consulte Gravar los errores de reescritura

Muchos usuarios de SE me han corregido, por lo que el crédito va para ellos, pero lo más importante es que aquí está el código correcto:

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

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000" always; 

       [....]
}

737
2017-12-05 20:43



Tendría que hacer esto en una base de dominio por dominio, sin embargo, ¿no? ¿Qué sucede si desea aplicarla a todos los dominios de su servidor? - JM4
@ JM4: si usa $ host $ en la reescritura en lugar de server_name y agrega default_server a la directiva de escucha, funcionará para todos los dominios de su servidor. - Klaas van Schelven
Es importante mencionar que el 301 se almacena en su caché local sin fecha de caducidad. No es muy útil cuando la configuración cambia. - Trefex
@everyone Use un redireccionamiento 307 para conservar el contenido POST. - Mahmoud Al-Qudsi
Tenga en cuenta que debe utilizar $host en lugar de $server_name si estas usando subdominios - Catfish


NOTA: La mejor manera de hacerlo fue proporcionada por https://serverfault.com/a/401632/3641 - pero se repite aquí:

server {
    listen         80;
    return 301 https://$host$request_uri;
}

En el caso más simple, se arreglará su host para que sea el servicio al que desea enviarlo. Esto hará una redirección 301 al navegador y la URL del navegador se actualizará en consecuencia.

A continuación se muestra la respuesta anterior, que es ineficiente debido a la expresión regular, un simple 301 es excelente como lo muestra @kmindi

He estado usando nginx 0.8.39 y superior, y utilicé lo siguiente:

 server {
       listen 80;
       rewrite ^(.*) https://$host$1 permanent;
 }

Envía un redireccionamiento permanente al cliente.


269
2017-08-17 03:07



Creo que deberían ser 80, ya que esto está escuchando http y luego le dice al cliente que vuelva como https (443). - Michael Neale
¡Esta debería ser la mejor respuesta! - Nathan
Esta es la respuesta más exigente. - Case
Este es el más fácil, pero el menos seguro: de esta manera, permite que su servidor redirija a un usuario a cualquier página, sin verificar si está permitido usarlo en su servidor. Si su servidor atiende a mydomain.co, los usuarios malintencionados todavía podrían usar su servidor para redirigir a los usuarios a otros dominios como mydomain.co, como google.com. - friedkiwi
@ cab0lt no hay problema de seguridad aquí. Servir una redirección no presenta un riesgo de seguridad. Si hay requisitos de control de acceso, estos deben verificarse en el punto donde el navegador solicita la nueva URL. El navegador no obtendrá acceso simplemente sobre la base de la redirección, ni tampoco necesita la redirección para solicitar la nueva URL. - mc0e


Creo que la mejor y única manera debería ser usando un HTTP 301 movido permanentemente redirigir así:

server {
    listen         [::]:80;
    return 301 https://$host$request_uri;
}

los HTTP 301 movido permanentemente la redirección también es la más eficiente porque no hay expresiones regulares para evaluar, según lo ya mencionado fallas.


El nuevo HTTP 308 movido permanentemente conserva el método de solicitud y es soportado por los principales navegadores. Por ejemplo, usando 308 evita que los navegadores cambien el método de solicitud POST a GET para la solicitud de redireccionamiento.


Si quieres preservar el nombre de host y el subdominio esta es la forma.

Esta sigue funcionando si no tienes DNS, como también lo estoy usando localmente. Estoy solicitando por ejemplo con http://192.168.0.100/index.php y será redirigido a exactamente https://192.168.0.100/index.php.

yo suelo listen [::]:80 en mi host porque tengo bindv6only ajustado a false, por lo que también se enlaza a ipv4 socket. cambiarlo a listen 80 Si no quieres IPv6 o quieres enlazar en otro lado.

La solución de Saif Bechan utiliza el server_name que en mi caso es localhost pero que no es accesible a través de una red.

La solución de Michael Neale es buena, pero según las fallas, hay una mejor solución con redireccionamiento 301;)


121
2018-06-23 17:19



Bien, intenta citarlo, pero 301 no funciona en HTTPS. - Case
¿qué no funciona? la sección del servidor indicado es para que el tráfico http (sin s) no encriptado se redirija permanentemente al servidor encriptado (esa sección que escucha en 443 (https) no está en la lista) - kmindi
Comprobé que esto funciona muy bien con https y todo - @kmindi actualicé mi respuesta con referencia a la tuya - ¡creo que es la forma correcta y esto sigue apareciendo! Buen trabajo. - Michael Neale
Cuando se utiliza una solicitud de dominio (no IP), no funciona a menos que cambie '[::]: 80' a '80'. - Joseph Lust
Ese podría ser el comportamiento esperado: trac.nginx.org/nginx/ticket/345. Actualicé la respuesta para describir la opción de escuchar. - kmindi


Lo anterior no funcionó con la creación de nuevos subdominios todo el tiempo. p.ej. AAA.example.com BBB.example.com para aproximadamente 30 subdominios.

Finalmente conseguí una configuración trabajando con lo siguiente:

server {
  listen 80;
  server_name _;
  rewrite ^ https://$host$request_uri? permanent;
}
server {
  listen  443;
  server_name example.com;
  ssl on;
  ssl_certificate /etc/ssl/certs/myssl.crt;
  ssl_certificate_key /etc/ssl/private/myssl.key;
  ssl_prefer_server_ciphers       on;
# ...
# rest of config here
# ...
}

17
2018-06-25 04:29



¡gracias! nginx volvería 301 https://*/ o cancela la solicitud prematuramente en las otras respuestas aquí. server_name _; con $host Fue la respuesta que hizo el truco. +1 - zamnuts
¡Este es óptimo! Sin embargo, recomiendo para algunos reemplazar _ con el dominio real, por ej. .domain.com Tenía dos servidores y nginx estaba dirigiendo accidentalmente uno de mis servidores al servidor predeterminado. - zzz
¡Esta es la única respuesta que me funcionó, gracias! - Snowman
Muchas gracias amigo. He intentado muchas de las soluciones, pero no funcionó. Esta solución es impresionante y funcionó para mí. nombre del servidor _; ¿Para qué sirve esto? No lo entendí. Por favor explícame esto. - Pavan Kumar


Dentro del bloque del servidor también puedes hacer lo siguiente:

# Force HTTPS connection. This rules is domain agnostic
if ($scheme != "https") {
    rewrite ^ https://$host$uri permanent;
}

16
2017-07-31 19:50



Esta configuración hizo que mi servidor produjera un bucle de redireccionamiento - Corkscreewe
Tal vez porque hay otro redireccionamiento en su lugar o https no está habilitado en su sitio / aplicación - Oriol
Ninguno de los otros parecía funcionar, excepto este. Usando la versión nginx: nginx / 1.10.0 (Ubuntu) - ThatGuy343
upvoted para https: // $ host $ uri - AMB
¡Este es el camino a seguir si estás detrás de un equilibrador de carga! - Antwan


Publiqué un comentario sobre la respuesta correcta hace mucho, mucho tiempo con una corrección muy importante, pero creo que es necesario resaltar esta corrección en su propia respuesta. Ninguna de las respuestas anteriores es segura de usar si, en algún momento, configuró HTTP de forma no segura y espera contenido del usuario, tiene formularios, alberga una API o ha configurado algún sitio web, herramienta, aplicación o utilidad para comunicarse con su sitio.

El problema se produce cuando un POST La solicitud se realiza a su servidor. Si la respuesta del servidor con un simple 30x redirigir El contenido POST se perderá. Lo que sucede es que el navegador / cliente actualizará la solicitud a SSL pero degradar la POST a un GET solicitud. los POST los parámetros se perderán y se hará una solicitud incorrecta a su servidor.

La solución es simple. Necesitas usar un HTTP 1.1 307 redirigir Esto se detalla en RFC 7231 S6.4.7:

  Note: This status code is similar to 302 (Found), except that it
  does not allow changing the request method from POST to GET.  This
  specification defines no equivalent counterpart for 301 (Moved
  Permanently) ([RFC7238], however, defines the status code 308
  (Permanent Redirect) for this purpose).

La solución, adaptada de la solución aceptada, es utilizar 307 en su código de redireccionamiento:

server {
       listen         80;
       server_name    my.domain.com;
       return         307 https://$server_name$request_uri;
}

server {
       listen         443 ssl;
       server_name    my.domain.com;
       # add Strict-Transport-Security to prevent man in the middle attacks
       add_header Strict-Transport-Security "max-age=31536000"; 

       [....]
}

6
2018-03-19 20:24



Muy, muy, muy, muy manejable. ¡Gracias! - Denis Matafonov


Me las arreglé para hacerlo así:

server {
listen 80;
listen 443 ssl;

server_name domain.tld www.domain.tld;

# global HTTP handler
if ($scheme = http) {
        return 301 https://www.domain.tld$request_uri;
}

# global non-WWW HTTPS handler
if ($http_host = domain.tld){
        return 303 https://www.domain.tld$request_uri;
}
}

https://stackoverflow.com/a/36777526/6076984


4
2018-04-21 18:27



Versión actualizada, sin IF: paste.debian.net/plain/899679 - stamster


Estoy ejecutando ngnix detrás de un AWS ELB. El ELB está hablando con ngnix a través de http. Como el ELB no tiene manera de enviar redirecciones a los clientes, verifico el encabezado y redireccionamiento de Proto X-Forwarded:

if ($http_x_forwarded_proto != 'https') {
    return 301 "https://www.exampl.com";
}

3
2018-01-04 17:09