Hacker News new | past | comments | ask | show | jobs | submit login
Redbird: A modern reverse proxy for Node (github.com/optimalbits)
136 points by Immortalin on Nov 5, 2018 | hide | past | favorite | 74 comments



I am one of those JS guys who like to put JS/Node.js everywhere, but I do not get the problem Redbird is trying to solve: the Express.js doc is quite clear that for serious things, you should use a dedicated http server. [1]

If you just want reverse-proxying, you can choose between the simplicity of Caddy or the power of Nginx (or Apache). Why would I want to run a JS app (that I know will be less performant) to do that?

  [1] https://expressjs.com/en/advanced/best-practice-performance.html


> If you just want reverse-proxying, you can choose between the simplicity of Caddy or the power of Nginx (or Apache). Why would I want to run a JS app (that I know will be less performant) to do that?

The same reason you'd use Caddy over Nginx or Apache, why use the former over the the latter when the latter already exist and are faster? Because someone who knows Go but not C can customize its codebase, just like someone who knows JS but not C or Go can modify Redbird's.

If Node.js is good enough to build and run servers then it's good enough to build reverse proxies.


I have used apache since version 1.0 came out. I have never needed to modify the code.

If you use this logic, you would not be able to run Linux because it is written in C, correct?


No, not correct. Why do you think it's okay to immediately jump to an absurd conclusion?

There's value in being able to modify the software you're using. That doesn't mean you throw out absolutely everything every single time you want to appreciate that value.


There are cases when performance is not your main focus but simplicity of use is. Like during development. I'd of course never use this in production, but it's perfect for my development needs.


I agree with the sentiment, but using nginx as a proxy is reasonably easy (at least after you make one that works and can reuse that configuration.)

The advantage of developing on as similar a platform to the projected production platform is that when you do deploy to a real environment, there are fewer nasty surprises.


How easy is it to use nginx for dynamic proxying? Wondering, because the need I have is to be able to dynamically route requests to ephemeral flask apps that could be on a different host/port at any given moment. Not my design BTW, but it's what I need to do.

The thought was to have node manage the flask processes and another tracker service which would dynamically proxy to the apps. Can nginx provide this? Forgive my ignorance, just new to the concept of dynamic proxying.


nginx is just a web server so it doesn't have dynamic programming capabilities. However, if you wanted to do something like that from nginx you could script it in Lua using OpenResty https://github.com/openresty/


It is not reasonably easy, I can't set it up completely with "git clone" and it does not stay inside the project (that's an issue when your developers use a huge variety of operating systems with varying installed and configured software). That means a lot of time lost during problem solving with the hundreds of developers I work with, most of them have never even heard about nginx, they're developers, not sysadmins.

There absolutely should not be any nasty surprises with switching a reverse proxy, and you can cover that with end to end tests. Such issue would be a bug in the reverse proxy.

Of course there are things like Docker, but that implies performance issues on Mac.


> If you just want reverse-proxying, you can choose between the simplicity of Caddy or the power of Nginx (or Apache). Why would I want to run a JS app (that I know will be less performant) to do that?

I don't have the numbers to back this up, but I would be inclined to believe that a Node.js implemented reverse-proxy would outperform Apache.


- node (whose main reason for existing is event driven IO) is in the same order of magnitude as nginx (whose main reason for existing is also event driven IO). I think sometimes people think node is ruby/python/php levels of performance. It isn't.

- And as another comment mentions, developer productivity may be better than minor performance difference - you mentioned Caddy, same rationale applies here.

- nginx is also a bit crippled as useful features (like dynamic reconfig) are only in the proprietary nginx plus.

- This has good defaults - having to set up the seperate webserver for ACME is a pain, this is way easier.


