Proxy Websockets and HTTP through the same location in Nginx

Right now there's an application that allows people to connect to a Desktop app through the web by exposing an AngularJS web server powered by Atmosphere. The Desktop app exposes the current person's IP address so anyone with the address can connect to.

I'm trying to mask this IP by proxying it through my server (example.com). My server currently hosts a series of applications (Ruby on Rails + Elastic Search, Logstash, Kibana - ELK) and are proxied by an Nginx client.

I've worked out to successfully mask the IP addresses through Node HTTP Proxy (locally), and now I'm trying to make it work while using Nginx. The AngularJS app uses Websockets so I need to proxy both the HTTP and WS request.

See this diagram: enter image description here

I'm very close to figuring everything out. I've tested locally without Nginx and the IP addresses are getting masked correctly. I'm having a challenge to make Nginx redirect the HTTP and Websockets through the same location (See code).

From all the tutorials and Server Fault posts I've seen that Websockets usually point to a different location, and Nginx gracefully upgrades the connection.

I'm having a challenge right now, that I'm trying to proxy through the same location HTTP/2 and Websockets protocols. I've resorted to evil hacks such as using IF inside the location blocks (but they haven't worked).

Ideally I'd like to have Websockets point to a different location than the HTTP, and that would solve the problem. My current problem is that I don't have the source code to the AngularJS App in order for me to do so.

The Atmosphere server seems to detect the Websockets connection through query parameters (This is the URL that it connects to):

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.

Here's part of my current configuration from 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;
  }
}

In the code above I can't seem to have proxy_set_header Host $http_host; and proxy_set_header Upgrade $http_upgrade in the same location block. That's why I tried matching unsuccessfully the query_string of X-Atmosphere-tracking-idand setting the headers to upgrade it in case that it matches it.

Otherwise, if I upgrade the connection I'm not able to see the Web Page loaded as it doesn't seem to proxy the HTTP protocol but the WS.

Is the only way to upgrade Websockets is to have it point to a different location? Or is there a way to upgrade both (HTTP and WS) by pointing them at the same place?

Thank you!

5
задан 4 May 2018 в 23:46
1 ответ

Самый простой способ, который я нашел, - это перейти в разные места на основе заголовка «Обновление»:

server {
  # ...

  location / {
    try_files /nonexistent @$http_upgrade;
  }

  location @websocket {
    # websocket related stuff
  }

  location @ {
    # web related stuff
  }
}
5
ответ дан 3 December 2019 в 01:36

Теги

Похожие вопросы