Hosting nodejs server at dotcloud

I am trying to host a nodejs application on "dotcloud" hosting service. My nodejs uses the "websocket" package to handle messages. i.e. npm install websocket

My application works fine when running on localhost on my laptop. But when I deploy my app to dotcloud it doesn't work correctly.

Here's what's going on: You point your browser to a URL in dotcloud: pirate-captainlonate.dotcloud.com

The expression then processes the GET request with express.get ('/' .......) {} Express serves the .html page to the client as you would expect. The .html file, in turn, tries to establish a connection to the server. Again I can get this working very well on my local machine. However, no connection is established. In particular, dotcloud is definitely serving me a .html file, but the .html file does not establish a connection to the server. But connection.onerror is not called either. This is strange.

Here is some code to help you understand what I am doing:

Client side:

this.connection = new WebSocket('ws://pirate-captainlonate.dotcloud.com:1337'); 

this.connection.onerror = function (error) {
        console.log("ERROR with the connection *sadface*");
    };

**** Note that I note the onerror function here to show that I do indeed have it set up, but it not being called. It would seem that no error is being thrown.

      

Server side:

var webSocketServer = require('websocket').server; // websocket
var server = require('http').createServer();
var expr = require("express"); // load the express module
var xpress = expr(); // xpress now holds the server object

// Helps Node serve the game.html page upon a get request
xpress.configure(function() {
    xpress.use(expr.static(__dirname + "/public"));
     xpress.set("view options", {layout: false});
});

// All requests to root serve the game.html page
xpress.get('/', function(req, res) {
    res.sendfile(__dirname + '/public/game.html');
});

// What ports to listen on
var webSocketsServerPort = 1337;
xpress.listen(8080);
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + " Server is listening on port " + webSocketsServerPort);
});

// WebSocket Server
var wsServer = new webSocketServer({
    httpServer: server
});

      

This should be enough code to show you how it works. Now one of you is probably asking, what is "β†’ dotcloud logs" displayed?

[www.0] ==> /var/log/supervisor/app.log <==
[www.0] Sat Feb 16 2013 02:57:59 GMT+0000 (UTC) Server is listening on port 1337
[www.0] ==> /var/log/supervisor/supervisord.log <==
[www.0] 2013-02-16 02:57:57,946 WARN Included extra file "/home/dotcloud/current/supervisord.conf" during parsing
[www.0] 2013-02-16 02:57:58,033 INFO RPC interface 'supervisor' initialized
[www.0] 2013-02-16 02:57:58,033 WARN cElementTree not installed, using slower XML parser for XML-RPC
[www.0] 2013-02-16 02:57:58,033 CRIT Server 'unix_http_server' running without any HTTP authentication checking
[www.0] 2013-02-16 02:57:58,038 INFO daemonizing the supervisord process
[www.0] 2013-02-16 02:57:58,039 INFO supervisord started with pid 140
[www.0] 2013-02-16 02:57:59,048 INFO spawned: 'app' with pid 154
[www.0] 2013-02-16 02:58:00,290 INFO success: app entered RUNNING state, process has stayed up for > than 1 seconds (startsecs)
[db.0] ==> /var/log/mongodb/mongodb.log <==
[db.0] Sat Feb 16 01:45:02 [conn4] end connection 127.0.0.1:51326 (0 connections now open)

      

Ok, ok, I would really like this to work. I've been on this forever. Let me know if there is anything else you need to help me answer my question.

Thank,

- Nathan

Addendum: this is how the server sends the html file.

xpress.get('/', function(req, res) {
    res.sendfile(__dirname + '/public/game.html');
});

      

+3


source to share


3 answers


It looks like you are trying to use 2 HTTP ports for your service, and dotCloud only supports 1 out of the box, so you need to tell them you want to have another by adding a small snippet to your dotcloud.yml

Here is an example dotcloud.yml

that asks for a second tcp port named server

app:
    type: nodejs
    ports:
       server: tcp
    config:
       node_version: v0.8.x

      

After you add this and click, your server will be given a 2nd TCP port that you can use for your server, you just need to figure out which port that gets the value from your environment file.

Here is a snippet that will get your port from ENV, by default it will be 4242 if it doesn't exist, so you can still execute locally.

var webSocketsServerPort = process.env['PORT_SERVER'] || 4242;

      

If you're wondering how I got the name of the ENV variable, it's simple. this will be PORT_ and then the top line of the name from dotcloud.yml

. Since I used the server above it became PORT_SERVER , if I was using node it would be PORT_NODE, so put what you want, but make sure these values ​​match.

Customer:



To find out what port you need to connect to your client, you need to go back to your environment variables again. This time, you are looking for a variable that looks like DOTCLOUD_APP_SERVER_PORT

. Important . The variable name can be different.

How did I get the name of the envirornment variable?

The variable name looks like DOTCLOUD_{{app_name}}_{{port_name}}_PORT

all caps. Replace {{variable}} with the information below.

{{app_name}}

= the name of your app from your dotcloud.yml, in the above example it is app

{{port_name}}

= the port name, server

in the example dotcloud.yml.

To find it, you can get it from your applications environment.json

, environment.yml

files, ENV shell variables, or go into the dotCloud toolbar, click on your application and then the Environment tab to see a list of your application variables.

If you make these three changes, your problems should go away.

If you need more code examples, check out this github repository that does something similar to what you are trying to do.

