Tratar con nginx 400 "La solicitud HTTP simple se envió al puerto HTTPS" error


115

Estoy ejecutando una aplicación Sinatra detrás de pasajeros / nginx. Estoy tratando de que responda a las llamadas http y https. El problema es que cuando ambos están definidos en el bloque del servidor, las llamadas https se responden normalmente, pero http produce un error de 400 "La solicitud HTTP simple se envió al puerto HTTPS". Esto es para una página estática, así que supongo que Sinatra no tiene nada que ver con esto. ¿Alguna idea sobre cómo solucionar este problema?

Aquí está el bloque del servidor:

server {
        listen 80;
        listen 443  ssl;
        server_name localhost;
        root /home/myhome/app/public;
        passenger_enabled on;

        ssl on;
        ssl_certificate      /opt/nginx/ssl_keys/ssl.crt;
        ssl_certificate_key  /opt/nginx/ssl_keys/ssl.key;
        ssl_protocols        SSLv3 TLSv1;
        ssl_ciphers          HIGH:!aNULL:!MD5;

        location /static {
            root  /home/myhome/app/public;
            index  index.html index.htm index.php;
        }

        error_page 404 /404.html;

        # redirect server error pages to the static page /50x.html
        error_page 500 /500.html;

        access_log /home/myhome/app/logs/access.log;
        error_log /home/myhome/app/logs/error.log;
}

En mi caso fue que la URL en el navegador: my.example.com:443no funcionó. Cambiar eso en cambio a https://my.example.comfuncionó. Extraño, nunca tuve este problema con apache.
Sebastian

1
ssl on;le dice a NGINX que sirva CUALQUIER contenido a través de SSL. Utilice el indicador "ssl" al final de su, listen 443;por ejemplo, listen 443 ssl;si su servidor entrega tráfico tanto http como https, y elimine la ssl on;directiva.
Stphane

Respuestas:


195

Me encontré con un problema similar. Funciona en un servidor y no en otro servidor con la misma configuración de Nginx. Encontré la solución que Igor responde aquí http://forum.nginx.org/read.php?2,1612,1627#msg-1627

Si. O puede combinar servidores SSL / no SSL en un servidor:

server {
  listen 80;
  listen 443 default ssl;

  # ssl on   - remember to comment this out

}

Según lo que dice rapam iosif, asegúrese de incluir tambiénssl off;
aceofspades

20
Solo necesita eliminar la línea ssl on;(no es necesario agregar ssl off). Además, como no recuerdo qué versión de Nginx, ya no es necesario usarla defaulten listen 443línea. Entonces, la configuración de OP estaba bien, solo es necesario eliminarla ssl ony debería funcionar.
Laurent

@bobojam no dude en incluir la explicación de mi respuesta, para que la suya sea más completa. Le pedí al autor de OP que aceptara su respuesta.
Alexander Azarov

2
¿Cómo resuelve el propósito de SSL comentando ssl on? La respuesta de @ MichaelJ.Evans a continuación es una solución mucho mejor.
Neel

1
No parece funcionar con varios archivos conf. Dice que hay 2 valores predeterminados duplicados. Usa la solución de Alexander.
Ryall

39

Las respuestas anteriores son incorrectas en el sentido de que la mayoría anula la prueba "es esta conexión HTTPS" para permitir el servicio de las páginas a través de http independientemente de la seguridad de la conexión.

La respuesta segura usando una página de error en un código de error http 4xx específico de NGINX para redirigir al cliente a reintentar la misma solicitud a https. (como se describe aquí /server/338700/redirect-http-mydomain-com12345-to-https-mydomain-com12345-in-nginx )

El OP debe usar:

server {
  listen        12345;
  server_name   php.myadmin.com;

  root         /var/www/php;

  ssl           on;

  # If they come here using HTTP, bounce them to the correct scheme
  error_page 497 https://$host:$server_port$request_uri;

  [....]
}

1
Probablemente desee $ server_name en lugar de $ host, el server_name presumiblemente se establece en el CN ​​que autentica el certificado SSL. De esa manera, el usuario no obtendrá una pantalla de miedo si ingresó a través de una IP o localhost.
George

