Search code examples
sslnginxwebsocketdjango-channelsdaphne

Using WebSocket Secure with Nginx and Daphne


I've been struggling to figure it all out, but I finally have something working with the following:

nginx:

server {
    server_name example.com;

    location = /favicon.ico { access_log off; log_not_found off; }
    location /static/ {
        root /home/example/example;
    }

    location / {
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "Upgrade";
        include proxy_params;
        proxy_pass http://unix:/tmp/daphne.sock;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
}

server {
    if ($host = www.example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    if ($host = example.com) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


    listen 80;
    server_name example.com;
    return 404; # managed by Certbot
}

daphne.service:

[Unit]
Description=daphne daemon
After=network.target

[Service]
User=example
Group=www-data
WorkingDirectory=/home/example/example
StandardOutput=file:/var/example.log
StandardError=file:/var/example.log
ExecStart=/home/example/example/venv/bin/daphne \
          -u /tmp/daphne.sock \
          project.asgi:application

[Install]
WantedBy=multi-user.target

I'm constrained to using https. The page does load with that. However, if I try and make a websocket connection it fails with something about mixed protocols. So I change 'ws://' to 'wss://' and now I get The URL 'wss://' is invalid. How can I get this to work?


Solution

  • The problem was quite simple to resolve. In my JavaScript I had

    new WebSocket(
            window.location.protocol == 'https:' ? 'wss://' : 'ws://'
            + window.location.host
            + '/ws/'
    );
    

    when I should have had

    new WebSocket(
            (window.location.protocol == 'https:' ? 'wss://' : 'ws://')
            + window.location.host
            + '/ws/'
    );
    

    Note the parentheses.