Question

How to deploy nodejs (socket.io) app on digital ocean app engine

Posted February 10, 2021 1.2k views
Node.jsDigitalOcean App Platform

Hi, I have a nodejs (socket.io) app running on a dedicated Ubuntu server; a good friend of mine introduced me to app engine. As such, I have created and deployed a nodejs app as per instructions.

I can access the app via http as a websever, express.js is handling all of that.

However, when I try to access the app via a socket, it fails, and I do not understand why.

I have attached my code:

const logger = require('winston');
const express = require("express");
const socket = require("socket.io");
const fs = require('fs');
const http = require('http');

// my utility module
const functions = require('./my_modules/functions');
const utils = require('./my_modules/utils');


// App setup
const PORT = 8080;

// Logger config
logger.remove(logger.transports.Console);
logger.add(new logger.transports.Console, { colorize: true, timestamp: true });

const app = express();

app.use(function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'OPTIONS, GET, PUT, POST, DELETE');
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
});

// this inserts a json middleware into the current app
// which parse the request, and populate the request.body property, i.e req.body
app.use(express.json());

// parse url encoded inputs, i.e) key=value&key=value and populate the req.body property
// this is usefull, when we are not using json
app.use(express.urlencoded({ extended: true }));

let server = http.createServer(app);

server.listen(PORT, () => {
    logger.info('SocketIO > Server listening on port: ' + PORT);
});


// Socket setup
const io = socket(server);

// const staffs = [];
// const riders = [];
const devices = [];

// home entry
app.get('/', (req, res) => {
    console.log("devices", devices);
    res.status(200).send(utils.response(true, "Hello World"));
});


io.on('connection', (socket) => {

    // log on server that app has been connected
    logger.info('SocketIO > Connected socket ' + socket.id);

    // notifies, the client of successful connection
    socket.emit('connection', "You're connected to the node server buddy");

    // sets the initial parameter of an object
    socket.on('init', (data) => {
        let obj = JSON.parse(data);
        devices.push({
            socket: socket,
            userid: obj.userid,
            platform: "riderapp"
        });

        // if(obj.type == "rider"){
        //     riders.push({
        //         socket: socket,
        //         userid: obj.userid,
        //         platform: "riderapp"
        //     });
        // } else {
        //     staffs.push({
        //         socket: socket,
        //         userid: obj.userid,
        //         platform: "staffapp"
        //     });
        // }

    });

    // lsitens, when a socket is closed
    socket.on('disconnect', () => {
        let index = 0;
        staffs.forEach(staff => {
            if(staff.socket.id === socket.id){
                staffs.splice(index, 1);
            }
            index++;
        });

        let index2 = 0;
        riders.forEach(rider => {
            if(rider.socket.id === socket.id){
                riders.splice(index2, 1);
            }
            index2++;
        });

        logger.info('SocketIO > Disconnected socket ' + socket.id);
    });
});
edited by bobbyiliev

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.

×
Submit an Answer
1 answer

I would guess that in development your code is run over http and so the websocket runs over websocket (no tls).

When you deploy to app engine you get tls between your client and server, this causes the websocket to use wss(ws over tls).

Your server isn’t configured to use tls, (it needs the location of your cert and key) so it fails.

As for how to solve this - that is what I am attempting to do - so far with little success but if I figure out the cause I will post here a solution.

The way I see it though there are three options:

  1. force the websocket connection over ws (no tls).

  2. App Engine provides a way to reference the location of the certs and key (perhaps through environment variables, not unlike the way i have seen it provide values for dev database).

  3. Don’t use App engine, configure droplets where one is a nginx proxy that provides tls termination.

Me personally? Well I would settle for 1, 3 would make me re-evaluate my choice in PaaS and 2 would be the golden ticket.

Which one of these options are viable? Are there other options? No idea at the moment but I will report back with what I did to get past this.