Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Secure WebSocket Connection through nginx 1.10.3 and LetsEncrypt

Been ripping hair out because I cannot find out why I cannot connect to my WebSocket server through HTTPS.

So, I have an Express 4 server running a vue app. It uses the ws library from npm to connect to the WebSocket server. The nginx is 1.10.3. I use LetsEncrypt to secure it.

When I go online, I get (in the console):

main.js:12 WebSocket connection to 'wss://play.mysite.com:8443/' failed: Error in connection establishment: net::ERR_CONNECTION_CLOSED

Line 12:

window.ws = new WebSocket(${tls}://${window.location.hostname}:${port});`

That is wss://play.mysite.com:8443. It is indeed on a subdomain.

Here is my nginx block: update: I got it!

upstream websocket {
    server 127.0.0.1:8443;
}

server {
    root /var/www/play.mysite.com/dist;
    index index.html;

    access_log /var/log/wss-access-ssl.log;
    error_log /var/log/wss-error-ssl.log;

    server_name play.mysite.com www.play.mysite.com;

    location /ws {
        proxy_pass http://websocket;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
    }

    listen [::]:443 ssl ipv6only=on default_server; # managed by Certbot
    listen 443 ssl http2 default_server; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/play.mysite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/play.mysite.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
}

As you see, we have the subdomain on https://play.mysite.com. My Express server always listen on port 4000 and my WebSocket server listens to wss / port 8443 on production.

When I view the /var/log/wss-error-ssl.log, I get:

2018/03/01 04:45:17 [error] 30343#30343: *1 connect() failed (111: Connection refused) while connecting to upstream, client: 68.117.172.118, server: play.mysite.com, request: "GET /static/css/app.67b8cb3fda61e1e2deaa067e29b52040.css HTTP/1.1", upstream: "http://[::1]:4000/static/css/app.67b8cb3fda61e1e2deaa067e29b52040.css", host: "play.mysite.com", referrer: "https://play.mysite.com/"

So, what exactly am I doing wrong?

The proxy_pass was set right. Listening to port 8443 for WebSocket on both client/server. What is the meaning? Thank you.

edit: and yes, I know the port 8443 is running:

root@MySITE:/var/www/play.mysite.com# netstat -l
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 *:https                 *:*                     LISTEN
tcp        0      0 localhost:4000          *:*                     LISTEN
tcp        0      0 localhost:mysql         *:*                     LISTEN
tcp        0      0 *:http                  *:*                     LISTEN
tcp        0      0 *:ssh                   *:*                     LISTEN
tcp6       0      0 [::]:8443               [::]:*                  LISTEN
tcp6       0      0 [::]:https              [::]:*                  LISTEN
tcp6       0      0 [::]:http               [::]:*                  LISTEN
tcp6       0      0 [::]:ssh                [::]:*                  LISTEN
udp        0      0 *:bootpc                *:*
udp        0      0 45.76.1.234.vultr.c:ntp *:*
udp        0      0 localhost:ntp           *:*
udp        0      0 *:ntp                   *:*
udp6       0      0 2001:19f0:5:2b9c:54:ntp [::]:*
udp6       0      0 fe80::5400:1ff:fe61:ntp [::]:*
udp6       0      0 localhost:ntp           [::]:*
udp6       0      0 [::]:ntp                [::]:*
like image 780
test Avatar asked Feb 26 '18 00:02

test


1 Answers

TL'DR Add a second location block for /websocket and have the javascript client hit wss://play.mysite.com/websocket

I see a couple of issues with your nginx server conf.

  1. Nginx is not listening on port 8443 yet your javascript is hitting wss://play.mysite.com:8443. So while nginx is serving up ports 443 and 80 for the play.mysite.com domain, you javascript is trying to bypass nginx using wss (TLS) and hit NodeJS directly -- though I suppose you meant to offload the SSL onto Nginx. The wss call must go through nginx in order for the SSL handshake to be successful.

  2. You are passing all calls to localhost:4000. Instead I suggest that you have two location blocks location / { ... } and location /websocket { ... }. This way in the second websocket location block you can proxy pass the calls to localhost:8443. This would require the client to connect to wss://play.mysite.com/websocket.

like image 133
Cory Silva Avatar answered Nov 15 '22 08:11

Cory Silva