Setup ssl websockets from node using nginx and certbot

2020-06-04

Tags: nginx nodejs web-development instaboardgame websockets

Certbot is the tool from letsencrypt.org that lets you generate ssl certificates for your site without having to pay the likes of Verisign ever again. Basically I love the heck out of them for what they do.

Nginx runs on your server to redirect examplesite.com to localhost:1234 if you happen to be running your node express server on that port.

Now if you want to have a socket connection to your server to receive constant updates(for example if you are building an online sandbox styled board game system) you could use the npm module ws to create that websocket for your javascript code to connect to on some port, such as port 8080. This however will not be encrypted, and it will also be kinda ugly and not firewall friendly since it isn't running on a standard open port.

But you can run all that through nginx so that you get to have ssl encryption and also use the same port as your node.js express server.

How to do it

For the client side javascript, you can route your calls to wss://examplesite.com/websocket


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

upstream websocket {
   server 127.0.0.1:8080;
}

server {
    server_name examplesite.com;
    location /websocket {
            proxy_pass http://websocket;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $connection_upgrade;
            proxy_set_header Host $host;
    }

# after this is just an example of the rest of the nginx config for a node server on 8675
# that has a static build directory (for react or whatever)
    location / {
        proxy_pass http://127.0.0.1:8675;
        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;
        proxy_set_header X-Real-IP $remote_addr;
    }
    location ~ \.(gif|jpg|png|js|txt|html|mp3|css|woff2)$ {
        root /root/examplesite.com/build/;
        expires 30d;
    }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/examplesite.com/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/examplesite.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

}

You can use https://www.npmjs.com/package/wscat to test out your local ws://...:8080 and your wss://.../websocket connection, and both should now return the same thing.