Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Websocket connection by HTTPS with Let’s Encrypt #66

Closed
zeezdev opened this issue Jan 10, 2017 · 6 comments
Closed

Websocket connection by HTTPS with Let’s Encrypt #66

zeezdev opened this issue Jan 10, 2017 · 6 comments

Comments

@zeezdev
Copy link

zeezdev commented Jan 10, 2017

My configuration of Websocket work in Firefox but in Opera/Chrome not working,

I have a few question about the using daphne:

  1. I read many Issues but not found an answer. The Let’s Encrypt certificates in daphne is supported?
  2. Here use twisted endpoint description strings to bind to ports and sockets #37 (comment) shown the example how run daphne with SSL. What is mean? I can proxy request from HTTPS to port 8443 in my nginx-server and it should work (Websocket connection inclusive) or not?
  3. Whether I can use 'ws' instead 'wss' over HTTPS force.

Please help me understand the correct configuration daphne with HTTPS!!!
All work fine except Websocket connection (

I run daphne as:

Django(Channels) -> daphne -> nginx

run django worker:

python manage.py runworker -v2

run daphne with LetsEncrypt certificates:

daphne -e ssl:8443:privateKey=/etc/letsencrypt/live/my.domain.net/privkey.pem:certKey=/etc/letsencrypt/live/my.domain.net/fullchain.pem project.asgi:channel_layer -p 8000 -b 0.0.0.0

When I run my site without HTTPS (HTTP only) and run daphne as:

daphne project.asgi:channel_layer -p 8000 -b 0.0.0.0

Websocket is connected in all browsers.

nginx configuration:

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

server {
    listen 443 ssl;

    server_name my.domain.net <my.ip.address>;

    ssl on;
    ssl_certificate /etc/letsencrypt/live/my.domain.net/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/my.domain.net/privkey.pem;

    # allow only the most secure SSL protocols and ciphers, and use the strong Diffie-Hellman group
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_prefer_server_ciphers on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;
    ssl_ciphers '...';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

    client_max_body_size 512M;

    access_log /webapps/project/logs/nginx-access.log;
    error_log /webapps/project/logs/nginx-error.log;

    location /static/ {
        alias   /webapps/project/static/;
    }

    location /media/ {
        alias   /webapps/project/media/;
    }

    location /downloads/ {
        alias   /webapps/project/static/downloads/;
    }

    location /docs/ {
        alias /webapps/project/static/docs/en/;
    }

    location /docs/en/ {
        alias /webapps/project/static/docs/en/;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;

        proxy_set_header   Upgrade $http_upgrade;
        proxy_set_header   Connection $connection_upgrade;

	# need for google oauth
        proxy_set_header   Host $host; 
    }


    location ~ /.well-known {
       allow all;
    }
}


server {
    listen 80;
    server_name my.domain.net <my.ip.address>;

    location /downloads/ {
        alias   /webapps/project/static/downloads/;
    }

    location / {
        return 301 https://$host$request_uri;
    }
}

Websocket connection on client (browser) with using ReconnectingWebSocket:

   ...

    var ws_path = "wss://my.domain.net:8443/" + userId.toString() + "/stream/";
    console.log("WebSocket connecting to " + ws_path);
    webSocket = new ReconnectingWebSocket(ws_path); 
    webSocket.timeoutInterval = 5000;

    webSocket.onopen = function() {
        console.log("WebSocket connected.");
   };

    webSocket.onclose = function(event) {
        console.log("WebSocket disconnected.");
    };

    webSocket.onmessage = function(message) { ... }

    ...
@andrewgodwin
Copy link
Member

It looks fine to me at first glance - and if Firefox connects it means websocket is getting through alright. What error do you get from the other browsers?

@zeezdev
Copy link
Author

zeezdev commented Jan 11, 2017

I forgot to say that a successful connection I get by means of little hack in my routing.py:

def ws_connect(message, pk):
    logger.info("WS: connected new user with pk={}".format(pk))
    try:
        user = User.objects.get(pk=pk)
        if not user.is_authenticated():
            logger.warn("WS: user pk={} is not authenticated".format(pk))
            return  # using /stream/ (devices) only for authenticated users
        Group(user.group_name).add(message.reply_channel)

        # FIXME: little hack, send a message for connection establishment
        group = Group(user.group_name)
        group.send({
                "text": json.dumps({
                        'payload': {
                            'action': 'connection',
                            'data': {}
                        }
                    }
                ),
        })
    except ObjectDoesNotExist:
        logger.warn("WS: user for pk={} not found".format(pk))
    except Exception as ex:
        logger.error(ex)

Without sending of the empty message the connection does not established and in Firefox too.
Without sending the message I get records in the log about that the client has been connected but immediately there are disconnection of the websocket client and I have messages in my browser:

WebSocket connection to 'wss://my.domain.net:8443/4/stream/' failed: WebSocket is closed before the connection is established.

and after a few attempt:

reconnecting-websocket.min.js:1 WebSocket connection to 'wss://my.domain.net:8443/4/stream/' failed: Error in connection establishment: net::ERR_TIMED_OUT

@andrewgodwin
Copy link
Member

Ah, it's because you're not accepting the connection like 1.0 now requires! See http://channels.readthedocs.io/en/latest/releases/1.0.0.html#connect-consumers

@zeezdev
Copy link
Author

zeezdev commented Jan 12, 2017

Thanks for your hint! I'll try it soon.

@andrewgodwin
Copy link
Member

Closing due to lack of response.

@fuzilogik
Copy link

Hi

I am experiencing a very similar issue to zeezdev. My setup is almost identical, besides me using Apache instead of nginx. I keep getting "WebSocket is closed before the connection is established." warnings followed by a "WebSocket opening handshake timed out" error after the web socket not being able to connect. Is there a suggested fix for this? I am running daphne with letsencrypt certificates in much the same was as described by zeezdev.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants