web-dev-qa-db-ja.com

Nginx:broken_headerとproxy_protocolおよびELB

Nginx設定でproxy_protocolを設定しようとしています。私のサーバーはAWSロードバランサー(ELB)の背後にあり、ポート80と443の両方でプロキシプロトコルを有効にしています。

しかし、これは私がサーバーにアクセスしたときに得られるものです。

broken header: "��/��
                                                             '���\DW�Vc�A{����
                                                                              �@��kj98���=5���g@32ED�</A
    " while reading PROXY protocol, client: 172.31.12.223, server: 0.0.0.0:443

これは、nginxエラーログからの直接のコピーペーストです。

これが私のnginx設定からの抜粋です:

server {
  listen  80 proxy_protocol;
  set_real_ip_from 172.31.0.0/20; # Coming from ELB
  real_ip_header proxy_protocol;
  return  301 https://$http_Host$request_uri;
}

server {
  listen      443 ssl proxy_protocol;
  server_name *.....com
  ssl_certificate      /etc/ssl/<....>;
  ssl_certificate_key  /etc/ssl/<....?;
  ssl_prefer_server_ciphers On;
  ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
  ssl_ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!DSS:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4;
  ssl_session_cache shared:SSL:10m;
  add_header X-Frame-Options DENY;
  add_header X-Content-Type-Options nosniff;
  ssl_stapling on;
  ssl_stapling_verify on;


  ...

この問題についてオンラインでヘルプが見つかりません。他の人々は壊れたヘッダーの問題を抱えていましたが、悪いヘッダーのエラーは常に判読可能です-彼らは私にとってのようにエンコードされているようには見えません。

何か案は?

13
Scott Hillman

2つの提案:

  1. ELBリスナーがプロトコルとしてTCPを使用し、HTTPではなく使用するように構成されていることを確認します。proxy_protocolが構成されたNginxにルーティングする次のようなLB構成があります。

    {
      "LoadBalancerName": "my-lb",
      "Listeners": [
         {
          "Protocol": "TCP",
          "LoadBalancerPort": 80,
          "InstanceProtocol": "TCP",
          "InstancePort": 80
        }
      ],
      "AvailabilityZones": [
        "us-east-1a",
        "us-east-1b",
        "us-east-1d",
        "us-east-1e"
      ],
      "SecurityGroups": [
         "sg-mysg"
      ]
    }
    
  2. ELBでプロキシプロトコルを有効にしたとのことですが、私は AWSセットアップ手順 に従っていると想定しています。その場合、ELBは最初の行をPROXY TCP4 198.51.100.22 203.0.113.7 35646 80\r\nのようなものとしてHTTPリクエストを正しく作成する必要があります。ただし、HTTPリクエストがPROXY ...行でNginxに送信されない場合は、表示されている問題が発生する可能性があります。ブラウザでEC2 DNS名に直接アクセスするか、EC2インスタンスにsshしてcurl localhostなどを試すと、Nginxログに同様の壊れたヘッダーエラーが表示されることを再現できます。

正しく形成されたHTTPリクエストで動作するかどうかを確認するには、telnetを使用できます。

    $ telnet localhost 80
    PROXY TCP4 198.51.100.22 203.0.113.7 35646 80
    GET /index.html HTTP/1.1
    Host: your-nginx-config-server_name
    Connection: Keep-Alive

次に、Nginxログを確認して、同じ壊れたヘッダーエラーがあるかどうかを確認します。そうでない場合、ELBは適切にフォーマットされたPROXYリクエストを送信していない可能性が高いので、ELBプロキシプロトコルの構成を(おそらく新しいLBで)再実行して、正しくセットアップされていることを確認することをお勧めします。

11
Stephen Karger

私はこのエラーを抱えていて、このチケットに出くわしました:

最終的に、私は不要なproxy_protocol宣言nginx.confファイル。私はそれを削除し、すべてが再び機能していました。

奇妙なことに、nginxバージョン1.8.0、ただしnginxバージョンにアップグレードした場合1.8.1は、エラーが発生し始めたときです。

0
Troy Grosfield

上記のStephen Kargerのソリューションは正しいです。ELBがプロキシをサポートするように設定するように調整する必要があります。これを正確に実行するためのAWSドキュメントは次のとおりです: http://docs.aws.Amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/enable-proxy-protocol.html 。ドキュメントは最初は少し難しいので、必要に応じて、Enable Proxy Protocol Using the AWS CLIセクションのステップ3と4にスキップできます。これらは、プロキシチャネリングを有効にするために必要な唯一の手順です。さらに、Stephenが示唆したように、ELBがTCPまたはhttpではなくhttpsを使用していることを確認する必要があります。これらはどちらもELBのプロキシ実装では正しく動作しないためです。 。ソケットチャネルを80や443などの一般的なポートから遠ざけることをお勧めします。これにより、標準化された接続をデフォルトの動作で維持できます。もちろん、その呼び出しを行うかどうかは、アプリスタックの外観に完全に依存します。

それが役立つ場合は、npmパッケージwscatを使用して、次のようにWebSocket接続をデバッグできます。

$ npm install -g wscat
$ wscat --connect 127.0.0.1

接続がローカルで機能する場合、それは確かにロードバランサーです。ただし、そうでない場合は、ソケットホストにほぼ間違いなく問題があります。

さらに、nmapのようなツールは、開いているポートを見つけるのに役立ちます。デバッグのための素晴らしいチェックリスト:

npm install -g wscat
# can you connect to it from within the server?
ssh [email protected]
wscat -c 127.0.0.1:80
# can you connect to it from outside the server?
exit
wscat -c 69.69.69.69:80
# if not, is your socket port open for business?
nmap 69.69.69.69:80

サーバー内からnmapを使用して、開いているポートを検出することもできます。 nmapをubuntuにインストールするには、単にSudo apt-get install nmapと入力します。 osx、brew install nmap

現時点ではsslサポートを提供していませんが、ここに私が持っている動作設定があります。この構成では、ポート80にフィードRails app、port 81ソケット接続をelb経由でフィードし、ポート82内部ソケット接続用に開いています。これが誰かに役立つことを願っています! !Rails、Unicorn、Fayeを使用してデプロイする人なら誰でも、これが役立つはずです:)幸せなハッキング!

