How to run two servers on Heroku? - node.js

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

Related

Access dynamic port number in Webpack

I'm building an electron/nodejs/react application that will run on a users localhost (e.g. localhost:8080).
I'm using Portfinder to locate a free port and run the application on that port.
portfinder
.getPortPromise()
.then(port => {
app.listen(port, function() {
console.log("Server started on localhost:" + port + ", Node ENV " + app.get("env"));
});
})
.catch(err => {
//Could not get a free port, `err` contains the reason.
});
In the React app, I need to access this port number to send http requests back to the node server.
Is there a way to access this dynamically created port # in React or Webpack outside of using env variables in package.json or .env file?
If the same server is used for serving client and backend APIs, then you can use relative routes (/api/getData). The client will hit the same server.
If your backend is hosted on a different server, then you need to pass the information to client manually.

Host a Node.js bot (express and botkit)

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.

404 - from nginx application to remote servers localhost?

I am new to react, and wanted to deploy a site to my domain with Nginx. I need to make the application to be able to fetch from client side, to the localhost of the remote server hosting the site with Nginx. I know exposing this many details might make security experts and hackers either drool or shake their heads. But I am losing my sanity from this.
This is a filtered version of my Node.js express service running on the remote server:
const express = require("express")
const cors = require("cors")
const app = express();
const PORT = 1234;
const spawn = require("child_process").spawn;
app.use(cors())
app.listen(PORT, function(){
console.log(`listening on port:${PORT}...`)
})
app.get("/api/play/:choice", function(req,res){
pythonProcess = spawn('python',["./script.py", req.params.choice]);
pythonProcess.stdout.on('data', function(data) {
res.status(200).send(data.toString('utf-8'))})
})
this is how I am fetching from the deployed react application. The public IP of the droplet I am using
fetch(`104.248.28.88/1234/api/play/rock`)
Change the fetch to replace the / with a : to indicate port, rather than directory
fetch("104.248.28.88:1234/api/play/rock")

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!

heroku app crashes with socket.io

The application, an API server meant to communicate with a Unity client was working just fine, until I added sockets. Manually testing socket.io using the chrome extension socket.io tester demonstrated that it is working just great on my local machine. Now that I've deployed it to heroku, it doesn't work. It crashes right off.
Typically, answers to this issue are all about the PORT not being set correctly, but in this case I have set the port to process.env.PORT, so there shouldn't be any problems with that. My app was working just fine until I added socket.io.
Here is my basic server file:
import express from "express"
import mongoose from "mongoose"
import http from "http"
import config from "./config/index.js"
mongoose.Promise = global.Promise
// mongo
mongoose.connect(config.mongo.uri)
mongoose.connection.on("error", function(err) {
console.error("MongoDB services error: " + err)
})
// server
let app = express()
let server = http.createServer(app)
let socketio = require("socket.io")(server)
require("./socketio").default(socketio)
require("./express").default(app)
require("./api").default(app)
// start
server.listen(config.port, function () {
console.log("Listening on port: " + config.port)
})
export default app
Is there anything here to imply why the app may be crashing?
So for anyone who might also be having trouble with Heroku in this way. It turns out that I had my config file with the proper port setting listed in my .gitignore file. (I don't know how it got there!) I wasn't paying attention to the logs when the app was starting up so I was missing the log that it the config file was missing. I was impressed by how Heroku's staff was able to point that out.

Resources