Python: we use the node event loop too now (https://magic.io/blog/uvloop-blazing-fast-python-networking/).

But actually, you could have setup a pure Python server instead of nginx for the last 10 years with twisted.

Not that you should not consider uring nginx anyway: it deals with caching, load balancing, has great tutorials, it's battle tested, and has tons of pluging.

But performance wise, WSGI is not Python.


Sure, I mentioned Tornado a few minutes before you posted this. Twisted obviously counts too, I dislike the non-PEP8 coding style it uses but that's off topic. I love Python's non blocking features, they're just not in the mainline VM right now. Here's hoping for a libuv or whatever else non blocking Python 4 VM / stdlib.


Asyncio has been in the the mainline VM for quite some time.


Yep, the stdlib just needs to use it. In nodeland blocking is the exception: that's not yet the case in Python.


Do you know of a performance benchmark that shows the current status? I can't find many that describe node not at those levels of performance, Especially against Ruby.


Sure: https://iwf1.com/apache-vs-nginx-vs-node-js-and-what-it-mean...

I haven't seen anyone compare Ruby to node perf, unless there's a non blocking variant of Ruby (looks like nio4r), in which case it would have similar perf.

Likewise node vs Python Tornado would be a good comparison.

Thing is, nio4r and Tornado aren't the standard library. Whereas node's stdlib is: node's file and socket read operations etc are non blocking, Python and Ruby equivs are not.

Also (addressing weird moderation - sudden downvotes when I mentioned other languages): please don't turn this into a lang tribal thing: I personally think Python is a better language than JavaScript, it just blocks by default. This isn't a matter of preference, it's a fact.


That resource looks like node is faster than those other languages? I think you might be getting the down votes because your comment is being interpreted that it is slower.


> I think sometimes people think node is ruby/python/php levels of performance. It isn't.

Except, it is ruby/python/php slow: https://www.techempower.com/benchmarks/#section=data-r17&hw=...

All of PHP, Ruby, and Python beat Node.js in the above-linked benchmark.


Raw number crunching performance is similar with Node and Go. Python and ruby are in different league than them. https://benchmarksgame-team.pages.debian.net/benchmarksgame/...


Do you think this discussion or the OP is about "[r]aw number crunching performance" ?


I think the readme is missing a "why not" section. For example: why not use nginx instead, which more people have experience with.


Convenience is one

I've used redbird to create a local dev proxy that can run be via npm scripts (which were already in the repo) so our engineering team didn't have to run the entire constellation of docker containers if they were only working on frontend code, and the only setup required was `npm install` which they already needed to do

I do wish you could just `npm install nginx` though


how would npm install nginx be different from [yum|apt] install nginx?


Its a local installation, inside the folder, instead on the operating system. Also, other people will automatically install it when the package is saves inside the package.json or yarn file. You can also limit the version you want with these files, that the end user dont need to think about. Just yarn install :)


  serv() { docker run --rm --name "nginx-${1:-8000}" -p "${1:-8000}:80" "${@:2}" -v $PWD:/usr/share/nginx/html:ro caub/nginx-dev; }
this is what I do to run a local static server, you could run nginx with a config for proxying on docker as well

also yarn.. bleh, just npm, nowadays it's even faster (on linux)



I'd like to double-down here on the benefit of having a local installation of a reverse proxy vs what yum/apt gives you.

Though this is the main reason I use Caddy over Nginx. I have my Caddy executable and config for all my projects right there in the home root. I ssh into one of my cheap vps and I'm an `ls` away from remembering how to configure it.

Meanwhile, every time I use Nginx I have to remember where the different folders are that it uses, where the configs are, and how to even start/stop/reload it. I usually symlink its config to the home root and paste a few common commands into ~/README.md for future-me.

Obviously, at a larger scale where you're automating your machines, this doesn't really matter. But at any scale under that where you're sshing into different machines, it becomes a nice to have.


On top of what others said, ease of use during (team) development through simplicity and consistency - some developers have Macs, some have Linux, some have Windows - and no one wants a work project altering their system anyhow.


One reason might be that nginx is implemented in a memory-unsafe language.


As opposed to node with runtime implemented in C++?


"Because they can" is often the most fitting answer. Even a tiny feature is worthy to start a totally new project with a fancy name.


