Report this

What is the reason for this report?

SSL Error: How to use Nginx with Node.js App using Express and Socket.io

Posted on September 9, 2020

I am runnning into an SSL error when setting up Nginx as a reverse proxy for a Node.js app. This app uses Express to serve static content and Socket.io to manage Websocket connections.

The error occurs on the client side when attempting to connect to the socket.io server:

GET https://mywebsite.com:3000/socket.io/?EIO=3&transport=polling&t=NHqAzi7 net::ERR_SSL_PROTOCOL_ERROR

The steps I have taken to set this up are as follows:

  • followed this tutorial to set up Nginx to use certificates generated by certbot,
  • add a path to /etc/nginx/sites-available/mywebsite.com for the default /socket.io/ socket path

My Nginx configuration file looks like this:

server {

    root /var/www/mywebsite.com/html;
    index index.html index.htm index.nginx-debian.html;

    server_name mywebsite.com www.mywebsite.com;

    location / {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

    location /socket.io/ {
        proxy_pass http://localhost:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }

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


    listen 80;
    listen [::]:80;

    server_name mywebsite.com www.mywebsite.com;
    return 404; # managed by Certbot
}

And my server setup follows these instructions and looks like this:

var express = require('express'),
    http = require('http');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);

app.use(express.static(__dirname + "/public"));

server.listen(3000, ()=>{
  console.log('server listening on port 3000');
});

Finally, my client connects to the server like this:

socket = io('https://mywebsite.com:3000');

Any idea what else I could try to get this working?



This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Hi there @bicycle,

As you have already setup a reverse proxy for yourdomain.com/socket.io/ to proxy to port 3000, what you could do is update your client connects to the server like this:

socket = io('https://yourdomain.com/socket.io/');

That way as per your Nginx configuration the connection would get proxied to port 3000.

Hope that this helps! Regards, Bobby

Your setup seems mostly correct, but the issue likely arises from how you’re handling WebSockets in the Nginx configuration and the way the client is connecting to the server. Let’s address these points:

1. Nginx Configuration for WebSocket

In your Nginx configuration, the location /socket.io/ block looks properly configured for handling WebSocket connections. However, there’s no need to use the port number in your client-side connection. Nginx is already listening on port 443 (HTTPS) and proxying those requests to your Node.js app on port 3000. The client should simply connect to:

socket = io('https://mywebsite.com');

Connecting directly to port 3000 (https://mywebsite.com:3000) in the client bypasses Nginx and tries to establish a direct connection to your Node.js app, which isn’t set up for HTTPS (and thus causes the SSL error).

2. HTTPS Setup in Node.js App

Your Node.js server is currently set up with a regular HTTP server. This is fine since Nginx handles the SSL termination. Ensure that your server isn’t trying to handle SSL itself, as Nginx is already taking care of that.

3. Verify Nginx and Node.js are Running

Ensure both Nginx and your Node.js application are running:

  • Check Nginx status: sudo systemctl status nginx
  • Check your Node.js app is listening on port 3000: sudo lsof -i :3000

4. Firewall Settings

Make sure your server’s firewall is not blocking relevant ports. Since you are using Nginx as a reverse proxy, external traffic should only need to access ports 80 and 443.

5. Test Nginx Configuration

After making changes to your Nginx configuration, always test the configuration and reload if it’s successful:

sudo nginx -t
sudo systemctl reload nginx

6. Client-Side Connection

On the client-side, make sure to connect to the WebSocket server via the Nginx proxy (as shown above). There’s no need to specify the port in the URL since Nginx handles the proxy to the correct port.

7. Debugging

If it’s still not working:

  • Check the Nginx error logs (/var/log/nginx/error.log) for any clues.
  • Use browser developer tools (Network tab) to check the WebSocket connection status and errors.

8. SSL Certificate

Make sure your SSL certificates are up to date and correctly configured in Nginx.

By addressing these points, you should be able to resolve the SSL connection issue and properly route your WebSocket traffic through Nginx to your Node.js application.

The developer cloud

Scale up as you grow — whether you're running one virtual machine or ten thousand.

Get started for free

Sign up and get $200 in credit for your first 60 days with DigitalOcean.*

*This promotional offer applies to new accounts only.