Host a Node.js bot (express and botkit) - node.js

I just made a bot in node.js for the Cisco Webex Teams application. My bot uses "express" and "botkit". "Express" requires listening on the port "3000" and "Botkit" listening on the port "8080".
I tried heroku.com but it does not accept two predefined ports and does not save files dynamically (fs.write)
var PUBLIC_URL = "http://a796e3b7.ngrok.io";
var port ='3000';
var ACCESS_TOKEN ='xxx';
var SECRET = "xxx";
var express = require('express');
var app = express();
var Botkit = require('botkit');
var controller = Botkit.webexbot({
log: true,
public_address: PUBLIC_URL,
access_token: ACCESS_TOKEN,
secret: SECRET,
webhook_name: process.env.WEBHOOK_NAME || 'Email2Webex',
});
controller.setupWebserver(8080, function(err, webserver) {
controller.createWebhookEndpoints(webserver, bot, function() {
console.log("Webhooks set up!");
});
});
app.post('/mailgun', upload.any(),function(req, res, next){
res.end('ok');
});
app.listen(port);
Currently I use ngrok to host the bot locally on my computer and I want to be able to host it on a server so I do not have to worry about it. how can I do ?

You can't set the port on Heroku apps. Heroku sets the port you're supposed to use through the PORT environment variable, and you should use it via process.env.PORT. Generally speaking, deployed applications should not run on development ports like 8080 - if it's an HTTP server, it must listen on port 80, for example.
In order to have two apps listening at the same time, I suggest you refactor your code and include both your bot and your app into a single express server that will listen at the port defined by Heroku's PORT environment variable.
Concerning access to the file system, it is borderline possible to use it, but there are high security restrictions, so a code that might run on your machine is likely to break on the server. Generally speaking it's a bad idea to access the file system directly in Heroku, except for read-only actions on deployed files. That is in part because the file system is ephemeral, so dont assume your written files will always be there. Most issues related to the caveats of using the file system can be resolved by using database or file storage features provided by Heroku, though.

Related

How to run a gRPC Server and an Express Server on the Same PORT in cloud run

Are there any known techniques or hacks for running both an Express Server and a GRPC Server on the same port? I am aware Cloud Run exposes just a single Port for a service instance.
So, I'm literally just looking for hacks as it stands now.
Like below
const app = express();
const port=process.env.PORT;
app.listen(port,()=>{});
gRPCServer.bindAsync(`0.0.0.0:${port}`, grpc.ServerCredentials.createInsecure(), () => {
gRPCServer.start();
});
I wish to expose some routes to my users via express and only use GRPC for internal micro services communication.
I saw https://github.com/grpc-ecosystem/grpc-gateway but there are very few documentations on how to use it with NodeJS plus I DON'T want to generate client libraries. I prefer dynamic code generation.

How to run two servers on Heroku?

I have built a project in Angular 9 for the frontend and Node.js as the backend server.
Now I am running node appserver.js for running the backend server. This listens to port 9090 as default. In another terminal, I am running ng serve to run my Angular app on port 4200 as usual. I have a service in the Angular app that sends and receives messages from server.
I have used WebSocket class to connect to the port 9090. My app works fine in local. But now how could I deploy in Heroku. Heroku gives a random port number which will be specified as process.env.PORT. how could I get that port in my WebSocket service?
My questions are:
How to deploy two servers in Heroku?
How port number in appserver.js is specified as port number in WebSocket service in Angular?
Is there any use of the .env file and ProcFile to solve my problem?
Is there any use of multi-buildpack which is in Heroku to solve my problem?
You cannot deploy two separate servers when they each require a port. You will have to put them into separate apps. In some cases you can combine web servers. Deploying a server is done as regular.
When deploying a web service on Heroku Heroku provides you a port to which you have to bind to. You can then visit your web service under <appname>.herokuapp.com. (<-- this is why 1.) requires you to put them into separate apps.). Furthermore when you connect to the webservice you merely give the URL. That URL is automatically translated into <ipaddress>:<port>. So in your frontend you are not going to specify a port number. You are specifying the websocket URL in your frontend without any port.
In your web server you bind to process.env.PORT.
.env file shouldn't be versioned/committed. No use. If you require environment variables you can set them through Heroku's dashboard. Procfile is not required since you are using Node.js it will look into your npm start script located in package.json. But it doesn't hurt to have since it gives clarity.
There is no multi-buildpack for this.
If your 2 servers are strictly distinct and use separate protocols. One using http, the other ws you can bundle your two servers into one. Here is an example:
const http = require('http');
const path = require('path');
const express = require('express');
const WSServer = require('ws').Server;
const DateFormat = require('dateformat');
let wss;
let server;
const app = express();
app.use(express.static(path.join(__dirname, './../build')));
server = new http.createServer(app);
wss = new WSServer({ server })
this.wss = wss;
wss.on('connection', function(socket) {
console.log(DateFormat(new Date(), 'm/d h:MM:ss TT'),
`client connected to server (${wss.clients.size} total)`);
socket.on('message', function(data) {
console.log(data)
});
socket.on('close', function(code, desc) {
console.log(DateFormat(new Date(),
"h:MM:ss TT"),'client disconnected, total:', wss.clients.length);
});
});
wss.on('listening', () => console.log('Websocket listening on port', config.get('port')));
wss.on('error', err => console.log('Websocket server error:', err));
server.on('error', err => console.log('Server error:', err));
server.listen(process.env.PORT);
Example in a project:
https://github.com/vegeta897/d-zone/blob/63730fd7f44d2716a31fcae55990d83c84d5ffea/script/websock.js
In the project the backend with the websocket server was extended to include an express server serving the static files. Note that this change only exists in the heroku branch.
You will find all the relevant changes that made that project heroku compatible in this commit:
https://github.com/vegeta897/d-zone/commit/63730fd7f44d2716a31fcae55990d83c84d5ffea

