3

I successfully deployed uwsgi + nginx + Django. But I want to communicate with my server using websocket.

I followed this tutorial to handle normal https requests. https://uwsgi-docs.readthedocs.io/en/latest/tutorials/Django_and_nginx.html

The nginx conf file settings are like this:

upstream django {
    server unix:///path/to/your/mysite/mysite.sock; # for a file socket
}

# configuration of the server
server {
    # the port your site will be served on
    listen 443 ssl; # managed by Certbot
    # the domain name it will serve for
    server_name example.com; # substitute your machine's IP address or FQDN
    charset     utf-8;



    location /static {
        alias /path/to/your/mysite/static; # your Django project's static files - amend as required
    }

    # Finally, send all non-media requests to the Django server.
    location / {
        uwsgi_pass  django;
        include     /path/to/your/mysite/uwsgi_params; # the uwsgi_params file you installed
    }
}

I Googled a lot and found that people recommended to add these settings:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_redirect off;

It does not work. I did not use proxy_pass because I am already using uwsgi_pass django; and my client attempts to connect using websocket to the same url (location) I uwsgi_pass to django. I looked into uwsgi docs and found this page: https://uwsgi-docs.readthedocs.io/en/latest/WebSockets.html

According to this page, I do not need additional settings if I just add --http-websockets option. So I did. Like this:

/usr/local/bin/uwsgi --emperor /etc/uwsgi/vassals --http-websockets www-data --daemonize /var/log/uwsgi-emperor.log

It is added in /etc/rc.local. This command does not work either. I also tried to add http-websockets = true to .ini file. It even made uwsgi stop. So I removed that option.

What is wrong here?

I get 400 Bad Request for every websocket request. The only data I see is (Opcode -1). There is no graphql error message.

Grateful
  • 383
  • 5
  • 18
  • 1
    I know using `nginx > gunicorn > django` stack will work for sure, if everything else fails, try that :) – Dusan Gligoric Sep 23 '19 at 13:11
  • @DusanGligoric Okay. I will try gunicorn. But I do not see good documents regarding using websocket. The only one I found is this: https://flask-socketio.readthedocs.io/en/latest/#gunicorn-web-server – Grateful Sep 23 '19 at 13:54
  • Me too, I know using `nginx > gunicorn > django` :D. @Beginner, you could follow gunicorn document to implement it, here is the guideline how to set it up using socket. https://docs.gunicorn.org/en/latest/deploy.html#systemd – Toan Quoc Ho Sep 23 '19 at 13:56
  • Where do you see 400 bad request? Are you logging errors in django so you can look at the django logs? Have you check your uwsgi logs? – dirkgroten Sep 23 '19 at 14:13
  • @dirkgroten I see 400 error on Chrome Developer's mode, through Network tab. The screen does not show anything because it is a graphql request. I do log errors in django, but this error does not show in a django level. I send django logs to uwsgi and it says nothing but "Bad Request: /graphql/" – Grateful Sep 23 '19 at 22:17
  • @ToanQuocHo Thank you! I will look into it! – Grateful Sep 23 '19 at 22:17
  • @dirkgroten in my console, I can see this: WebSocket connection to 'wss://mydomain/graphql/' failed: Error during WebSocket handshake: Unexpected response code: 400 – Grateful Sep 24 '19 at 01:04
  • @DusanGligoric How did you implement gunicorn? I followed a guide from https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04 and I changed the command using gevent-websocket like gunicorn -k geventwebsocket.gunicorn.workers.GeventWebSocketWorker -w 1 --bind mysocket config.wsgi I was able to escape from 400 error, – Grateful Sep 24 '19 at 06:30
  • @ToanQuocHo but now I see "WebSocket connection to 'wss://mydomain/graphql/' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received" There are only lots of "101 Switching Protocols" status in my Network Tab of Chrome. – Grateful Sep 24 '19 at 06:30
  • A 400 error must come from Django. I don’t understand “I send the Django log to uwsgi”. Django log should be in a file directly and if it raises a 400 error there must be a full error trace in your Django log file. Are you using a `FileHandler` in your `LOGGING` settings? – dirkgroten Sep 24 '19 at 06:50
  • @dirkgroten No, I am using logging.StreamHandler. Let me check Django again. – Grateful Sep 24 '19 at 06:58
  • @dirkgroten But now, I am getting 101 Switching Protocol status instead of 400 erorrs. – Grateful Sep 24 '19 at 07:01
  • You shouldn’t use StreamHandler in production. Use FileHandler. – dirkgroten Sep 24 '19 at 07:07
  • You can’t use WSGI for serving websockets, you need an ASGI server or aiohttp. – dirkgroten Sep 24 '19 at 07:11
  • @dirkgroten Thank you for the recommendation. I just switched to FileHandler. But I find that nothings is logged. I am trying to work with gunicorn, but besides that, uWSGI docs mention that it does support websocket. https://uwsgi-docs.readthedocs.io/en/latest/WebSockets.html – Grateful Sep 24 '19 at 07:20
  • Are you using Django-channels with graphql? – dirkgroten Sep 24 '19 at 07:33
  • @dirkgroten Yes! That is right! – Grateful Sep 24 '19 at 07:33
  • @dirkgroten I just switched to uWSGI again to see 400 error. It did make logs, but the only thing I see is this: "Bad Request: /graphql/" – Grateful Sep 24 '19 at 07:34
  • Have you created an asgi.py file and configured uwsgi to call that instead of wsgi.py for wss connections? I have used Daphne in the past for websockets. Just followed [thi](https://channels.readthedocs.io/en/latest/deploying.html#configuring-the-asgi-application) explanation. – dirkgroten Sep 24 '19 at 07:39
  • @dirkgroten I switched to Daphne and it works now. The problems were resolved. Thank you very much for replying to me!! – Grateful Sep 24 '19 at 12:06

1 Answers1

0

You need to change socket type from .sock to net (ip:port). And use this consruction on NGinx "proxy" and server with django.