To be precise, I meant "why not use ..." comparison. I don't mind why the project was started. Whatever the reason, well done for getting it to this stage! But the other side - why should we be interested - is interesting :-)


One reason could be that it might be easier for node.js devs to read and understand its source code. I don't use the software nor have read its source code, though.


Sometimes I think that there are not enough of real problems to solve in the js world.

Too many people pumped into a tight space of the frontend development are creating in there another copy of the whole infrastructure while limited by the tools that weren't designed for that.


Node was designed to build networking applications just like this.


No, node was the realization that JS’s concurrency model could be applied to applications like this.


No? You're not even disagreeing with the parent.


I am, but it is subtle.


I used to use Redbird, but configuration is a bit weird and not very well described if you need to use Auto HTTPS feature. Project seems rather dead and bugs are solved very slow (upgrading to newer node version caused it to not install because of outdated dependency, iirc PR with solution were ready, but not merged for weeks (?)).

Finally I got rid of it and replaced it with Caddy webserver


I’m a fan of traefik. https://traefik.io

I’m not ready for full k8s, but traefik gives me ACME and detects my docker containers and routes them for me.

If I only need https redir I’ll use that or nginx.

I can Redbird being useful where you only have node as an option.


I mostly agree with the sentiment in other comments of just using nginx, but there is one standout feature here that looks incredibly useful:

> We have now support for automatic generation of SSL certificates using LetsEncrypt. Zero config setup for your TLS protected services that just works.

I've scripted this kind of letsencrypt certs automation before with certbot and nginx, which is fine but a 'just works' declarative plugin for nginx would be much nicer.

Does anything like this exist? Anyone have experience with using it? Asking here as googling brings up a bunch of outdated forum threads etc to wade through.


You can use acme.sh to automate certificate issuing, installation, verification, renewal and some server configuration: https://github.com/Neilpang/acme.sh


It's not nginx but Caddy had stupid easy SSL automation through LetsEncrypt.


From the roadmap section:

Automatic routing via Redis

Could anyone explain to me how does this work and what is automatic routing in this context?


I assume that instead of config file (or hardcoded values), they will use Redis store for mapping of the domains/target nodes. E.g. traffic from www.hacker.com is forwarded to 192.168.1.1, and traffic from www.news.com is forwarded to 192.168.1.2.


What are some good practices to install this as a service (to replace apache, for example). Do you just setup a systemd script or you have any common utility for this? I read about pm2 being a common choice. Do you recommend it? Is there any alternative for multiple app types apart from node?


I use PM2. It's very good, and it keeps things in the node ecosystem.


Pm2 isn't the best tool we could have, but it's probably the best one existing.

To all future users: don't call `pm2 start ...` too often one by one (like in .sh script) - it won't start all of these, just some of them (at least on raspberry, maybe faster cpu helps here), use "ecosystem" feature for starting multiple services


This looks excellent. Is it intended to be integrated with other Node libs? I.e. can I use it as an express middleware somehow, or is it explicitly intended as a standalone thing - more like Nginx-but-configured-with-JS-instead-of-a-weird-custom-language? I can see value in the latter too, but I'm curious about the motivation here.


Good question. I was also looking for an answer to this.

Would love to add some middleware to turn this into an OAuth2 proxy.


I had a similiar thought, although not OAuth2, of integration with something like authelia[1].

[1] https://github.com/clems4ever/authelia


0.2.3 released 4 years ago.

I don’t know, a last release that long ago doesn’t inspire faith in the health of the project.


It doesn't look like they're using GitHub releases. npm shows some much more recent versions: https://www.npmjs.com/package/redbird.


The last release was 0.8.0, about a month ago.


The releases on github are outdated.

https://github.com/OptimalBits/redbird/releases


Quite nice. node-http-proxy is awesome, lacks a few features (but has a few more such as websockets). Redbird has http2 as well.

