How do I deploy socket.io to Google App Engine?

16,374

Solution 1

In short this cannot be done on production and it appears to be work in process. The right architecture is to have a chat server on google compute engine as outlined here.

But as a proof of concept to use socket.io on google app engine is very similar to that shown in google appengine samples for websockets.

In case of socket.io do the following steps on server side. Code snippet below.

  1. Create second express middleware and server.
  2. Attach/use socket.io with new server.
  3. Listen to port (65080).
  4. Open firewall for port (65080) on google compute engine.
  5. Link to working repository.

socket.io changes on server side

    var app_chat = require('express')();
    var server1 = require('http').Server(app_chat);
    var io = require('socket.io')(server1);
    server1.listen(65080);

    io.on('connection', function (socket) {
      console.log('user connected');
      socket.on('chat_message', function (data) {
        console.log('client sent:',data);
        socket.emit('chat_message', 'Server is echoing your message: ' + data);
      });
    });

open firewall by command

gcloud compute firewall-rules create default-allow-websockets \
    --allow tcp:65080 \
    --target-tags websocket \
    --description "Allow websocket traffic on port 65080"

I hope Google comes up with a production-ready solution soon enough on as this will become a key armour in any PaaS-arsenal.

Solution 2

GAE support for persistent socket connections arrived in February 2019!

To make this work, you'll need to be using the flex environment and modify your app.yaml to include session_affinity:

network:
  session_affinity: true

Note that I still had to open port 65080 to get this working, but no other changes were required for me.

Read the deets at:

https://cloud.google.com/appengine/docs/flexible/nodejs/using-websockets-and-session-affinity

Solution 3

Google has an example app using WebSockets here, you need to do the following to get it working correctly:

  • Open up a firewall port for the server so clients can reach your server
  • Fetch your internal IP in Google App Engine, so clients know what IP to connect to
  • Echo out your IP from your server via something like a rest API or a HTML page

That should be it (don't take my word for it though, this is what I've been able to find out after doing some research on the docs), hope it helps!

Fetching your external IP from within Google App Engine

var METADATA_NETWORK_INTERFACE_URL = 'http://metadata/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip';

function getExternalIp (cb) {
    var options = {
        url: METADATA_NETWORK_INTERFACE_URL,
        headers: {
            'Metadata-Flavor': 'Google'
        }
    };

    request(options, function (err, resp, body) {
        if (err || resp.statusCode !== 200) {
            console.log('Error while talking to metadata server, assuming localhost');
            return cb('localhost');
        }

        return cb(body);
    });
}

Opening the firewall port

gcloud compute firewall-rules create default-allow-websockets \
    --allow tcp:65080 \
    --target-tags websocket \
    --description "Allow websocket traffic on port 65080"

Solution 4

This app.yaml configuration worked for me:

runtime: nodejs
env: flex
manual_scaling:
instances: 1
network:
 session_affinity: true

And I enabled the firewall rules by this command:

gcloud compute firewall-rules create default-allow-websockets     --allow 
tcp:65080     --target-tags websocket     --description "Allow websocket 
traffic on port 65080"
Share:
16,374

Related videos on Youtube

Rian Smith
Author by

Rian Smith

Updated on September 15, 2022

Comments

  • Rian Smith
    Rian Smith over 1 year

    I created my first node.js app using socket.io. Specifically I implemented the chat example published by socket.io. It works perfectly, locally. And then I tried deploying it to Google App Engine (making some code tweaks for node to work).

    Everything shows up indicating that the node part is working well. However the chat doesn't work indicating that socket.io part isn't working. You can see the deployed app (and page source) here.

    Do I have to do anything additional? Something in the yaml or json files?

    yaml content:

    runtime: nodejs
    vm: true
    
    skip_files:
      - ^(.*/)?.*/node_modules/.*$
    

    json content:

    {
      "name": "Chaty",
      "description": "chatrooms app",
      "version": "0.0.1",
      "private": true,
      "license": "Apache Version 2.0",
      "author": "McChatface",
      "engines": {
        "node": "~4.2"
      },
      "scripts": {
        "start": "node app.js",
        "monitor": "nodemon app.js",
        "deploy": "gcloud preview app deploy"
      },
      "dependencies": {
        "express": "^4.13.4",
        "socket.io": "^1.4.6"
      }
    }
    
  • Rian Smith
    Rian Smith almost 8 years
    I feel like I'm close, but haven't gotten it to work yet. I opened the firewall port and deployed the google websocket project. That worked. But I don't yet know how to make it work with socket.io. Because socket.io is using the using the server listening in 8080 and using express. // Start the server var server = app.listen(process.env.PORT || '8080', '0.0.0.0', function() { console.log('Press Ctrl+C to quit.'); }); var io = require('socket.io')(server);
  • Ruud Helderman
    Ruud Helderman about 6 years
    The link to the sample app is broken; this one seems to come close: github.com/GoogleCloudPlatform/appengine-websocketchat-java
  • Ruud Helderman
    Ruud Helderman about 6 years
    The link to Google's sample app is broken; this one seems to come close: github.com/GoogleCloudPlatform/appengine-websocketchat-java
  • 0.sh
    0.sh about 5 years
    am getting this error in the console Failed to load resource: net::ERR_CONNECTION_TIMED_OUT staging-dot-wellnite-web-app.appspot.com:65080/socket.io/…
  • tommyc38
    tommyc38 over 4 years
    did you have any issues on mobile devices? Everything works great on desktop but on my iPhone (safari & chrome) it can't connect. Moreover, I haven't opened any other ports...everything is through 8080. Lastly, my app is using https which I have ready can cause issues....I am stumped here.
  • Mohit
    Mohit about 4 years
    This is what worked for me. Only yaml config was sufficient for my app engine instance, didn't need to change the firewall settings
  • Mohit
    Mohit about 4 years
    I'm still having issues on mobile. I tried making it work with https, but it seems chrome just won't accept the cert. Even Safari works, same engine!. @tommyc38: Did you ever figure it out? I will try moving my backend to AWS.