Estaba tratando de implementar esto en mi instalación local de GitLab , pero utilicé la configuración de inserción de NGINX personalizada en el método de bloque del servidor de GitLab , por lo que nginx['custom_gitlab_server_config'] = "error_page 497 https://$host:$server_port$request_uri;"funcionó
Aaron C

17

El error lo dice todo en realidad. Su configuración le dice a Nginx que escuche en el puerto 80 (HTTP) y use SSL. Cuando apunta su navegador http://localhost, intenta conectarse a través de HTTP. Dado que Nginx espera SSL, se queja del error.

La solución alternativa es muy sencilla. Necesitas dos serversecciones:

server {
  listen 80;

  // other directives...
}

server {
  listen 443;

  ssl on;
  // SSL directives...

  // other directives...
}

7
En realidad, no necesita dos secciones de servidor. Elimine la línea "ssl on" y cambie las líneas de escucha según la respuesta de @ bobojam.
toxaq

12

Tuve exactamente el mismo problema, tengo la misma configuración que su ejemplo y lo hice funcionar eliminando la línea:

ssl on;

Para citar el doc:

Si los servidores HTTP y HTTPS son iguales, se puede configurar un solo servidor que maneje las solicitudes HTTP y HTTPS eliminando la directiva "ssl on" y agregando el parámetro ssl para el puerto *: 443


1
¿Alguna posibilidad de que tengas el enlace al documento?
Adam Parkin

12

Según el artículo de wikipedia sobre códigos de estado . Nginx tiene un código de error personalizado cuando se envía tráfico http al puerto https (código de error 497)

Y de acuerdo con nginx docs en error_page , puede definir un URI que se mostrará para un error específico.
Por lo tanto, podemos crear una uri a la que se enviarán los clientes cuando se genere el código de error 497.

nginx.conf

#lets assume your IP address is 89.89.89.89 and also 
#that you want nginx to listen on port 7000 and your app is running on port 3000

server {
    listen 7000 ssl;
 
    ssl_certificate /path/to/ssl_certificate.cer;
    ssl_certificate_key /path/to/ssl_certificate_key.key;
    ssl_client_certificate /path/to/ssl_client_certificate.cer;

    error_page 497 301 =307 https://89.89.89.89:7000$request_uri;

    location / {
        proxy_pass http://89.89.89.89:3000/;

        proxy_pass_header Server;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
}

Sin embargo, si un cliente realiza una solicitud a través de cualquier otro método que no sea GET, esa solicitud se convertirá en un GET. Por lo tanto, para preservar el método de solicitud por el que entró el cliente; usamos redirecciones de procesamiento de errores como se muestra en los documentos de nginx en error_page

Y es por eso que usamos la 301 =307redirección.

Usando el archivo nginx.conf que se muestra aquí, podemos hacer que http y https escuchen en el mismo puerto


esto funciona para mí - error_page 497 301 = 307 89.89.89.89:7000$request_uri ;
ugali soft

7

Aquí hay un ejemplo para configurar HTTP y HTTPS en el mismo bloque de configuración con soporte para ipv6 . La configuración se prueba en Ubuntu Server y NGINX / 1.4.6, pero debería funcionar con todos los servidores.

server {
    # support http and ipv6
    listen 80 default_server;
    listen [::]:80 default_server ipv6only=on;

    # support https and ipv6
    listen 443 default_server ssl;
    listen [::]:443 ipv6only=on default_server ssl;

    # path to web directory
    root /path/to/example.com;
    index index.html index.htm;

    # domain or subdomain
    server_name example.com www.example.com;

    # ssl certificate
    ssl_certificate /path/to/certs/example_com-bundle.crt;
    ssl_certificate_key /path/to/certs/example_com.key;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
    ssl_prefer_server_ciphers on;
}

No incluya lo ssl onque pueda causar un 400error. La configuración anterior debería funcionar para

http://example.com

http://www.example.com

https://example.com

https://www.example.com

¡Espero que esto ayude!



4

De hecho, puedes hacer esto con:

ssl off; 

Esto resolvió mi problema al usar nginxvhosts; ahora puedo usar SSL y HTTP simple. Funciona incluso con puertos combinados.


Funciona para mí en nginx / 1.6.3 :)
djthoms
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.