https://github.com/3on/node-tcp-on-dotcloud

+2


source


<<<Original poster here β†’>

Ok I got this to work on Dotcloud. I'm just going to post what you need to know. If you encounter this problem, the final solution will be posted. I want to thank Ken at dotcloud for being on the right track. Thanks to him I found out about environment.yml, environment.json files. Moreover, by doing

console.log(process.env);

      

there was a HUUGE helper on the server side. Here KK makes a decision:

First, I want you to see how I declare my requirements and variables:

var webSocketServer = require('websocket').server; // websocket
var server = require('http').createServer();
var expr = require("express"); // load the express module
var xpress = expr(); // xpress now holds the server object

      

Ok, now that you know what this is, I must tell you that I decided to use ejs to create a template. The problem I am facing is that I need my client to be able to "know" on which port to connect to the server via WebSocket. Without a websocket connection already in place, how else am I going to provide the client with a "port" type variable. Keep in mind that the port can change, so I couldn't just hardcode the port like 50234 or something at the end of my ws: // url. The solution was to use "ejs".

ejs is a module (ie "npm install ejs"). I'm not going to explain how to use it. But here is the website I used to find out: http://embeddedjs.com/

Here are some things you need to know: When a client points their browser to your dotcloud url, this is how you send them a file, in my case I changed my .html file to an .ejs file so that I can render it as a template.

xpress.get('/', function(req, res) {
    res.render('game', 
    {
        answer: superCoolPort
    });
});

      

"game" means that in whatever folder I told the server to look for templates, there should be a file named game.ejs. Notice how I am handling a template named game.ejs with some data. In this case, the data is a local variable in my server.js file called "superCoolPort". This is what this variable is:

var superCoolPort = process.env['DOTCLOUD_WWW_SERVER_PORT'];

      

Ok now the expression ("xpress" in my case) needs to listen on port 8080.

xpress.listen(8080);

      

This is NOT the port your WebSocket will try to connect to. This is the port on which your browser tries to connect to the page. But Dotcloud doesn't let you put anything on port 80, so if you put it on 8080, they'll redirect it to 80 for you. This way you don't need to enter url: 8080 in the browser.

Now let me explain how the http server becomes wsServer. Basically you have created an http server and make it listen on a port. Then you connect this http server to your websocket server. See where I declare "server" at the top?

This is the port on which the HTTP server will listen. Note that this means the websocket server will also listen on that port.

var webSocketsServerPort = process.env['PORT_SERVER'] || 4242;
server.listen(webSocketsServerPort, function() {
    console.log((new Date()) + "The http server is listening on port " + webSocketsServerPort);
});

// WebSocket Server
var wsServer = new webSocketServer({
    // WebSocket server is tied to a HTTP server. WebSocket request is just
    // an enhanced HTTP request.
    httpServer: server
});

      

Before going to the client, I want you to know how I set up my express configurations.



xpress.configure(function() {
     // Sets the directory to look for templates
     xpress.set('views', __dirname + '/public');
     // This line tells Express that we are using the ejs engine to render templates
     xpress.set('view engine', 'ejs');
     xpress.use(expr.static(__dirname + "/public"));
     xpress.set("view options", {layout: false});
});

      

All of the above has been added to the server.js file.

Ok, I'll go over the template. I used to have a file called game.html. Well, I wanted this to be a template that I could display with some data (the port number that the website has to connect). So first I changed the filename to game.ejs. Then I made some changes like this:

<body onload="init()">

      

became

<body data-port="<%=answer%>" onload="init()">

      

See how onload = "init ()"? This means that init will not be called until the page is loaded. This is important because when we want to access a port, you are not guaranteed that it is available unless you are inside init (). I know this because I tried to access it before I defined init () and said the variable is null.

Now, inside init (), you can access the port number like this:

var port = $('body').data('port');

      

My client.js file can now initialize a website connection like this:

this.connection = new WebSocket('ws://pirate-captainlonate.dotcloud.com:' + this.thePort);

      

where "this.thePort" is the same as "port" at the top.

I want to make this solution as complete as I can, here is my dotcloud.yml file. Its this one directory above the server.js file:

www:
    type: nodejs
    approot: app
    ports:
        server: tcp
    processes:
        app: node app.js
    config:
        node_version: v0.8.x

db:
    type: mongodb

      

Here is my package.json file. It's in the same directory as my server.js file (which in my case is called app.js):

{
  "name": "app",
  "version": "0.0.0",
  "scripts": {
    "start" : "node app.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies":{
      "express" : "",
      "mongodb" : "",
      "fs": "",
      "ejs": "",
      "ws": "",
      "websocket": ""
  },
  "repository": "",
  "author": "",
  "license": "BSD"
}

      

Finally, I honestly don't know if this is needed or not, but here is my supervisord.conf file. It is located in the same directory as server.js.

[program:node]
command = node app.js
directory = /home/dotcloud/current

      

Okay, I think that's all. I hope I left nothing behind. Ultimately though these changes were necessary for me to have my nodejs application use "websocket" to deploy and run in Dotcloud.

+1


source


It looks like you are trying to access WebSocket on port 1337, but you should try over port 80.

this.connection = new WebSocket('ws://pirate-captainlonate.dotcloud.com');

      

Most public platforms only proxy your application on port 80. Speaking of which, have you tried running your application on Nodejitsu? http://nodejitsu.com

-1


source







All Articles