处理nginx 400“普通HTTP请求已发送到HTTPS端口”错误


115

我正在旅客/ nginx后面运行Sinatra应用程序。我正在尝试使其同时响应http和https调用。问题是,当在服务器块中同时定义了两者时,通常会响应https调用,但是http会产生400“普通HTTP请求已发送到HTTPS端口”错误。这是用于静态页面的,所以我猜测Sinatra与这无关。有想法该怎么解决这个吗?

这是服务器块:

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;
}

在我的情况下,浏览器中的网址:my.example.com:443不起作用。改为改为https://my.example.com工作。很奇怪,Apache从来没有遇到过这个问题。
塞巴斯蒂安

1
ssl on;告诉NGINX 通过SSL 服务器任何内容。在您的末尾使用“ ssl”标志,listen 443;例如,listen 443 ssl;如果您的服务器同时传递http和https流量,并删除ssl on;指令。
斯特凡

Answers:


195

我遇到了类似的问题。它可以在一台服务器上运行,而不能在具有相同Nginx配置的另一台服务器上运行。在这里找到了Igor回答的解决方案http://forum.nginx.org/read.php?2,1612,1627#msg-1627

是。或者,您可以将SSL /非SSL服务器合并在一台服务器中:

server {
  listen 80;
  listen 443 default ssl;

  # ssl on   - remember to comment this out

}

根据rapam iosif所说的,请确保您还包括ssl off;
aceofspades 2012年

20
您只需要删除该行即可ssl on;(无需添加ssl off)。此外,由于我不记得哪Nginx的版本,有没有更需要利用defaultlisten 443线。因此,OP配置没问题,只需要删除ssl on就可以了。
劳伦特

@bobojam随时附上我的答复中的解释,以使您的答复更加完整。我已要求OP作者接受您的回答。
亚历山大·阿扎罗夫

2
如何通过注释解决SSL的目的ssl on。@ MichaelJ.Evans下面的答案是一个更好的解决方案。
Neel 2014年

1
似乎不适用于多个conf文件。说有两个重复的默认值。使用亚历山大的解决方案。
Ryall

39

上面的答案是错误的,因为大多数情况下都超过了“此连接是HTTPS”测试,以允许通过http服务页面,而不考虑连接安全性。

使用NGINX特定的http 4xx错误代码上的错误页面来重定向客户端以将相同请求重试到https的安全答案。(如此处概述/server/338700/redirect-http-mydomain-com12345-to-https-mydomain-com12345-in-nginx

OP应使用:

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
您可能希望使用$ server_name而不是$ host,大概将server_name设置为SSL证书进行身份验证的CN。这样,如果用户通过IP或本地主机进入,则不会出现吓人的画面。
乔治,

我试图在本地安装的GitLab上实现此功能,但使用了将自定义NGINX设置插入GitLab服务器块方法中的方法,从而达到nginx['custom_gitlab_server_config'] = "error_page 497 https://$host:$server_port$request_uri;"了目的
Aaron C

17

该错误实际上说明了一切。您的配置告诉Nginx监听端口80(HTTP)并使用SSL。当您将浏览器指向时http://localhost,它会尝试通过HTTP连接。由于Nginx需要SSL,因此会报错。

解决方法非常简单。您需要两个server部分:

server {
  listen 80;

  // other directives...
}

server {
  listen 443;

  ssl on;
  // SSL directives...

  // other directives...
}

7
您实际上不需要两个服务器部分。删除“ ssl on”行,并根据@bobojam的答案更改监听行。
toxaq 2012年

12

我遇到了完全相同的问题,我的配置与您的示例相同,并且通过删除以下行使其工作:

ssl on;

引用文档:

如果HTTP和HTTPS服务器相等,则可以通过删除指令“ ssl on”并为*:443端口添加ssl参数来配置处理HTTP和HTTPS请求的单个服务器。


1
您有机会链接到doc吗?
亚当·帕金

12

根据维基百科有关状态码的文章。将HTTP流量发送到https端口时,Nginx具有自定义错误代码(错误代码497)

根据error_page上的nginx文档,您可以定义将针对特定错误显示的URI。
因此,我们可以创建一个uri,将在引发错误代码497时将客户端发送到该uri。

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;
    }
}

但是,如果客户端通过除GET之外的任何其他方法发出请求,则该请求将转换为GET。从而保留客户端通过的请求方法;我们使用错误处理重定向,如error_page上的nginx文档所示

这就是为什么我们使用301 =307重定向。

使用此处显示的nginx.conf文件,我们可以使http和https在同一端口上侦听


这对我有用-error_page 497 301 = 307 89.89.89.89:7000$request_uri ;
ugali soft

7

这是在具有ipv6支持的同一配置块中配置HTTPHTTPS的示例。该配置已在Ubuntu ServerNGINX / 1.4.6中进行了测试,但这适用于所有服务器。

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;
}

不包括ssl on可能导致400错误的内容。上面的配置应该适用于

http://example.com

http://www.example.com

https://example.com

https://www.example.com

希望这可以帮助!



4

实际上,您可以执行以下操作:

ssl off; 

这解决了我使用nginxvhosts的问题;现在,我可以同时使用SSL和纯HTTP。即使与组合的端口一起工作。


在nginx / 1.6.3上为我工作:)
djthoms
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.