Nginx 代理返回二进制数据

Nginx 代理返回二进制数据

我在应用程序前面使用 nginx 作为代理来终止 TLS。我已将其设置为监听端口 80 并重定向到 443。

最初,Chromium 会下载一个名为“download”的文件,而不是重定向,但由于某种原因,它不再这样做了(我尝试了这个问题但这并没有帮助)。尽管问题显然仍然存在,但 Chromium 可以正确重定向,而 Firefox 仍然会对此做出反应,认为这是一个文件下载:

Firefox 提供下载二进制数据

该问题在 curl 中最明显:

curl -v http://example.com
* Rebuilt URL to: http://example.com/
*   Trying 54.213.157.146...
* Connected to example.com (54.213.157.146) port 80 (#0)
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.50.0
> Accept: */*
> 
* Connection #0 to host example.com left intact
����

它似乎没有返回通常的标头/状态/等,而是返回了二进制数据。同时,https 版本似乎可以正常工作:

curl -v https://example.com
* Rebuilt URL to: https://example.com/
*   Trying 54.213.157.146...
* Connected to example.com (54.213.157.146) port 443 (#0)
* ALPN, offering http/1.1
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.2 (OUT), TLS header, Certificate Status (22):
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use http/1.1
* Server certificate:
*  subject: CN=example.com
*  start date: Jul 29 18:50:00 2016 GMT 
*  expire date: Oct 27 18:50:00 2016 GMT 
*  subjectAltName: host "example.com" matched cert's "example.com"
*  issuer: C=US; O=Let's Encrypt; CN=Let's Encrypt Authority X3
*  SSL certificate verify ok. 
> GET / HTTP/1.1
> Host: example.com
> User-Agent: curl/7.50.0
> Accept: */* 
> 
< HTTP/1.1 200 OK
< Server: nginx/1.11.1
< Date: Fri, 29 Jul 2016 22:53:33 GMT 
< Content-Type: text/html; charset=utf-8
< Content-Length: 1121
< Connection: keep-alive
< X-Powered-By: Express
< ETag: W/"461-VBuWbiWQQ/3ptwQjG8pM3w"
< Strict-Transport-Security: max-age=63072000; includeSubdomains; preload
< X-Frame-Options: SAMEORIGIN
< X-Content-Type-Options: nosniff
< 
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
...

显然我的 nginx 配置错误,但我不清楚具体原因。

我的nginx.conf:

user nginx;
worker_processes 2;

events {
    worker_connections  8096;
    multi_accept        on;
    use                 epoll;
}

http {
  include mime.types;
  default_type application/octet-stream;

  proxy_cache_path /var/cache/nginx keys_zone=anonymous:10m;
  proxy_temp_path /var/tmp/nginx;

  sendfile on;
  client_max_body_size 20M;
  tcp_nodelay off;
  tcp_nopush on;
  keepalive_timeout 65;

  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  map $http_upgrade $connection_upgrade {
      default upgrade;
      ''      close;
  }

  #Include the vhost files.
  include vhosts/*.conf;
}

以及 vhosts 文件:

server {
  listen 80 http2;
  server_name ${DOMAIN};
  return 301 https://$server_name$request_uri;
}

server {
  listen 443 ssl http2;
  server_name ${DOMAIN};

  ssl_certificate /etc/letsencrypt/live/${PATH}/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/${PATH}/privkey.pem;
  ssl_dhparam /etc/ssl/dhparams.pem;

  ssl_ciphers "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA";
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_prefer_server_ciphers on;
  ssl_session_cache shared:SSL:10m;
  add_header Strict-Transport-Security "max-age=63072000; includeSubdomains; preload" always;
  add_header X-Frame-Options SAMEORIGIN;
  add_header X-Content-Type-Options nosniff;
  ssl_session_tickets off;
  ssl_stapling on;
  ssl_stapling_verify on;

  root /etc/letsencrypt/webrootauth;

  location / {
    proxy_pass http://${UPSTREAM};
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_cache   anonymous;
    proxy_cache_valid 200 301 302 30m;
    expires 30m;
    proxy_buffering off;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $http_connection;      
  }

  location ~* \.(html|css|jpg|gif|ico|js)$ {
    proxy_cache          cache;
    proxy_cache_key      $host$uri$is_args$args;
    proxy_cache_valid    200 301 302 30m;
    expires              30m;
    proxy_pass  http://backend;
  }

  location /.well-known/acme-challenge {
    alias /etc/letsencrypt/webrootauth/.well-known/acme-challenge;
    location ~ /.well-known/acme-challenge/(.*) {
      add_header Content-Type application/jose+json;
    }
  }
}

有谁知道这是什么原因造成的吗?

答案1

您使用的 http2 指令意味着该端口具有 SSL 支持(没有 SSL 它就无法工作),因此您看到的二进制数据实际上是 nginx 尝试在没有任何证书的情况下通过端口 80 进行安全通信。

您可以使用以下方法验证:

curl --tlsv1.2 https://your-domain-name.is:80

这将为你带来:

curl: (35) error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol

而其他任何服务器都会给你

curl: (35) Unknown SSL protocol error in connection to example.com:80

从端口 80 删除 http2 指令(并将其放到端口 443)

如果您坚持将 http2 指令保留在端口 80 上,至少将所有与 ssl 相关的参数添加到该部分,这样您就可以使用 ssl 进行通信https://your-domain-name.is:80(开个玩笑......)

相关内容