Deploy Node.js RestFull API to Heroku

I have a school assignment where i must build a node.js server (Without Express) that receives a POST request containing {day: 25, month:12, year:2017} and sends the number of days remaining to that date.
I was able to solve this using moment npm package (https://www.npmjs.com/package/moment)
The server is listening on port 3000.
The code works perfectly when i send a post request to 127.0.0.1:3000
However, i changed listen port to 80, created a new app on heroku and then deployed my code and it doesn't work anymore, heroku says application crash.
Does anyone have an idea ?
server is created like this :
var http = require('http');
var moment = require('moment');
moment().format();
var server = http.createServer(function(request, response) {
....
});
server.listen(80);
Heroku uses the process.env of nodeJS. In order to make sure your app works on heroku you should set the an variable called port that takes either port 3000 / 80 for local app and process.env.PORT for heroku deployments.
const port = process.env.PORT || 3000
Hope that helped!

Azure web deployment not displaying web page

I'm writing a simple nodejs app to be deployed to azure.
The app works fine, 100%, but the web page I have to manage admin matters refuses to load.
It always displays internal server error. I'm using express and viewing the logs but they say nothing useful. The app doesn't crash so I cant understand why it wont display.
This is the simple hello world code I'm using for testing, and even that wont display.
var express = require('express');
var app = express();
app.use(express.static('website'));
app.listen(80);
Does anyone have any idea what could be the problem?
Edit: I forgot to include that I do set the port environment variable
var port = process.env.PORT || 80;
var baseHost = process.env.WEBSITE_HOSTNAME || 'localhost';
Thats at the top of my server.js, sorry about that.
guess your app is listening on the wrong port when running on Azure App Service.
you will have to get the port number from environment variable "process.env.port"
var app = require('express')();
var port = process.env.port || 8080; // 8080 for local or whatever number u want
var listener = app.listen(port, function(){
console.log('Listening on port ' + port);
});
Follow this blog to get a Node.js app working on Azure. I used this for a demo recently and it worked properly.
Create a Node.js web app in Azure App Service
You have to use GIT and Continuous Deployment to get Azure App Services to recognize and setup the right pieces for your node application to function, it also takes care of node packages for you automatically.
Hope this helps, TehDude
Try turning on logging to get a better idea of what's going on
From How to debug a Node.js web app in Azure App Service:
To enable the logging of stdout and stderr streams, you must create an
IISNode.yml file at the root of your Node.js application and add the
following:
loggingEnabled: true
This enables the logging of stderr and stdout from your Node.js
application.
The IISNode.yml file can also be used to control whether friendly
errors or developer errors are returned to the browser when a failure
occurs. To enable developer errors, add the following line to the
IISNode.yml file:
devErrorsEnabled: true
Once this option is enabled, IISNode will return the last 64K of
information sent to stderr instead of a friendly error such as "an
internal server error occurred".
Node.js application running on Azure Web Apps Service, is hosted on IIS handled mapping via IISNode, which gives a Named Pipe to receive the incoming requests, not a TCP port like you would use when running locally.
This Named Pipe has been defined as the port in Node.js runtime on Azure Web Apps. You can define the port in your app like: process.env.PORT || 3000, with which your app can run on Azure or locally.

Node.js hosting with Socket.io client support?

I made a socket.io client app which connects to my socket.io server and then they communicate whatever they need to.
When I do it locally on one machine or even on two different local machines, everything works fine. So I tried to deploy the client on cloud9 and it keeps throwing this error:
net.js:540
connectReq = self._handle.connect(address, port);
Error: No local connects allowed for security purposes
at connect (net.js:540:31)
at net.js:607:9
at Array.0 (dns.js:88:18)
at EventEmitter._tickCallback (node.js:190:38)
The client code is, where [ip-address] is my servers IP address:
var io = require('socket.io-client'),
socket = io.connect('[ip-address]', {
port: 1337
});
Is there a way to run such a socket.io client at c9.io?
Did they block it because of this article?
Are there any free node.js hosting solutions where one could run a socket.io client application like the one above?
Thanks.
Depending on your needs you could create a free Heroku account. You wont have access to a database, and you're limited in resources, but if the app is small enough and efficient enough it could suffice.
Nodejitsu is currently free node.js hosting solution where everything works (including socket.io)
OpenShift uses Port 8080 and Heroku 3000.
The Client code has to be like this:
// Wrong!:
// mySocket = io.connect(host, port);
// Right:
mySocket = io();
mySocket.on(....);
The Server code has to look like this:
var express = require('express'),
app = express(),
server = require('http').Server(app),
io = require('socket.io')(server);
app.use(express.static('path/to/public/html'));
server.listen(8080); // OpenShift 8080, Heroku 3000
io.on(...);
https://devcenter.heroku.com/articles/node-websockets#create-a-socket-io-client

Resources