Causing a HTTP-IN node to process a request from an independent http server

Hi All,

we have been using Node-Red in production for some years now, and everybody who knows me here knows I'm a big fan.

Up to this point we have mostly been using NR on local machines with no incoming internet access, but now have applications for running it with public ports exposed.

We've achieved this currently by producing our own native HTTP/HTTPS servers within a flow, and then exposing these ports as highly controlled single points of entry (e.g. we produced a WS port with custom authentication, etc., which can also respond to posts.... either with local certs and make it native https or behind an https endpoint - e.g. elastic load balancer by Amazon). This gives us confidence that we are only exposing what we want to expose.

The thought came to me that since I'm already abusing the NR internals, there should be some 'simple' way to take a request that arrives on our native nodejs server, and pass the request indirectly into some nominated HTTP-In node.
e.g. to have a list of 'allowed' urls, and if the url matches and auth succeeds, call the 'nodeApp' express server middleware so this request then hits the 'normal' NR flows.

The HTTP-IN node seems to register itself using RED.httpNode.xxx and remove itself from RED.httpNode._router.stack

Does this kind of approach seem viable? What challenges do you anticipate? Any hints on What to call on the express server would be useful :).

best regards,

Simon

so, to reveal what I have found.
simply put, if you have access to require, then the code snippet below allows you to send requests directly to any HTTP-IN node that you know the url of.
I've not tested HTTPS yet, but am assuming it will work.
I am confused as to why I never see 'done request', but the HTTP-IN-> HTTP-OUT in the flow for 'GET' with url '/haha' works just fine.
So you can expose just PARTS of your HTTP in flows via an alternative port, or even an https port.

var red = require('node-red');
var app = red.httpNode;
const serverequest = (request, res) => {
    request.parsedurl = url.parse(request.url,true);
    console.log('raw request');
    if (request.parsedurl.pathname === '/haha'){
        app.handle(request, res, (err)=>{
            console.log('done request');
        });
        return;
    }
    res.writeHead(400);
    res.end('');
    return;
}
let server = http.createServer(options, serverequest);

Unless I've misunderstood (a common problem for me to be sure), what you are trying to achieve appears to be to create a custom reverse proxy?

If that is the case, why not simply use a tool specifically written for that purpose such as NGINX, Caddy or HAproxy? (OK so 2 of those aren't just reverse proxies of course but hopefully you get my drift). Why reinvent the wheel?

Hi Julian,
haha... because to run our stuff we need no dependencies and no installation on windows, mac, linux, aws. It's NR inside a single exe. So it's sort of got to be self contained; can't go asking a customer to install extra bits because they are normally not so technical, and so then a barrier to sale.
Even asking them to install letsencrypt would be a struggle.
But yes, it's acting like how I would normally use Apache, only exposing the bits I want exposed, and adding some custom auth.
(or my favourite - HAProxy - brilliant at the job once you get6 your head around it).
br,
Simon

OK, so incorrect assumption by me that you were offering a pre-built device.

In that case, it makes more sense.

An alternative would be to take control of ExpressJS yourself. Using Node-RED as an embedded app within your own app. Instructions for that are in the docs. I've done it previously (very simple version though) and it works fine. You then could use ExpressJS middleware to do what you want.

Might be simpler than messing with the http-in node?

it really is as simple as calling app.handle() with the request :). I just love nodejs & NR....

3 Likes