# Use Node-RED as reverse proxy

**URL:** <https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017>\
**Category:** General\
**Created:** [7 July 2019 23:17 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017 "2019-07-07T23:17:04Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [7 July 2019 23:17 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/1 "2019-07-07T23:17:04Z")

</div>

Hi folks,

During development of my camera-viewer, I'm having some security issues (concerning [CORS](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image)). Summarized: when I show a camera Mjpeg stream from **host X** on my Node-RED dashboard (from **host Y** ), I cannot get access to the underlying image data. So you can display the images (using an img or video element), but you cannot get the image (as bytes) from those elements. It is some copyright protection system. You can only get around it when host X sends a _Access-Control-Allow-Origin_ http header variable, but I cannot rely on that ... 🤬

So I want to have my host Y to supply **both** my Node-RED dashboard and also my camera Mjpeg stream. I assume my browser won't start complaining again about cross-domain issues ... And I'm highly allergic for combining multiple tools, thus I would like my Node-RED flow to offer both the dashboard and also the camera mjpeg stream (without having to use other tools!!). So I assume Node-RED has to behave as a _reverse proxy_.

Let's assume I want to decode this [public](https://webcam1.lpl.org/axis-cgi/mjpg/video.cgi) online mjpeg stream:

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/3/34dba57d241f867e912925a18de161dcdfb8e601.png)

I could solve this with my multipart-stream **decoder** node (which decodes the camera mjpeg stream to separate images), combined with my multpart-stream **encoder** node (which encodes the camera images back to an mjpeg stream):

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/2/2960c84718ca594f1c7fb4d41ef89be994d72b29.png)

```auto
[{"id":"254b4aec.9c6f06","type":"http in","z":"8bb35f74.82618","name":"","url":"/mjpeg_test","method":"get","upload":false,"swaggerDoc":"","x":400,"y":320,"wires":[["b8e4e8b7.f45358"]]},{"id":"4c392f29.e336a","type":"multipart-decoder","z":"8bb35f74.82618","name":"","ret":"bin","url":"https://webcam1.lpl.org/axis-cgi/mjpg/video.cgi","tls":"","delay":0,"maximum":1000000,"blockSize":1,"x":390,"y":260,"wires":[["b8e4e8b7.f45358"]]},{"id":"b8e4e8b7.f45358","type":"multipart-encoder","z":"8bb35f74.82618","name":"","statusCode":"","ignoreMessages":false,"outputOneNew":false,"outputIfSingle":true,"outputIfAll":false,"globalHeaders":{"Content-Type":"multipart/x-mixed-replace;boundary=--myboundary","Connection":"keep-alive","Expires":"Fri, 01 Jan 1990 00:00:00 GMT","Cache-Control":"no-cache, no-store, max-age=0, must-revalidate","Pragma":"no-cache"},"partHeaders":{"Content-Type":"image/jpeg"},"destination":"all","highWaterMark":"500000","x":620,"y":300,"wires":[[]]},{"id":"3f7224a8.1503ec","type":"inject","z":"8bb35f74.82618","name":"Start stream","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":"","x":190,"y":260,"wires":[["4c392f29.e336a"]]}]

```

And then indeed my camera stream is available via my Node-RED hostname:

![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/4/4f3c34bfd144f40395c79160aeb22c4a147486fa.png)

So far so good. But this involves a lot of processing (mostly for finding boundary sequences in the large image chunks) on my poor Raspberry, which is not what I want. Indeed now my Node-RED flow needs to separate individual images, concatenate them together again, and then my browser has to separate the individual images again ...

**I would like to pass the (infinite stream of) data chunks from the camera mjpeg stream straight to my browser (via the Node-RED flow), without any processing**. What would be the best way to accomplish that? Perhaps with a combination of httpin/httprequest/httpout or anything else ???

Thanks !  
Bart

---

<div class="post-metadata">

