Custom domains for dashboard endpoint

Hi There!

A thought occurred to me and I was wondering whether its possible - can I configure Node-RED to server the dashboard on a custom domain?

For example https://demo.openmindmap.org/ui becomes https://website.openmindmap.org without having an apache or nginx doing the redirects/rewrites. In my case, the domain demo.openmindmap.org is hosted on Heroku where I can only specify the custom domains that go directly to Node-RED. But I can setup multiple domains on Heroku so that Node-RED would need to know that website. goes to /ui, i.e. it would need to do the routing.

The use-case here would be create blogs or demo-pages for designers or whatever in Node-RED and then have an endpoint that would exclusively show the dashboard.

I hope that this isn't a repetition of someone elses question!

Cheers!

Certainly. Lots of people are doing that.

The external domain name maps to an external IP address using DNS. This has nothing to do directly with the use of a web proxy service or not.

There are, however, lots of benefits for adding a proxy to the stack. Including performance, security and flexibility as well as giving a better user experience.

Well, Node-RED has a number of ways of delivering web pages of course. Not only UI but also http-in/-out pairings and uibuilder to mention a few. Speaking of uibuilder, I've previously done some proof of concept work around using it to create a content management system. There are lots of ways to achieve these outcomes just with Node-RED.

Me too!

But perhaps I should clarify what I mean. I've got an installation on Heroku which means I do a git push and Node-RED is deployed. At Heroku I can't configure a proxy, all I can do is setup an domain CNAME that points to the Heroku proxy. Sure if I had a bare metal server or AWS stack, then I could setup a proxy but that's not what I want to do.

Heroku is very limited in what one can do - by design so. What I specifically looking is mapping URL paths to domains:

nodered.example.com --> node-red flow editor
dashboard.example.com --> node-red dashboard, i.e. the equivalent to nodered.example.com/ui

It's the /ui that can't be mapped to the dashboard.example.com (via Heroku nor my DNS provider). The path part has to be proxied somehow. If the stack is just Node-RED running on an Heroku instance, then there is no room for a proxy (unless I setup an nginx/apache to run on Heroku and then do magic redirects).

Sure I could use a HTTP-in node to simulate that however then I can't use the dashboard components that assume they are reachable via /ui (or whatever is set in the settings.js). Alternatively is there a way to hook up the dashboard components to point to an http-out node to send back their content?

Turning the question around: is there a way to specify a domain for the dashboard within Node-RED? I.e. does the NR webserver do domain mapping to routes? It does some mapping, mapping /ui to the dashboard component. In the settings.js I can change the dashboard path but can I set it to a domain without a path?

I.e.:

  settings.ui = {
        path: "/",
        host: "dashboard.example.com"
  };

is what I'm looking for ... I'ven't tried it but it probably works :slight_smile:

As far as I know, you can only do that at the web server level. DNS takes care of only the domain name to IP address mapping.

"A CNAME record is used in lieu of an A record, when a domain or subdomain is an alias of another domain."

So You can use CNAMEs to map to different Heroku instances or to map different sub-domains to the same instance. But you cannot use them to map to a URI.

However, you could use Node-RED http-in/-out pairs to map from 1 URI to another using a redired (e.g. 301) response. Not very efficient though since you are forcing the browser to load twice and Node-RED to deliver twice.

No, for the reverse of the same reason. Domains and URI paths are not actually related. DNS services the former and the web server the latter. (*)

No, because there are two services required for that outcome.


(*) Actually, I suppose I should clarify that a web server that has proxy capabilities CAN re-route based on the source domain that a browser uses to do a request. But Node-RED's ExpressJS web server is not proxy capable itself (as far as I know).


I also note that it is possible to deploy a proxy to Heroku since there is at least 1 node.js based proxy library. So you could either achieve what you want using 2 Heroku instances or by embedding Node-RED into a custom node.js service that includes the proxy (theoretically - never tried of course).

1 Like

Thats what I wanted to know, so it's not possible with just simply red, node-red of course.

I did some quick ddg'ing and found this:

So there does seem to be a some middleware for doing this. I'm no NodeJS expert but it does seem there are possibilities out there.

The Rails router has this built in using constraints #justsaying :slight_smile:

Redirects can get messy if the underlying server does not know the domain changes, i.e., checking if domain is X then redirect to /ui but with the same or different domain? Plus I would have to hijack the /ui path in Node-RED - which does seem doable AFAIR.

Indeed, indeed! Why complicated when simple is simpler! I would tryout some middleware solution (if possible) before wrapping Node-RED in NodeJS proxy blanket.

Thanks for the detailed background info :+1:

Well, if you ever decide to try that, maybe it would be an interesting extension to uibuilder :grin:

Yes, it wasn't really a serious solution.

Seems more sensible, yes.

Good luck and let us know how you get on :slight_smile:

I think I might have a solution.

If I set the adminRoot to something like /fubar and the ui path to / (slash) and add a middleware (to the ui setting) that rejects anything that comes from the wrong domain, that should do the trick.

I'll give try and see what happens...

Ok that seems to work, I just tested this on my localhost installation, in settings.js I did this:

  httpAdminRoot: '/cfg',
  httpAdminMiddleware: [
    (req,res,next) => {
        if ( req.host == "127.0.0.1" ) {
          next();
        } else {
          res.status(404).send("Not Found - " + req.host );
        }
    }
  ],

  /*** somewhere further down ***/

  ui: {
    path: "/",
    middleware: [
      (req, res, next) => {
        if ( req.hostname == "localhost" ) {
          next();
        } else {
          res.status(404).send("Not Found - " + req.hostname );
        }
      }
    ],
    ioMiddleware: [
      /* need to do the same for the socket */
    ]
  },

This meant that I had the following:

http://localhost/cfg --> flow editor
http://127.0.0.1/cfg --> 404 Not Found

http://localhost/ --> 404 Not Found
http://127.0.0.1/ --> Dashboard

The next step would be to try this out at Heroku and check whether the domain (and which header with domain) is passed through to the Node-RED endpoint.

Looks good.

Just to let you know that you should be able to use the same technique with uibuilder endpoints since it has its own middleware capabilities both for all uibuilder endpoints in settings.js. The next release of uibuilder will also be adding middleware for individual uibuilder node instances as well as a global setting. Also worth noting that uibuilder also has middleware for Socket.IO connections as well as ExpressJS.

1 Like

I've tried on heroku and it does work. I have also updated my heroku node-red base repo so that it becomes a matter of just setting an env variable.

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.