NGINX proxy is passing HTTP GET requests instead of WebSocket handshakes to my django application.
Facts:
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With