But to be frank, we have used node-http-proxy and other stuff before. It doesn't end with development. People put this to reverse proxy API calls in production, and then the other stuff that this calls into - it also uses proxying to call more stuff. In general, if you find yourself using this as a "convenient, declarative way to route" in production, you _might potentially_ be digging yourself a hole. The lines between "harmless reverse proxying" and "service routing and discovery" can become thin.


This would be more useful for my team if it would also transpile into nginx configuration.


I'm surprised no one mentioned the threading situation in the comments. The main reason why you need a reverse proxy (like nginx) on top of your express app is because node.js is single-threaded. Yes, you can fork (which means a new process and IPC), but that's even more of a performance hog.

If you have to serve a large static file - guess what... no other request gets processed at the same time. It's a neat idea but until we get true multi-threading in Node.js, I'll stick with my nginx, thank you very much.


Wait, what?

Node is very happy to asyncronously stream chunks of data over HTTP. You could write a blocking server by collecting the whole response in memory and sending it out all at once, but that’s not required by Node.

This is literally the reason Node even exists, nonblocking I/O with a simple threading model. You can have a million open connections all asynchronously nibbling data as the buffers empty.


Was recently looking for a reverse proxy for a project at work that utilizes multiple webpack repos that eventually gets built into one big webapp.

Without a proxy your forced to only work on one area of the app at once so hopefully something like this will let me run all webpack instances under the same endpoint during dev.


I use hoxy[1] for a lot of similar use cases, e.g. integration testing third party code.

[1] https://github.com/greim/hoxy


https://github.com/webpack/webpack-dev-server

Would this work? Or what’s the issue you are referring to?


I'm pretty sure he's aware of Webpack's devserver. A common problem is multiple libraries (with different webpack configs) being built that are required inside a single app. I guess GP's approach is to run multiple devservers, all on a different port, and then put a reverse proxy in front of it.

Last I checked, webpack does support building multiple scripts (by turning the `entry` config setting into an array or object), but they'll all have the same settings (so that intermediate results used by multiple entry points only need to be built once). If webpack since added support for multiple entire configurations behind a single webpack dev server then that would be splendid of course, but last I checked they didn't.

We have a similar problem at my company that we build our frontend React code for the browser and for node, and the latter has subtly different build settings. Our solution is to run the webpack devserver for the browser, a webpack watch mode for the nodejs version, and then we run the nodejs version using nodemon so that it reloads whenever the webpack watch mode rebuilds. The nodejs version contains an expressjs reverse proxy to forward requests for things in the `assets` directory to the webpack devserver. It's messy, but it works. My biggest beef is that it's rather dissimilar from our production setup.

Of course if we'd done node+browser from the start we'd have written our code such that the node version could be run in node without a compilation step, but we were first frontend-only and then added server rendering, and by then the code already made use of a number of webpack-isms (such as weird require("raw!css!stylus!myfile.styl") type of stuff).


Webpack actually supports exporting an array of configurations. https://github.com/webpack/webpack-dev-server/tree/master/ex...


I like the simplicity of this but am weary of using it in production based on other commenters. I would find something like this very useful if it would generate nginx configs instead of trying to function as the reverse proxy.


Regarding proxies, could anyone recommend where to learn about implementing a proxy / proxy chain? a book, or online resource, etc.


Sorry, but what’s a reverse proxy?


It's where the server has a proxy that can fetch resources from different places. E.g. ServerA (proxy) get a request for /something, but then fetches it from ServerB (web server) and returns it to the client. It proxies the response to the client.

The comparison is a forward proxy, which the client has, and a reverse proxy is where it's on the server side.


Reverse proxies also often provide optional benefits like...

Load balancing, not having to run the webserver as root to bind to 80/443, caching responses, buffering, rate limiting, injecting headers, serving static assets, etc.


Got it. I'm actually doing it using nginx to forward to node... Didn't know that's how it was called...


What does “modern” mean in this context? ES6?


This makes a very nice letsencrypt proxy.


Yet another JavaScript project reinventing the wheel and badly at that. It seems the NodeJS community suffers from NIH syndrome more than others. This is a sign of lack of seniors and leadership.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: