javascripttypescriptnginxwebsocketws

Browser's native WebSocket via remote server in the onopen event readyState property is always CLOSED


Everything works fine on the local server. But when I try to test on a remote server through Nginx, then inside the event handler onopen readyState is always CLOSED.

Nginx config:

server {
  server_name    domain.domain;
  access_log     /var/log/nginx/domain.domain.access.log;
  error_log      /var/log/nginx/domain.domain.error.log;
  location / {
      proxy_connect_timeout 1d;
      proxy_send_timeout 1d;
      proxy_read_timeout 1d;
      proxy_pass http://localhost:3001;
      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection "Upgrade";
      proxy_set_header Host $host;
  }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/domain.domain/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/domain.domain/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 = domain.domain) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


  server_name    domain.domain;
    listen 80;
    return 404; # managed by Certbot


}

Server sample code:

import { WebSocketServer } from 'ws';
this.connection = new WebSocketServer(args, () => {
  log('info', 'Server listen at port:', args.port, true);
});
this.connection.on('connection', (ws, req) => {
  // Event is triggered fine 
  console.log('Client connected');
})

Client sample code:

const connection = new WebSocket(
  'wss://domain.domain:443', 'json'
);
connection.onopen = () => {
  // Event triggered bud connection.readyState is CLOSED every time
  setInterval(() => {
    console.log(connection.readyState);
  }, 1000)
}
connection.onerror = () => {
  // Never triggered
}
connection.onclose = () => {
  // Never triggered
}

Previously, the same code with the same server settings worked fine. But when after some time I recreated the virtual server from the backup, such a problem appeared, although everything else works as before.


Solution

  • Revisiting my code again, I saw that since the last successful test, I added a CORS check to the server, which, as it turned out, was not properly configured in the environment variables.

    this.connection.on('connection', (ws, req) => {
      // Event is triggered fine 
      console.log('Client connected');
      const { origin } = req.headers;
      const notAllowed = process.env.CORS.split(',').indexOf(origin || '') === -1;
      if (cors && notAllowed) {
        log('warn', 'Block CORS attempt', { headers: req.headers });
        ws.close();
        return;
      }
    })
    

    Another question is why event onclose did not fire on the client and why warn was not displayed on the server. But I think that since I output in stdout with a special method and maybe it also did not work due to incorrect environment variables, but this is another question - it does not need to be considered here.