I'm trying to understand how to use redbird as a reverse proxy (seems less work than nginx for a legacy node server but maybe I'm wrong) and I'm failing to understand their example in the readme file, can't find the answer elsewhere: https://github.com/OptimalBits/redbird
My setup: I have a node server running under "example.com" and I need to create a sub-domain (api.example.com). Right now the legacy app installed on the server redirects all trafic from port 80 to 443 and has a SSL cert installed (not LetsEncrypt as I said this is legacy and probably before getting a cert was free). This certificate only covers "example.com" and "www.example.com". After a few hours (ok, days) of trying to find the best way of adding a sub-domain (to be served through HTTPS too), this is how I thought it would work:
- Add the A-record for my sub-domain (api.example.com);
- Get a certificate for api.example.com from Let's Encrypt;
- Change the legacy app so it doesn't listen to port 80 (for the redirect)
- Change the legacy app so it listens to 7000 instead of 443
- Put my new app online and make it listen to 7001
- Setup Redbird to listen to 80 and redirect to 443
- Setup Redbird to register "example.com" and redirect requests to 7000 (with the existing cert)
- Setup Redbird to register "api.example.com" and redirect requests to 7001 (with my new cert)
Am I on the right path?
Note: I know redbird has a feature for getting ssl certificates automatically but since I have to use the legacy certificate for the main domain (example.com) I figured I couldn't use the automagical way.
I'm able to go through the list down to #6 but then the redbird documentation for HTTPS is confusing to me. Here's their example:
var redbird = new require('redbird')({
port: 8080, //??? => so this is the entry point? Why not 443 since we want only HTTPS?
// Specify filenames to default SSL certificates (in case SNI is not supported by the
// user's browser)
ssl: {
port: 8443, //??? => what is this port for? Is it our default HTTPS port (in my case 443?)
key: "certs/dev-key.pem",
cert: "certs/dev-cert.pem",
}
});
// Since we will only have one https host, we dont need to specify additional certificates.
redbird.register('localhost', 'http://localhost:8082', {ssl: true}); //??? => this is the port my request will be forwarded too... right?
What I think I gather from this is : traffic coming to localhost through port 8080 is redirected to port 8082. Right? But then what is 8443 for?
Barely understanding what's going on I tried the below:
var redbird = new require('redbird')({
port: 80,
secure: false,
// Specify filenames to default SSL certificates (in case SNI is not supported by the
// user's browser)
ssl: {
port: 443,
key: "/etc/cert/example.key",
cert: "/etc/cert/example.crt",
}
});
// Since we will only have one https host, we dont need to specify additional certificates.
redbird.register('example.com', 'http://localhost:7000', {ssl: true});
redbird.register('api.example.com', 'http://localhost:7001', {
ssl: {
key: "/etc/letsencrypt/api.example.key",
cert: "/etc/letsencrypt/api.example.crt"
}
});
Why don't we have HTTPS instead of HTTP in the second argument of redbird.register() ?
Needless to say the above does not work and when I open example.com from my browser or api.example.com, it responds : "ECONNRESET".
UPDATE: I was serving both node apps with HTTPS (on 7000 and 7001), and tried serving them to the proxy as HTTP. I got the proxy correctly forwarding the requests to the corresponding ports, BUT only the main (legacy) app (at "example.com") has the right SSL certificate. When I open "api.example.com" I get the warning saying the site is not secure...
Makes me wonder: is it ok to have a main domain with a certificate from say GoDaddy and a subdomain from LetsEncrypt? Is that the reason it's not working?
When I click in chrome at the "not secure" warning (when looking at api.example.com), it says Cetificate (invaild) and it show the certificate information for the main domain (example.com) instead of the certificat I configured for api.example.com...
UPDATE2: So I tried with getting a new certificate for my domain and all its subdomains (using the wildcard *.example.com and also noteworthy: *.example.com does not include example.com so it needs to be added manually). With the all-encapsulating certificate, the below code works but it a lot slower than without Redbird as a reverse proxy (I was expecting a difference but not that much, here we're talking about over 3 seconds difference - and the site being legacy and not optimized, those 3 seconds are on top of an excruciating 8 sec+ with cache disabled).
var redbird = new require('redbird')({
port: 80,
secure: true,
ssl: {
port: 443,
key: "/etc/letsencrypt/live/example.com/privkey.pem",
cert: "/etc/letsencrypt/live/example.com/cert.pem",
}
});
redbird.register('example.com', 'http://localhost:7000', {ssl: true});
redbird.register('www.example.com', 'http://localhost:7000', {ssl: true});
redbird.register('api.example.com', 'http://localhost:7001', {ssl: true});
Here are a few things I can deduce from this experience and it might help others:
- the port specified where 80 is in the above is the entry port for HTTP. If you specify in the same object the ssl part, redbird will redirect all HTTP traffic to HTTPS (I couldn't find that in the documentation).
- the port specified where 443 is in the above is the entry port for HTTPS. You still have done no redirection at this point, just kind of explaining to redbrid what's what. I think.
- the cert in the ssl object should be the file cert.pem not fullchain.pem (this isn't necessarily a redbird issue but just one of those things that could trip people up).
- the port where 7000 and 7001 are above are the ports where you want to redirect your traffic to (kind of obvious but documentation should have obvious stuff).
- Finally, what the object {ssl: true} does is tell redbird to use the default SSL config above, an alternative would be to specify another config per registered domain but I was not able to make that work (might be because I was only dealing with sub-domains and this feature might only be for non-sub-domains... if that's the case it would have been good to have in the docs).
So this is disappointing because (by order of most important to least):
- There seems to be a huge hit on perf: am I missing a "prod" parameter that could improve this?
- It seems the only way this works is by having all my node apps/servers as http (not https) and pointing to their ports (7000 and 7001) and only have the proxy server be https. It's not too troubling since no one seems to be able to get to the ports 7000 and 7001 directly, but I'm thinking 7000 and 7001 could have been https too. Can they be? Or does it not make sense to have these apps in https if the proxy can handle that?
- I was not able to keep the old (and expensive) ssl certificate that is not yet expired. Or is there a way that I didn't find?
I bet this is gotten so long no one will ever read this...