web-dev-qa-db-ja.com

Nginxの同じ場所を経由するプロキシWebソケットとHTTP

現在、ユーザーは Atmosphere を使用してAngularJS Webサーバーを公開することにより、Web経由でデスクトップアプリに接続できるアプリケーションがあります。デスクトップアプリは現在のユーザーのIPアドレスを公開するので、そのアドレスを持つユーザーは誰でも接続できます。

私のサーバー(example.com)を介してプロキシすることで、このIPをマスクしようとしています。私のサーバーは現在一連のアプリケーション(Ruby on Rails + Elastic Search、Logstash、Kibana-ELK)をホストしており、Nginxクライアントによってプロキシされています。

Node HTTP Proxy(locally))を使用してIPアドレスを正常にマスクするように努力しましたが、今、Nginxを使用しながらそれを機能させようとしています。AngularJSアプリはWebsocketを使用するため、 HTTPリクエストとWSリクエストの両方をプロキシします。

この図を参照してください: enter image description here

私はすべてを理解するのに非常に近いです。 Nginxを使用せずにローカルでテストしたところ、IPアドレスが正しくマスクされています。 Nginxが同じ場所を介してHTTPとWebソケットをリダイレクトするように挑戦しています(コードを参照)。

すべてのチュートリアルとサーバー障害の投稿から、WebSocketは通常別の場所を指し、Nginxは接続を適切にアップグレードすることがわかりました。

私は今、同じ場所のHTTP/2およびWebsocketsプロトコルを介してプロキシしようとしているという課題を抱えています。私はlocationブロック内でIFを使用するなどの悪質なハックに頼りました(しかし、それらは機能していません)。

理想的には、WebsocketがHTTPとは異なる場所を指すようにしたいのですが、それで問題が解決します。私の現在の問題は、AngularJSアプリのソースコードがないためです。

Atmosphereサーバーは、クエリパラメーターを通じてWebsockets接続を検出するようです(接続先のURLです)。

ws://the-user-ip/?X-Atmosphere-tracking-id=0&X-Atmosphere-Framework=2.3.2-javascript&X-Atmosphere-Transport=websocket&Content-Type=application/json&X-atmo-protocol=true.

これは、Nginxからの現在の構成の一部です。

upstream ipmask_docker_app {
  server ipmask:5050;
}
server {

  server_name "~^\d+\.example\.co$";

  # listen 80;
  listen 443 ssl http2;
  listen [::]:443 ssl http2;
  # HTTPS config omitted due to conciseness. 

 location / {
    # https://www.digitalocean.com/community/questions/error-too-many-redirect-on-nginx
        # proxy_ignore_headers X-Accel-Expires Expires Cache-Control;
        # proxy_ignore_headers Set-Cookie;
        # proxy_hide_header Set-Cookie;
        # proxy_hide_header X-powered-by;
        # proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header Host $http_Host;
        proxy_pass http://ipmask_docker_app;

        proxy_http_version 1.1;

    # Enables Websockets
    # https://www.nginx.com/blog/websocket-nginx/
    # https://stackoverflow.com/a/46675414/1057052
    # Have the http_version 1.1 disabled. I want to know if it works

      # THIS IS EVIL:
      set $ws_header_upgrade  '';
      set $ws_value_upgrade  '';
      set $ws_header_connection ''; 

      proxy_set_header 'Debug Header' $query_string;

      if ($args ~* "X-Atmosphere-tracking-id") {
        set  $ws_header_upgrade Upgrade;
        set  $ws_value_upgrade $http_upgrade;
        set $ws_header_connection "Upgrade";
      }

      proxy_set_header $ws_header_upgrade  $ws_value_upgrade;
      proxy_set_header Connection $ws_header_connection;

    # limit_req zone=one;
    access_log /var/www/cprint/log/nginx.access.log;
    error_log /var/www/cprint/log/nginx.error.log;
  }
}

上記のコードでは、同じlocationブロックにproxy_set_header Host $http_Host;proxy_set_header Upgrade $http_upgradeを含めることはできません。そのため、X-Atmosphere-tracking-idのquery_stringを一致に失敗し、一致する場合はそれをアップグレードするようにヘッダーを設定しました。

それ以外の場合、接続をアップグレードすると、WebページはHTTPプロトコルではなくWSをプロキシするようには見えないため、ロードされたWebページを表示できません。

Websocketをアップグレードする唯一の方法は、別のlocationを指すようにすることですか?または、同じ場所を指すようにして両方(HTTPとWS)をアップグレードする方法はありますか?

ありがとうございました!

6
Jose A

私が見つけた最も簡単な方法は、「アップグレード」ヘッダーに基づいて別の場所にジャンプすることでした:

server {
  # ...

  location / {
    try_files /nonexistent @$http_upgrade;
  }

  location @websocket {
    # websocket related stuff
  }

  location @ {
    # web related stuff
  }
}
6
mkg20001