Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Docker NGINX Proxy not Forwarding Websockets

NGINX proxy is passing HTTP GET requests instead of WebSocket handshakes to my django application.

Facts:

  • Rest of the non-websocket proxying to django app is working great.
  • I can get WebSockets to work if I connect to the django application container directly. (Relevant log entries below.)
  • The nginx configuration works localhost on my development machine (no containerizing). (Log example below.)

Relevant Logs:

Daphne log when connecting through containerized nginx proxy:

`xxx.xxx.xxx.xxx:40214 - - [24/May/2017:19:16:03] "GET /flight/all_flight_updates" 404 99`

Daphne log when bypassing the containerized proxy and connecting directly to the server:

xxx.xxx.xxx.xxx:6566 - - [24/May/2017:19:17:02] "WSCONNECTING /flight/all_flight_updates" - -
xxx.xxx.xxx.xxx:6566 - - [24/May/2017:19:17:02] "WSCONNECT /flight/all_flight_updates" - -

localhost testing of nginx (non-containerized) configuration works:

[2017/05/24 14:24:19] WebSocket HANDSHAKING /flight/all_flight_updates [127.0.0.1:65100]
[2017/05/24 14:24:19] WebSocket CONNECT /flight/all_flight_updates [127.0.0.1:65100]

Configuration files:

My docker-compose.yml:

version: '3'
services:
  db:
    image: postgres
  redis:
    image: redis:alpine
  web:
    image: nginx
    ports:
     - '80:80'
    volumes:
     - ./deploy/proxy.template:/etc/nginx/conf.d/proxy.template
    links:
     - cdn
     - app
    command: /bin/bash -c "envsubst '' < /etc/nginx/conf.d/proxy.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
  cdn:
    image: nginx
    volumes:
     - ./cdn_static:/usr/share/nginx/static
     - ./deploy/cdn.template:/etc/nginx/conf.d/cdn.template
    command: /bin/bash -c "envsubst '' < /etc/nginx/conf.d/cdn.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
  app:
    build: .
    image: app
    ports:
     - '8000:8000'
    links:
     - redis
     - db
    volumes:
     - ./cdn_static:/var/static

My proxy.template NGINX configuration template:

  upstream cdn_proxy {
    server cdn:80;
  }

  upstream daphne {
    server app:8000;
    keepalive 100;
  }

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

  server {
    location /static {
      proxy_pass http://cdn_proxy;
    }

    location / {
      proxy_buffering off;
      proxy_pass http://daphne;
      proxy_read_timeout     300;
      proxy_connect_timeout  300;

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;

      proxy_redirect     off;
      proxy_set_header   Host $host;
      proxy_set_header   X-Real-IP $remote_addr;
      proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Host $server_name;

    }
  }

UPDATE

I have built a more compact example of the problem using the tutorial on the NGINX website and put it on github at https://github.com/c0yote/nginx-websocket-issue.

You get a 426 instead of a 404, but I believe this is because the simple server doesn't know how to handle the GET that NGINX is sending. I am reinforced in this thought by the fact that if you issue a GET (from a browser for example) directly against the 8000 port you get the same 426.

Therefore the core problem is still that NGINX is sending a GET.

MORE INFO:

tcpdump shows that the GET to the websocket server has an Upgrade field, but the GET against NGINX does not. This is confusing since the wscat command is identical with the exception of the target port.

GIGA UPDATE:*

If I take the NGINX proxy off port 80 to say, 8080 it works. My only guess is that the js client makes some assumption about port 80. If anyone knows why this is the case, I'd love to know.

like image 391
Präriewolf Avatar asked May 24 '17 19:05

Präriewolf


1 Answers

It was my organization's firewall.

It was stripping the connection upgrade out of the GET header on port 80. When I changed to a different port, it worked fine.

like image 143
Präriewolf Avatar answered Nov 02 '22 15:11

Präriewolf