2010-10-08 17 views

Respuesta

28

¿Por qué es algo así útil? A primera vista, no estaba seguro de si podría hacerse. Pero presentó una pregunta interesante.

Puede tratar de poner una declaración de redirección en su archivo de configuración y reiniciar su servidor. Pueden ocurrir dos posibilidades:

  1. El servidor emitirá la redirección, lo que parezca querer.
  2. El servidor primero hará el intercambio https, y ENTONCES emitirá el redireccionamiento, en cuyo caso, ¿cuál es el punto?

Agregará más si se me ocurre algo más concreto.

ACTUALIZACIÓN:(un par de horas más tarde) usted podría intentar esto. Es necesario poner esto en su archivo nginx.conf -

server { 
     listen 443; 
     server_name _ *; 
     rewrite ^(.*) http://$host$1 permanent; 
} 

envía una redirección permanente al cliente. Supongo que está utilizando el puerto 443 (predeterminado) para https.

server { 
    listen  80; 
    server_name _ *; 
    ... 
} 

Añadir esta para que sus peticiones normales HTTP en el puerto 80 no se ven afectadas.

ACTUALIZACIÓN:18o Dic el año 2016 - server_name _ se debe utilizar en lugar de server_name _ * en versiones nginx> 0.6.25 (gracias a @Luca Steeb)

+2

respuesta Viejo pero sólo quiero decir que es útil debido a la regla de "contenido no seguro" hoy en día. Cuando se utiliza un iframe, por ejemplo. –

+1

Otro uso es cuando está entregando un conjunto de 404 páginas "discontinuadas" para múltiples dominios a través de hosts virtuales. No es necesario servir el tráfico cifrado real, y no es (fácilmente) posible poner certs válidos en cada dominio. –

+5

Otra razón por la que sería útil: tengo un servidor que aloja varios dominios. Uno de ellos tiene SSL, pero los otros dominios no tienen certificados SSL.Cuando alguien va a esos otros dominios a través de HTTPS, necesita redireccionar a HTTP –

6
location/{ 
    if ($scheme = https) { 
     rewrite ^(.*)? http://$http_host$1 permanent; 
    } 
} 
+0

puede necesitar agregue un indicador de ubicación que abarque más que/si desea asegurarse de que todo coincida. Pero la respuesta con el servidor es probablemente la mejor para ser honesto. ¿Cómo se manejan los fantasmas de todos modos? – ansiart

0

La única regla simple ya se explicó en la publicación sobre mí:

server { 
    listen ip:443; 
    server_name www.example.com; 
    rewrite ^(.*) http://$host$1 permanent; 
} 
3

esta pregunta se habría adaptado mejor al sitio serverfault.com.

Una mejor manera de hacer la redirección a http:

server { 
    listen 443; 
    return 301 http://$host$request_uri; 
} 

Esto evita tanto el 'si' cláusula y la expresión regular en la reescritura que son características de las otras soluciones hasta la fecha. Ambos tienen implicaciones de rendimiento, aunque en la práctica tendrías que tener bastante tráfico antes de que importara.

Dependiendo de su configuración, es probable que también desee especificar una IP en la cláusula de escucha, y tal vez una cláusula de servidor en el anterior. Como es, se aplicará a todas las solicitudes del puerto 443 para todos los nombres de dominio. Por lo general, desea una IP por dominio con https, por lo que vincular lo anterior a una IP es más importante que vincularlo a un nombre de dominio, pero hay variaciones en eso, por ejemplo, donde todos los dominios son subdominios de un dominio.

EDITAR: TLS es casi universal ahora, y con él Server Name Identification (SNI) que permite sitios HTTPS en múltiples dominios que comparten una sola IP.Hay un buen informe here

26

rewrite y if se deben evitar con Nginx. La famosa línea es "Nginx no es Apache": en otras palabras, Nginx tiene mejores formas de manejar URL que reescribir. return sigue siendo técnicamente parte del módulo de reescritura, pero no tiene la sobrecarga de rewrite, y no está tan limitado como if.

Nginx tiene toda una página en why if is "evil". También proporciona una página constructiva que explica why rewrite and if are bad, y cómo puede evitarlo. Esto es lo que la página tiene que decir sobre rewrite y if:

This is a wrong, cumbersome, and ineffective way.

puede resolver este problema de manera adecuada utilizando return:

