Access dynamic port number in Webpack - node.js

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.

Related

How to connect to node.js server from any ip

I want to create a private backend for an application I want to make, but I am having trouble connecting to my node server, I have the basic stuff right now,
var http = require("http");
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('<html><body><h1>Hello World</h1></body></html>');
}).listen(3000);
console.log('Server running on port 300.')
But this only works for https://localhost:3000/, how do I make it so that if I have a separate computer on a separate connection, I can connect to this server?
I am not interested in just opening it to everyone but just to specific client IP's...
If the client IP's are on the same network as you, you can check out this question
If you want people from anywhere to access your application, I suggest hosting it on something like Heroku (very easy to deploy, pretty good free tier). You can then create a whitelist of IPs in your express application.
I would suggest for any port forwarding using ngrok or configuration in your router
For downloading ngrok https://ngrok.com/ go to this link
For configuration your router it will take some searching in google based on what type of router your using
You must mention that your localhost or Nat Ip and your public IP to resolve here is NOIP refrence https://www.noip.com/support/knowledgebase/general-port-forwarding-guide/
As you specified that you want the backend to be private, such that it can only be accessed by your specified node. You will have to host this node server on a cloud service or you can host it on your local machine by opening a port for the node server. Suppose you host the node server on port 1234 on your local machine ip address.
You can start the node server on localhost and your desired port, but you need to allow requests to the particular port.
Now you need to check for the origin of the request that your node server receives and validate that, so that only your private node(computer) can access the node server. You can do that by validating the hostname using express, you can get the hostname of the request in express.js using req.hostname or req.headers.host.
You would need to use express.js for this functionality and the code would be as follows
let express = require('express');
let app = express();
let allowedHost = 134.32.234.3 // the hostname which is allowed to access the backend
let port = 1234; // desired port
let host = 0.0.0.0 // desired host; 0.0.0.0 to host on your ip
app.get((req, res) => {
res.header('Content-Type', 'text/html');
if(req.hostname == allowedHost){
res.send('<html><body><h1>Hello World</h1></body></html>');
}
else{
res.send('Connection not allowed');
}
});
app.listen(host, port, ()=>{
console.log(`The server is running on http://${host}:${port}`);
}

Frontend to backend request seems to be wrong

Hi I am trying to deploy a simple React + Node app to a remote server. Backend started with pm2 and seems ok, frontend works with nginx, but when I try to get data from the db, console sends message
GET http://localhost:8080/v1/names net :: ERR_CONNECTION_REFUSED xhr.js: 177
Not too sure if I need to replace request url with the server IP instead of localhost.
Any help is greatly appreciated.
Yes, you should change all your request from localhost to your deployed address, I would also propose you take a look at .env Files to do it. Node.js Everywhere with Environment Variables!.
usually, you should use .env files to automatically choose the good address when deployed and when coding locally. have a nice day.
example of code with a .env file from the back with mongoose.
mongoose
.connect(
`mongodb+srv://${process.env.DB_USER}:${process.env.DB_PASSWORD}#cluster0.qvs4c.mongodb.net/${process.env.DB_NAME}?retryWrites=true&w=majority`
)
.then(() => {
app.set("port", process.env.PORT || 5000);
app.listen(app.get("port"), function () {
console.log("Node app is running on port", app.get("port"));
});
})
.catch((err) => {
console.log(err);
});
example of my .env File.
DB_USER=thatsmydbuser
DB_PASSWORD=thatsmypassword123!
DB_NAME=thatsmydbname

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

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.

node.js hosting with SSL?

So say I have a node.js application that hosts both a HTTP and HTTPS server as described in the question: How to force SSL / https in Express.js
In my code I have the following:
// General configuration settings for production usage
app.configure(function () {
app.set('port', process.env.PORT || 3000);
app.set('sslport', process.env.SSLPORT || 4000);
...
}
http.createServer(app).listen(app.get('port'), function () {
winston.info('Express server listening on port ' + app.get('port'));
});
var options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem')
};
https.createServer(options, app).listen(app.get('sslport'), function () {
winston.info('Express server listening on port ' + app.get('sslport'));
});
Which works perfectly fine for a local running node server.
However, I want to publish my site to a cloud hosted provider like Azure Web Sites, Heroku, Nodejitsu, etc.
All of the cloud hosts seem to set a process.env.PORT value, but only the one. When my HTTPS server is created this usually results in the app crashing, as the PORT is already in use / access denied / etc.
So how do I create / host a site with a secure login page with only one port to work with!?
If you use Heroku you get SSL without needing to specify a port in nodejs. All you need to do is listen on the heroku PORT environment variable for http requests. Once uploaded to heroku you can address your heroku app using either https (on 443) or http (on port 80). Heroku routes either to your server.
Similarly if using elastic load balancing with EC2 you can make use of SSL termination at the load balancer, and again route to your node server listening on port 80 using using http. http://aws.amazon.com/elasticloadbalancing
In both cases you can use either self-signed or proper SSL certificates depending upon your need.

Resources