**Author:** ![afelix](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/afelix/32/9743_2.png) [@afelix](https://discourse.nodered.org/u/afelix)\
**Post date:** [8 July 2019 06:51 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/2 "2019-07-08T06:51:59Z")

</div>

Quick question, is the camera you're trying to get the stream from a similar model AXIS or should I think of a different PTZ based or even different brand camera? Most of them have the mjpeg stream defined in cgi files, and this one just passes out jpeg images through it with a set content length. I remember messing with those mjpeg streams for AXIS some 6 years ago, but I've no idea if I can find those python files back, they didn't seem worth saving elsewhere so they're probably still on my old laptop.

What I do remember is that AXIS is friendly enough to write a manual on API access to those cameras through CGI: [https://www.axis.com/files/manuals/HTTP\_API\_VAPIX\_2.pdf](https://www.axis.com/files/manuals/HTTP_API_VAPIX_2.pdf)  
`/axis-cgi/mjpg/video.cgi` gets you a multi-part jpeg stream of constant images, as if a video is being displayed. Section 5.2 of the manual might get you API calls for this thing. Instead of requesting the stream you could request individual images every X second(s) instead.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [8 July 2019 11:24 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/3 "2019-07-08T11:24:35Z")

</div>

Hi Lena (@afelix),

> [@afelix](#):
>
> this one just passes out jpeg images through it with a set content length

Yes I know. Then indeed the parsing is much faster. But I have experienced in the last years (during development of my [node-red-contrib-multipart-stream-decoder](https://github.com/bartbutenaers/node-red-contrib-multipart-stream-decoder) node) that you cannot count on it. My decoder node makes use of the content-length header if available, and will search through all bytes otherwise. Lot's of camera's don't give the length, and I want a general solution that everybody can use ...

But in this case I don't want ANY processing to be done by Node-RED on the data chunks. _Node-RED receives data chunks from a source, and just need to pass those chunks to the receiver._ And I'm pretty sure that there will be lots of other use cases, for people (like me) that want to use their Node-RED to quickly setup a reverse-proxy.

When looking at the code of the [httprequest](https://github.com/node-red/node-red/blob/master/packages/node_modules/%40node-red/nodes/core/io/21-httprequest.js#L312) node, I don't see any chunk related code anymore (since it has been rewritten by Hitachi to use the 'request' library underneath). On the other hand the [node-red-contrib-http-multipart](https://github.com/sax1johno/node-red-contrib-http-multipart/blob/master/httpInMultipart.js) node 'could' perhaps do the job, but then the reverse proxy solution would only be usable for multipart responses (not for normal finite responses). Moreover that node is parsing the multipart headers, which is again a bit useless since the (dashboard) browser will do that also afterwards.

_Does anybody know if I can just pass the data chunks through Node-RED, or do I have to develop a new custom node (e.g. based on this [article](https://codeforgeek.com/reverse-proxy-using-expressjs/) ?)? If I should have to develop something on my own, does anybody have some info to get me started and stuff that I need to think about??_

---

<div class="post-metadata">

**Author:** ![afelix](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/afelix/32/9743_2.png) [@afelix](https://discourse.nodered.org/u/afelix)\
**Post date:** [8 July 2019 11:54 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/4 "2019-07-08T11:54:07Z")

</div>

Let me see if I can find something that different brands have in common for mjpeg streams. This is something I’ve to see in practice again before I can come up with more ideas.

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [8 July 2019 12:16 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/5 "2019-07-08T12:16:17Z")

</div>

`<pedant on>` I think in this case M stand for Motion... such that it is a stream of complete images`</pedant off>`

---

<div class="post-metadata">

**Author:** ![afelix](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/afelix/32/9743_2.png) [@afelix](https://discourse.nodered.org/u/afelix)\
**Post date:** [8 July 2019 12:31 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/6 "2019-07-08T12:31:35Z")

</div>

You’re right, the Axis docs confused me for a bit. I just checked it. Sorry for the confusion this might have caused others. Once again Lena, double-check before you speak please 🙂

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [8 July 2019 21:23 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/7 "2019-07-08T21:23:01Z")

</div>

In case somebody is reading this discussion afterwards, at first sight I don't think this could easily be implemented using the existing nodes:

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/2X/0/0f1f38ff9949f27abfbd1db5ee65b16392414f3c.png)

I **added** a few lines to the httprequest node code, to send an output message for every data chunk that arrives (instead of waiting for the entire response to arrive):

```auto
request(opts, function(err, res, body) {
    if(err){
        // Send error message
    }
    else{
        // Send (complete) response message
    }
}).on('data', function(data) {
    // Data-handler added to send an output message for every data chunk
    console.log('Chunk received with length ' + data.length);
    msg.payload = data; // decompressed data
    node.send(msg);
});

```

And indeed the **httprequest** node now sends an output message for every data chunk:

```auto
Chunk received with length 1664
Chunk received with length 6528
Chunk received with length 1472
Chunk received with length 6720

```

However the **httpout** node will give an error for every message (except for the first message):  
_**Error [ERR\_HTTP\_HEADERS\_SENT]: Cannot set headers after they are sent to the client**_

The httpout node expects a complete response, and will send it once and then it is considered to be completed. So dead end again ...

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [8 July 2019 22:10 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/8 "2019-07-08T22:10:02Z")

</div>

Well don't send to msg.res until it really is complete. As it says just send it once

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [9 July 2019 07:09 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/9 "2019-07-09T07:09:35Z")

</div>

Hey Dave (@dceejay),  
Do you mean I can send data chunks (via input messages) to the httpout node, which are immediately written to the client socket. And that I can keep the socket open (infinitely since the stream has no end)?

---

<div class="post-metadata">

**Author:** ![dceejay](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/dceejay/32/38_2.png) [@dceejay](https://discourse.nodered.org/u/dceejay)\
**Post date:** [9 July 2019 07:44 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/10 "2019-07-09T07:44:21Z")

</div>

Ah no, (Looked harder at your pic on a bigger screen) - the http out doesn't do that. I guess it must be possible to write a version that does - no idea if they can be versions of the same node.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [9 July 2019 10:59 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/11 "2019-07-09T10:59:10Z")

</div>

You could do http streaming but that doesn't really follow the Node-RED standard message-based approach does it?

I have wondered a few times whether Node-RED needed a "parallel" set of features that supported true streaming. I don't have the knowledge though as to whether that would be a reasonable approach.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [9 July 2019 22:11 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/12 "2019-07-09T22:11:55Z")

</div>

Hey guys,

I wrote an **experimental** node as a prove-of-concept: [node-red-contrib-reverse-proxy](https://github.com/bartbutenaers/node-red-contrib-http-proxy/blob/master/README.md). It contains currently only the basic functionality to allow me to redirect my mjpeg test stream via Node-RED. And since this is the first time ever that I work with proxies, please be kind/patient in your feedback 😉

Don't even know if this a good way of working to integrate it into Node-RED.  
But at least this way I can learn from it ...

You can install it directly from my Github page via the command in the above link.

---

<div class="post-metadata">

**Author:** ![TotallyInformation](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/totallyinformation/32/31_2.png) [@TotallyInformation](https://discourse.nodered.org/u/TotallyInformation)\
**Post date:** [9 July 2019 23:08 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/13 "2019-07-09T23:08:05Z")

</div>

Only taken a quick look at the code for interest as I don't need this capability myself right now. Seems a straight-forward solution. Not sure what the performance will be like.

One small thing, you have `console.log` on error where you could have `RED.log.error` to integrate properly to Node-RED logging.

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [14 July 2019 21:43 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/14 "2019-07-14T21:43:46Z")

</div>

After reading through all the fan mail about this reverse-proxy node, it became immediately obvious that the entire community was excited to get new functionality. Not ... 🥺

So I have added a bunch of new features, and I have added a lot of information and examples on the [readme](https://github.com/bartbutenaers/node-red-contrib-http-proxy/blob/master/README.md) page.

Julian (@TotallyInformation), thanks for your response! I have added a [performance test](https://github.com/bartbutenaers/node-red-contrib-reverse-proxy/blob/master/README.md#performance) in the readme page. It is not a very professional benchmark, but for my personal use case it is sufficient: it shows me that my poor Raspberry Pi 3 won't die after a slowly and painful dead, when I would start proxying my Mjpeg streams via Node-RED 🥳 🍾 🍰

Unless my test is incorrect ...

---

<div class="post-metadata">

**Author:** ![krambriw](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/krambriw/32/5429_2.png) [@krambriw](https://discourse.nodered.org/u/krambriw)\
**Post date:** [15 July 2019 08:18 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/15 "2019-07-15T08:18:51Z")

</div>

Great work Bart!  
I just wonder some few things. I understand the thing you explained about hiding credentials and the problem accessing IP cameras due to security exceptions,,,,I think

Besides just viewing video in attended mode, do you think this node you have developed also could make it possible for some kind of AI analyze _inside_ NR (by sending the stream further to another "analyzer" node or some external component)? As well as centralized recording...

---

<div class="post-metadata">

**Author:** ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)\
**Post date:** [15 July 2019 08:54 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/16 "2019-07-15T08:54:16Z")

</div>

@BartButenaers - Bart, your readme ends with

> Rermarks:
> 
> - The Y-axis contains a percentage of the overal CPU usage (i.e. a sum of the 4 cores).
> - Of course there is _ **NO processing** _ of the data chunks involved, since the Mjpeg stream is decoded (into separate images) in the dashboard (i.e. in the browser and not on my Raspberry).
> 
> When I open the

It should be Remarks (0ne 'r') and don't leave me hanging!! When you open what?😂

---

<div class="post-metadata">

**Author:** ![BartButenaers](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/bartbutenaers/32/10476_2.png) [@BartButenaers](https://discourse.nodered.org/u/BartButenaers)\
**Post date:** [15 July 2019 21:26 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/17 "2019-07-15T21:26:20Z")

</div>

> [@krambriw](#):
>
> I understand the thing you explained ,,,,I think

Hey Walter (@krambriw), I try to add as much information as possible. Novice users won't need it, but as soon as they become more advanced they know where to find it. But if it isn't clear for skilled people like you, I definitely have to find a way to simplify my explanation somehow. Will keep you updated ...

> [@krambriw](#):
>
> by sending the stream further to another "analyzer" node or some external component

If I'm not mistaken, I have read somewhere that Nick regretted that he had introduced (in the past) the exchange of the http request/response objects via messages. **But not sure about it !!!!!!!!!!** I thought because you could run into problems since those objects cannot simply be converted to json. For example in the future there will be pluggable custom wiring mechanisms, so I assume you cannot simply pass the request/response objects in messages - via some 'remote' wire - to another Node-RED instance.  
Therefore I don't think this is the way to go when you want streaming ...

> [@zenofmud](#):
>
> don't leave me hanging!! When you open what?

Paul (@zenofmud), unbelievable that you have read to the end of my readme 😂. I find this very suspicious ... Or you are some kind of masochist, or your Chinese nanny has teached you read from bottom to top?  
I have removed the open end, which means there will be no sequel next year...

---

<div class="post-metadata">

**Author:** ![zenofmud](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/zenofmud/32/316_2.png) [@zenofmud](https://discourse.nodered.org/u/zenofmud)\
**Post date:** [15 July 2019 22:41 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/18 "2019-07-15T22:41:11Z")

</div>

But...but...now I'll never know if the butler actually did it 😭

(while I read it, I never said I understood it 😊)

---

<div class="post-metadata">

**Author:** ![kenime](https://avatars.discourse-cdn.com/v4/letter/k/a88e4f/32.png) [@kenime](https://discourse.nodered.org/u/kenime)\
**Post date:** [16 July 2019 00:58 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/19 "2019-07-16T00:58:28Z")

</div>

I have read through the code on my mobile, a few notes:

1. can we receieve the config from msg? The usual trick is to set parameters like

```auto
const url = msg.params.url || config.url;

```

1. seems error event from http-proxy is not handled, not sure what would happen if there is error (e.g. Target url not found)

2. is it possible to return a msg instead of directly send the http response? Some people may want to post process the proxy result

3. will the response header "polluted" by the proxy's response header? One of your use case is to hide internal resource link and you will definitely not hoping for exposing proxy headers to actual response header

---

<div class="post-metadata">

**Author:** ![krambriw](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/krambriw/32/5429_2.png) [@krambriw](https://discourse.nodered.org/u/krambriw)\
**Post date:** [16 July 2019 08:03 UTC](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017/20 "2019-07-16T08:03:53Z")

</div>

Hi Bart, what you have written is fine, I do understand. Eventually what could be better highlighted is the absolute benefits & advantages & why. I had some difficulties to really get that at first glance

What I mean is maybe best explained with a typical use case example related to my own needs & thoughts. Assume I would like to build a gui for video viewing & management. If I do this "without thinking" I quickly go ahead and configure a Dashboard with direct links to my ip-cameras. This you can easily do out-of-the-NR-box

If I then lack a middle-ware in between handling the logon, like Motion does, I would reveal the credentials of my cameras (just have to use the inspect function in the browser). This might be ok if you just restrict viewing while on your local home network. But as soon as you would like to expose to the outside or have concerns that not everyone on the same network should have access, then you will face problems. I can imagine if setting up a small/midsize NR system with video managing as a commercial product, this would certianly be something to worry about

I do not know if this was a good example since I might have a setup that is already taking care of stuff like this. My setup is as below and maybe Motion actualy works as a proxy server when connecting ip cameras? And I access my home network from outside via VPN. Only thing not protected is that anyone connected to our home network can access the Dashboard

IP & USB Cameras \<-\> Motion \<-\> NR \<-\> Dashboard w Video Views \<-\> VPN Server \<-\> Router \<-\> Internet

[Next page](https://discourse.nodered.org/t/use-node-red-as-reverse-proxy/13017.md?page=2)