server { 
    listen 443 ssl; 

    # You will need a wildcard certificate if you want to specify multiple 
    # hostnames here. 
    server_name domain.example www.domain.example; 

    # If you have a certificate that is shared among several servers, you 
    # can move these outside the `server` block. 
    ssl_certificate /path/to/cert.pem; 
    ssl_certificate_key /path/to/cert.key; 

    # 301   indicates a permanent redirect. If your redirect is 
    #    temporary, you can change it to 302 or omit the number 
    #    altogether. 
    # $http_host is the hostname and, if applicable, port--unlike $host, 
    #    which will break on non-standard ports 
    # $request_uri is the raw URI requested by the client, including any 
    #    querystring 
    return 301 http://$http_host$request_uri; 
} 

Si esperas un montón de robots que no envíe una cabecera Host , puede usar $host en lugar de $http_host, siempre y cuando se adhiera a los puertos 80 y 443. De lo contrario, deberá llenar dinámicamente un sustituto $http_host. Este código es eficiente y seguro siempre que aparezca en la raíz de server (en lugar de en un bloque location), a pesar de usar if. Sin embargo, necesitaría usar un servidor predeterminado para que esto sea aplicable, lo que debería evitarse con https.

set $request_host $server_name:$server_port; 
if ($http_host) { 
    set $request_host $http_host; 
} 

Si desea utilizar SSL/TLS para rutas específicas, pero prohibir que de otro modo:

server { 
    listen 443 ssl; 
    server_name domain.example; 

    ssl_certificate /path/to/cert.pem; 
    ssl_certificate_key /path/to/cert.key; 

    location/{ 
     return 301 http://$host$request_uri; 
    } 

    location /secure/ { 
     try_files $uri =404; 
    } 
} 

server { 
    listen 80; 
    server_name domain.example; 

    location/{ 
     try_files $uri =404; 
    } 

    location /secure/ { 
     return 301 https://$http_host$request_uri; 
    } 
} 

Si el servidor no está en comunicación directa con el cliente - por ejemplo, si está usando CloudFlare: las cosas se complican un poco. Deberá asegurarse de que cualquier servidor en comunicación directa con el cliente agregue un encabezado X-Forwarded-Proto apropiado a la solicitud.

Usar esto es una proposición desordenada; para una explicación completa, vea IfIsEvil. Para que esto sea útil, el bloque if no puede estar dentro de un bloque location, por una variedad de razones complejas. Esto fuerza el uso de rewrite para la prueba de URI. En resumen, si tiene que usar esto en un servidor de producción ... no lo haga. Piénselo de esta manera: si ha superado a Apache, ha superado esta solución.

/secure,/secure /, y cualquier elemento en/secure/forzará https, mientras que el resto de los URI harán cumplir http. La construcción PCRE (?! ) es negative lookahead assertion. (?: ) es un non-capturing group.

server { 
    # If you're using https between servers, you'll need to modify the listen 
    # block and ensure that proper ssl_* statements are either present or 
    # inherited. 
    listen 80; 
    server_name domain.example; 

    if ($http_x_forwarded_proto = https) { 
     rewrite ^(?!/secure)/ http://$http_host$request_uri? permanent; 
    } 
    if ($http_x_forwarded_proto != https) { 
     rewrite ^/secure(?:/|$) https://$http_host$request_uri? permanent; 
    } 
} 
+2

Ok, entonces, si lo entiendo correctamente, no hay forma de servir por encima de http a un cliente que solicita https sin establecer primero una conexión https. Entonces, ¿necesita certs si quiere mover personas de https a http? – Freek

+1

@Freek Correcto, aunque siempre debe admitir HTTPS; es una característica de seguridad bastante básica pero eficaz, y cualquier usuario que se preocupe por sus contraseñas lo querrá. Puede obtener un certificado gratis de [Let's Encrypt] (https://letsencrypt.org/). Incluso si su sitio web no contiene información confidencial, podría usarse como un vector de ataque. – Zenexer

+0

Si está detrás de un Elastic Load Balancer que 'elimina el s' (https -> http), la única solución que funciona es con if ($ http_x_forwarded_proto = https) ... – jmcollin92

0

Esto me ayudó:

server { 
    listen 443; 
    server_name server.org www.server.org; 
    rewrite^http://$server_name$request_uri? permanent; 
} 
Cuestiones relacionadas