# sets up deployed Ruby on Rails server
upstream Unicorn {
  server unix:/path/to/Unicorn/unicorn.sock fail_timeout=0;
}

# sets up Faye socket
upstream rack_upstream {
  server 127.0.0.1:9292;
}

# sets port 80 to proxy to Rails app
server {
  listen 80 default_server;
  keepalive_timeout 300;
  client_max_body_size 4G;
  root /path/to/Rails/public;
  try_files $uri/index.html $uri.html $uri @Unicorn;

  location @Unicorn {
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $http_Host;
    proxy_set_header X-Forwarded_Proto $scheme;
    proxy_redirect off;
    proxy_pass http://Unicorn;
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
  }

  error_page 500 502 503 504 /500.html;
  location = /500.html {
    root /path/to/Rails/public;
  }
}

# open 81 to load balancers (external socket connection)
server {
  listen 81 proxy_protocol;
  server_name _;
  charset UTF-8;
  location / {
    proxy_pass http://rack_upstream;
    proxy_redirect off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}

# open 82 to internal network (internal socket connections)
server {
  listen 82;
  server_name _;
  charset UTF-8;
  location / {
    proxy_pass http://rack_upstream;
    proxy_redirect off;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }
}
0
avocadojesus

私もこの読み取り不可能なヘッダーの問題を取得しました。原因と修正方法を以下に示します。

私の場合、Nginxはuse-proxy-protocol=true正しく。 AWS ELBが必要なヘッダーを追加しなかったという理由だけで壊れたヘッダーについて文句を言う(例:PROXY TCP4 198.51.100.22 203.0.113.7 35646 80)まったく。 Nginxは暗号化されたHTTPSペイロードを直接参照します。これが、読み取り不可能な文字をすべて出力する理由です。

では、なぜAWS ELBはPROXYヘッダーを追加しなかったのですか?コマンドで間違ったポートを使用してプロキシプロトコルポリシーを有効にしたことがわかりました。 80と443の代わりにインスタンスポートを使用する必要があります。

ELBには次のポートマッピングがあります。

80 -> 30440
443 -> 31772

コマンドは

aws elb set-load-balancer-policies-for-backend-server \
  --load-balancer-name a19235ee9945011e9ac720a6c9a49806 \
  --instance-port 30440 \
  --policy-names ars-ProxyProtocol-policy

aws elb set-load-balancer-policies-for-backend-server \
  --load-balancer-name a19235ee9945011e9ac720a6c9a49806 \
  --instance-port 31272 \
  --policy-names ars-ProxyProtocol-policy

誤って80と443を使用しました。

これが誰かを助けることを願っています。

0
Yuping Jin