Giter Club home page Giter Club logo

redbird's Introduction

Redbird Reverse Proxy

With built-in Cluster, HTTP2, LetsEncrypt and Docker support

redbird

It should be easy and robust to handle dynamic virtual hosts, load balancing, proxying web sockets and SSL encryption.

With Redbird you get a complete library to build dynamic reverse proxies with the speed and robustness of http-proxy.

This light-weight package includes everything you need for easy reverse routing of your applications. Great for routing many applications from different domains in one single host, handling SSL with ease, etc.

Developed by manast

BuildStatus NPM version

SUPER HOT

Support for HTTP2. You can now enable HTTP2 just by setting the HTTP2 flag to true. Keep in mind that HTTP2 requires SSL/TLS certificates. Thankfully we also support LetsEncrypt so this becomes easy as pie.

HOT

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

Features

  • Flexible and easy routing
  • Websockets
  • Seamless SSL Support (HTTPS -> HTTP proxy)
  • Automatic HTTP to HTTPS redirects
  • Automatic TLS Certificates generation and renewal
  • Load balancer
  • Register and unregister routes programmatically without restart (allows zero downtime deployments)
  • Docker support for automatic registration of running containers
  • Cluster support that enables automatic multi-process
  • Based on top of rock-solid node-http-proxy and battle tested on production in many sites
  • Optional logging based on bunyan

Install

npm install redbird

Example

You can programmatically register or unregister routes dynamically even if the proxy is already running:

var proxy = require('redbird')({port: 80});

// OPTIONAL: Setup your proxy but disable the X-Forwarded-For header
var proxy = require('redbird')({port: 80, xfwd: false});

// Route to any global ip
proxy.register("optimalbits.com", "http://167.23.42.67:8000");

// Route to any local ip, for example from docker containers.
proxy.register("example.com", "http://172.17.42.1:8001");

// Route from hostnames as well as paths
proxy.register("example.com/static", "http://172.17.42.1:8002");
proxy.register("example.com/media", "http://172.17.42.1:8003");

// Subdomains, paths, everything just works as expected
proxy.register("abc.example.com", "http://172.17.42.4:8080");
proxy.register("abc.example.com/media", "http://172.17.42.5:8080");

// Route to any href including a target path
proxy.register("foobar.example.com", "http://172.17.42.6:8080/foobar");

// You can also enable load balancing by registering the same hostname with different
// target hosts. The requests will be evenly balanced using a Round-Robin scheme.
proxy.register("balance.me", "http://172.17.40.6:8080");
proxy.register("balance.me", "http://172.17.41.6:8080");
proxy.register("balance.me", "http://172.17.42.6:8080");
proxy.register("balance.me", "http://172.17.43.6:8080");

// You can unregister routes as well
proxy.register("temporary.com", "http://172.17.45.1:8004");
proxy.unregister("temporary.com", "http://172.17.45.1:8004");

// LetsEncrypt support
// With Redbird you can get zero conf and automatic SSL certificates for your domains
redbird.register('example.com', 'http://172.60.80.2:8082', {
  ssl: {
    letsencrypt: {
      email: '[email protected]', // Domain owner/admin email
      production: true, // WARNING: Only use this flag when the proxy is verified to work correctly to avoid being banned!
    }
  }
});

//
// LetsEncrypt requires a minimal web server for handling the challenges, this is by default on port 3000
// it can be configured when initiating the proxy. This web server is only used by Redbird internally so most of the time
// you  do not need to do anything special other than avoid having other web services in the same host running
// on the same port.

//
// HTTP2 Support using LetsEncrypt for the certificates
//
var proxy = require('redbird')({
  port: 80, // http port is needed for LetsEncrypt challenge during request / renewal. Also enables automatic http->https redirection for registered https routes.
  letsencrypt: {
    path: __dirname + '/certs',
    port: 9999 // LetsEncrypt minimal web server port for handling challenges. Routed 80->9999, no need to open 9999 in firewall. Default 3000 if not defined.
  },
  ssl: {
    http2: true,
    port: 443, // SSL port used to serve registered https routes with LetsEncrypt certificate.
  }
});

About HTTPS

The HTTPS proxy supports virtual hosts by using SNI (which most modern browsers support: IE7 and above). The proxying is performed by hostname, so you must use the same SSL certificates for a given hostname independently of its paths.

LetsEncrypt

Some important considerations when using LetsEncrypt. You need to agree to LetsEncrypt terms of service. When using LetsEncrypt, the obtained certificates will be copied to disk to the specified path. Its your responsibility to backup, or save persistently when applicable. Keep in mind that these certificates needs to be handled with care so that they cannot be accessed by malicious users. The certificates will be renewed every 2 months automatically forever.

HTTPS Example

(NOTE: This is a legacy example not needed when using LetsEncrypt)

Conceptually HTTPS is easy, but it is also easy to struggle getting it right. With Redbird its straightforward, check this complete example:

  1. Generate a localhost development SSL certificate:
/certs $ openssl genrsa -out dev-key.pem 1024
/certs $ openssl req -new -key dev-key.pem -out dev-csr.pem

// IMPORTANT: Do not forget to fill the field! Common Name (e.g. server FQDN or YOUR name) []:localhost

/certs $ openssl x509 -req -in dev-csr.pem -signkey dev-key.pem -out dev-cert.pem

Note: For production sites you need to buy valid SSL certificates from a trusted authority.

  1. Create a simple redbird based proxy:
var redbird = new require('redbird')({
	port: 8080,

	// Specify filenames to default SSL certificates (in case SNI is not supported by the
	// user's browser)
	ssl: {
		port: 8443,
		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});
  1. Test it:

Point your browser to localhost:8000 and you will see how it automatically redirects to your https server and proxies you to your target server.

You can define many virtual hosts, each with its own SSL certificate. And if you do not define any, they will use the default one as in the example above:

redbird.register('example.com', 'http://172.60.80.2:8082', {
	ssl: {
		key: "../certs/example.key",
		cert: "../certs/example.crt",
		ca: "../certs/example.ca"
	}
});

redbird.register('foobar.com', 'http://172.60.80.3:8082', {
	ssl: {
		key: "../certs/foobar.key",
		cert: "../certs/foobar.crt",
	}
});

You can also specify https hosts as targets and also specify if you want the connection to the target host to be secure (default is true).

var redbird = require('redbird')({
	port: 80,
	secure: false,
	ssl: {
		port: 443,
		key: "../certs/default.key",
		cert: "../certs/default.crt",
	}
});
redbird.register('tutorial.com', 'https://172.60.80.2:8083', {
	ssl: {
		key: "../certs/tutorial.key",
		cert: "../certs/tutorial.crt",
	}
});

Edge case scenario: you have an HTTPS server with two IP addresses assigned to it and your clients use old software without SNI support. In this case, both IP addresses will receive the same fallback certificate. I.e. some of the domains will get a wrong certificate. To handle this case you can create two HTTPS servers each one bound to its own IP address and serving the appropriate certificate.

var redbird = new require('redbird')({
	port: 8080,

	// Specify filenames to default SSL certificates (in case SNI is not supported by the
	// user's browser)
	ssl: [
		{
			port: 443,
			ip: '123.45.67.10',  // assigned to tutorial.com
			key: 'certs/tutorial.key',
			cert: 'certs/tutorial.crt',
		},
		{
			port: 443,
			ip: '123.45.67.11', // assigned to my-other-domain.com
			key: 'certs/my-other-domain.key',
			cert: 'certs/my-other-domain.crt',
		}
	]
});

// These certificates will be served if SNI is supported
redbird.register('tutorial.com', 'http://192.168.0.10:8001', {
	ssl: {
		key: 'certs/tutorial.key',
		cert: 'certs/tutorial.crt',
	}
});
redbird.register('my-other-domain.com', 'http://192.168.0.12:8001', {
	ssl: {
		key: 'certs/my-other-domain.key',
		cert: 'certs/my-other-domain.crt',
	}
});

Docker support

If you use docker, you can tell Redbird to automatically register routes based on image names. You register your image name and then every time a container starts from that image, it gets registered, and unregistered if the container is stopped. If you run more than one container from the same image, Redbird will load balance following a round-robin algorithm:

var redbird = require('redbird')({
  port: 8080,
});

var docker = require('redbird').docker;
docker(redbird).register("old.api.com", 'company/api:v1.0.0');
docker(redbird).register("stable.api.com", 'company/api:v2.*');
docker(redbird).register("preview.api.com", 'company/api:v[3-9].*');

etcd backend

Redbird can use node-etcd to automatically create proxy records from an etcd cluster. Configuration is accomplished by passing an array of options, plus the hosts and path variables, which define which etcd cluster hosts, and which directory within those hosts, that Redbird should poll for updates.

var redbird = require('redbird')({
  port:8080
});

var options = {
  hosts: ['localhost:2379'], // REQUIRED - you must define array of cluster hosts
	path: ['redbird'], // OPTIONAL - path to etcd keys
	... // OPTIONAL - pass in node-etcd connection options
}
require('redbird').etcd(redbird,options);

etcd records can be created in one of two ways, either as a target destination pair: /redbird/example.com "8.8.8.8" or by passing a JSON object containing multiple hosts, and Redbird options:

/redbird/derek.com				{ "hosts" : ["10.10.10.10", "11.11.11.11"]}
/redbird/johnathan.com    { "ssl" : true }
/redbird/jeff.com         { "docker" : "alpine/alpine:latest" }

Cluster support

Redbird supports automatic node cluster generation. To use, just specify the number of processes that you want Redbird to use in the options object. Redbird will automatically restart any thread that crashes, increasing reliability.

var redbird = new require('redbird')({
	port: 8080,
  cluster: 4
});

NTLM support

If you need NTLM support, you can tell Redbird to add the required header handler. This registers a response handler which makes sure the NTLM auth header is properly split into two entries from http-proxy.

var redbird = new require('redbird')({
  port: 8080,
  ntlm: true
});

Custom Resolvers

With custom resolvers, you can decide how the proxy server handles request. Custom resolvers allow you to extend Redbird considerably. With custom resolvers, you can perform the following:

  • Do path-based routing.
  • Do headers based routing.
  • Do wildcard domain routing.
  • Use variable upstream servers based on availability, for example in conjunction with Etcd or any other service discovery platform.
  • And more.

Resolvers should be:

  1. Be invokable function. The this context of such function is the Redbird Proxy object. The resolver function takes in two parameters : host and url
  2. Have a priority, resolvers with higher priorities are called before those of lower priorities. The default resolver, has a priority of 0.
  3. A resolver should return a route object or a string when matches it matches the parameters passed in. If string is returned, then it must be a valid upstream URL, if object, then the object must conform to the following:
  {
     url: string or array of string [required], when array, the urls will be load-balanced across.
     path: path prefix for route, [optional], defaults to '/',
     opts: {} // Redbird target options, see Redbird.register() [optional],
  }

Defining Resolvers

Resolvers can be defined when initializing the proxy object with the resolvers parameter. An example is below:

 // for every URL path that starts with /api/, send request to upstream API service
 var customResolver1 = function(host, url, req) {
   if(/^\/api\//.test(url)){
      return 'http://127.0.0.1:8888';
   }
 };

 // assign high priority
 customResolver1.priority = 100;

 var proxy = new require('redbird')({
    port: 8080,
    resolvers: [
    customResolver1,
    // uses the same priority as default resolver, so will be called after default resolver
    function(host, url, req) {
      if(/\.example\.com/.test(host)){
        return 'http://127.0.0.1:9999'
      }
    }]
 })

Adding and Removing Resolvers at Runtime.

You can add or remove resolvers at runtime, this is useful in situations where your upstream is tied to a service discovery service system.

var topPriority = function(host, url, req) {
  return /app\.example\.com/.test(host) ? {
    // load balanced
    url: [
    'http://127.0.0.1:8000',
    'http://128.0.1.1:9999'
   ]
  } : null;
};

topPriority.priority = 200;
proxy.addResolver(topPriority);


// remove top priority after 10 minutes,
setTimeout(function() {
  proxy.removeResolver(topPriority);
}, 600000);

Replacing the default HTTP/HTTPS server modules

By passing serverModule: module or ssl: {serverModule : module} you can override the default http/https servers used to listen for connections with another module.

One application for this is to enable support for PROXY protocol: This is useful if you want to use a module like findhit-proxywrap to enable support for the PROXY protocol.

PROXY protocol is used in tools like HA-Proxy, and can be optionally enabled in Amazon ELB load balancers to pass the original client IP when proxying TCP connections (similar to an X-Forwarded-For header, but for raw TCP). This is useful if you want to run redbird on AWS behind an ELB load balancer, but have redbird terminate any HTTPS connections so you can have SNI/Let's Encrypt/HTTP2support. With this in place Redbird will see the client's IP address rather than the load-balancer's, and pass this through in an X-Forwarded-For header.

//Options for proxywrap. This means the proxy will also respond to regular HTTP requests without PROXY information as well.
proxy_opts = {strict: false};
proxyWrap = require('findhit-proxywrap');
var opts = {
    port: process.env.HTTP_PORT,
    serverModule: proxyWrap.proxy( require('http'), proxy_opts),
    ssl: {
        //Do this if you want http2:
        http2: true,
        serverModule: proxyWrap.proxy(require('spdy').server, proxy_opts),
        //Do this if you only want regular https
        // serverModule: proxyWrap.proxy( require('http'), proxy_opts),
        port: process.env.HTTPS_PORT,
    }
}

// Create the proxy
var proxy = require('redbird')(opts);

Roadmap

  • Statistics (number of connections, load, response times, etc)
  • CORS support.
  • Rate limiter.
  • Simple IP Filtering.
  • Automatic routing via Redis.

Reference

constructor register unregister notFound close

This is the Proxy constructor. Creates a new Proxy and starts listening to the given port.

Arguments

    opts {Object} Options to pass to the proxy:
    {
    	port: {Number} // port number that the proxy will listen to.
    	ssl: { // Optional SSL proxying.
    		port: {Number} // SSL port the proxy will listen to.
    		// Default certificates
    		key: keyPath,
    		cert: certPath,
    		ca: caPath // Optional.
        	redirectPort: port, // optional https port number to be redirected if entering using http.
            http2: false, //Optional, setting to true enables http2/spdy support
            serverModule : require('https') // Optional, override the https server module used to listen for https or http2 connections.  Default is require('https') or require('spdy')
    	}
        bunyan: {Object} Bunyan options. Check [bunyan](https://github.com/trentm/node-bunyan) for info.
        If you want to disable bunyan, just set this option to false. Keep in mind that
        having logs enabled incours in a performance penalty of about one order of magnitude per request.
        resolvers: {Function | Array}  a list of custom resolvers. Can be a single function or an array of functions. See more details about resolvers above.
        serverModule : {Module} Optional - Override the http server module used to listen for http connections.  Default is require('http')
	}

Register a new route. As soon as this method is called, the proxy will start routing the sources to the given targets.

Arguments

    src {String} {String|URL} A string or a url parsed by node url module.
    	Note that port is ignored, since the proxy just listens to one port.

    target {String|URL} A string or a url parsed by node url module.
    opts {Object} route options:
    examples:
    {ssl : true} // Will use default ssl certificates.
    {ssl: {
        redirect: true, // False to disable HTTPS autoredirect to this route.
    	key: keyPath,
    	cert: certPath,
    	ca: caPath, // optional
    	secureOptions: constants.SSL_OP_NO_TLSv1 //optional, see below
    	}
    }
    {onRequest: (req, res, target) => {
      // called before forwarding is occurred, you can modify req.headers for example
      // return undefined to forward to default target
    }}

Note: if you need to use ssl.secureOptions, to disable older, insecure TLS versions, import crypto/constants first:

const { constants } = require('crypto')


Unregisters a route. After calling this method, the given route will not be proxied anymore.

Arguments

    src {String|URL} A string or a url parsed by node url module.
    target {String|URL} A string or a url parsed by node url module. If not
    specified, it will unregister all routes for the given source.

Gives Redbird a callback function with two parameters, the HTTP request and response objects, respectively, which will be called when a proxy route is not found. The default is

    function(req, res){
      res.statusCode = 404;
      res.write('Not Found');
      res.end();
    };

.

Arguments

    src {Function(req, res)} The callback which will be called with the HTTP
      request and response objects when a proxy route is not found.

Close the proxy stopping all the incoming connections.


redbird's People

Contributors

cchan avatar derektbrown avatar elderapo avatar ellisium avatar fbatiga avatar james9074 avatar jasisk avatar jchip avatar jgrenon avatar joelself avatar jonathonsim avatar justlep avatar karlhorky avatar kimar avatar liberquack avatar manast avatar merpnderp avatar mhemrg avatar mhussa avatar morkai avatar mrbarletta avatar mumrau avatar neocoder avatar niuba avatar oddmorning avatar olegcho avatar pyrosa avatar siedrix avatar wrongbad avatar xrahul avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

redbird's Issues

Red bird reverse proxy issue with meteor hostname+paths

I use Red bird reverse proxy for my meteor apps, it has been Fantastic, I recently face the following issue. Any help is appreciated.

My requests are redirected correctly when i use the below configuration i.e subdomain

var proxy = require('redbird')({port: 80});

proxy.register("app1.example.com", "http://127.0.0.1:3000");
proxy.register("app2.example.com", "http://127.0.0.1:4000");
but when i use domain + paths like in the below configuration

var proxy = require('redbird')({port: 80});

proxy.register("http://127.0.0.1/a", "http://127.0.0.1:3000");
proxy.register("http://127.0.0.1/b", "http://127.0.0.1:4000");
i get the error "no valid route found for given source". Below is the screenshot from browser

capture.

issue post on stack

http://stackoverflow.com/questions/33892447/red-bird-reverse-proxy-issue-with-meteor-hostnamepaths

Please let me know in case you require more information

Request is pending when the redirect server is down

When the destination server is down, I see in the log:
{"name":"redbird","hostname":"myLaptop","pid":5664,"level":50,"err":{"message":"connect ECONNREFUSED 127.0.0.1:8021","name":"Error","stack":"Error: connect ECONNREFUSED 127.0.0.1:8021\n at Object.exports._errnoException (util.js:874:11)\n at exports._exceptionWithHostPort (util.js:897:20)\n at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1063:14)","code":"ECONNREFUSED"},"msg":"Proxy Error","time":"2016-07-02T15:03:54.155Z","v":0}

And the request is pending on the chrome..

Support upper case in the domain

Hi there

It looks like redbird can not proxy requests with upper cases.
I have old clients trying to get to Support.example.com.
I tried to:
proxy.register("Support.example.com", "http://localhost:1234");
but redbird ignore the uppercase, so I always get:

"msg":"no valid route found for given source"

Is there a way to implement failover if a primary server does not accept the request?

Hello, I was wondering if Redbird was capable of handling failover? My company just got a second fiber line put in that we have setup for failover in the firewall so that if the primary connection goes down it switches over to the secondary, the only issue though is with DNS for all of our internally hosted sites. DNS only has the ability to basically load balance with multiple A records.

My plan is to use a droplet on DigitalOcean to basically be a gateway to all of our sites to solve this issue. It can test externally if the primary connection is working, and if so it can send the requests there, but if it detects that it is down, it can then send the request to the secondary IP, which I can then setup in the firewall to send the requests to the appropriate servers internally.

So the question is, is there a built in way currently to do this, or will I have to try and implement some of my own if/then logic to decide where to set the proxy.register command to?

Benchmark, security, comparison

Are there any benchmarks which compare redbird with apache and nginx for example by serving static files. People use nginx with express because it serves static files much faster. According to them nginx prevents DDOS attacks as well, and increases security. Ofc. I never saw any concrete examples. I think they just use it because everyone else do so.

off:
In my case I cannot find a real purpose to use a reverse proxy with nodejs. I have a home server with some nodejs services. Some of them run express and have HTTP interface. These are mostly for personal usage on the local network, but I think I'll add a dyndns and publish a few, for example my blog. It does not really need performance by static files, etc. Why do I need a reverse proxy to do this? Wouldn't express + fail2ban + port forwarding on the router be enough?

Getting IP Address of Client

This isn't so much an issue for me, but I've posted this here for the benefit of other users of Redbird. When I moved to Redbird I assumed that I would not be able to access the IP of the client connections, as this was the case with my previous reverse proxy, where everybody had the same IP of 127.0.0.1.

However, I have since realized that Redbird implements the "x-forwarded-for" header, which gives the correct address, and thankfully most of the services I run can be modified to look at that header for it's IP address. I have been using this header for a few weeks now with good results. Hopefully this information proves useful to you.

I'm not sure if it's possible for the client to manipulate the x-forwarded-for header by sending their own, but I presume Redbird has complete control over it so thus x-forwarded-for should be considered reliable?

autoban functionality.

We should have some mechanism to autoban ips that tries to makes attacks by some rules:

  • Accessing often to inexistent urls (trying to find backdoors).
  • Making DDOS attacks.

HTTPS -> HTTPS passthrough

Hi,

First of all, thanks for the great work. We intend to use Redbird in our Production environment due to it's ease of programming and automation.

This is a (pair of) questions - not a bug report, or a feature request:

(a) Is there a way to specify an HTTPS->HTTPS passthrough mode with just a port re-direction ? I couldn't find an obvious way to do it from the documentation.

(b) Once the "ssl" is specified during the instantiation of the proxy, it seems then that only HTTPS requests are honoured and it's not possible to proxy an plain HTTP request. Is my understanding correct ?

Thanks,
Avinash

FYI Redwire was heavily inspired by Redbird

Redwire

I've implemented some things similar and some things differently.
It has been running in production for a year and a half now.

Features that were new at the time:

  • Middleware
  • Swapping configuration at runtime (redwire-harmony)
  • * support (but not full regex, e.g. *.domain.com)

It would be interesting to see if any parts are common and potentially even merging the projects.

Custom resolvers + SSL

When we approach proxy over port 443 (SSL) custom resolvers do not run.

Creating the proxy

const proxy = redbird({
    port: 80,
    resolvers: [
        wildcardResolver
    ],
    letsencrypt: {
        path: __dirname + '/certs',
        port: 9999
    },
    ssl: {
        http2: false,
        port: 443
    }
});

Resolver:

function wildcardResolver(host, url) {
    if (domains.some(domain => domain === host)) {
        return {
            url: [
                WEB_URL
            ],
            opts: Object.assign({}, sslConfig)
        };
    }

    const find = domains.some(domain => new RegExp('([a-z0-9\-]+)\.' + domain, 'i').test(host));

    if (find) {
        return {
            //load balanced
            url: [
                WEB_URL
            ],
            opts: Object.assign({}, sslConfig)
        };
    }

    return null;
};

It more or less looks like this.

Am I missing some functionality or something ? IMO it should work the same for HTTP and HTTPS.

status code change

Hi,
is there a paramete to change the default 302 redirect status code for http->https conversion to 307 ?
for now I've changed the code manually in lib/proxy.js

thanks

Default route

First of all, thanks for this great tool!

I'm currently using redbird as a reverse proxy to run several websites off of one server. At the moment, if you type in an undefined route, it'll stall until the browser gives up and closes its end of the connection. It would be nice to have a default route that I could direct to some sort of 404 page.

Can't get basic example to work on Ubuntu Server 14.04

This works, tested by going to https://sensorypanel.net:

var fs = require('fs');

var http = require('http');
http.createServer(function(req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello World\n');
}).listen(80, '0.0.0.0');

var https = require('https');
var options = {
        key: fs.readFileSync('certs/sensorypanel.net/sensorypanel_net-key.pem'),
        cert: fs.readFileSync('certs/sensorypanel.net/sensorypanel_net.crt'),
        ca: fs.readFileSync('certs/ca_bundle.crt')
};
https.createServer(options, function(req, res) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello SSL World\n');
}).listen(443, '0.0.0.0');

This doesn't:

var redbird = require('redbird'),
    http = require('http');

var proxy = redbird({
        port: 80,
        ssl: {
                port: 443,
                key: 'certs/sensorypanel.net/sensorypanel_net-key.pem',
                cert: 'certs/sensorypanel.net/sensorypanel_net.crt',
                ca: 'certs/ca_bundle.crt'
        }
});

proxy.register('sensorypanel.net', 'http://localhost:4001', {ssl: true});

http.createServer(function(req, res) {
        console.log('Got a request!');
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('Hello World\n');
}).listen(4001, '0.0.0.0');

The connection isn't refused immediately. It just hangs. I can still go around the proxy via http://sensorypanel.net:4001, which verifies the underlying HTTP service is working. The firewall is off.

Here's a sample of the log:

{"name":"redbird","hostname":"sensorypanel.net","pid":1370,"level":30,"msg":"Listening to HTTPS requests on port 443","time":"2015-08-26T04:46:05.919Z","v":0}
{"name":"redbird","hostname":"sensorypanel.net","pid":1370,"level":30,"msg":"80 'Started a Redbird reverse proxy server'","time":"2015-08-26T04:46:05.925Z","v":0}
{"name":"redbird","hostname":"sensorypanel.net","pid":1370,"level":30,"from":{"protocol":"http:","slashes":true,"auth":null,"host":"sensorypanel.net","port":null,"hostname":"sensorypanel.net","hash":null,"search":null,"query":null,"pathname":"/","path":"/","href":"http://sensorypanel.net/"},"to":{"protocol":"http:","slashes":true,"auth":null,"host":"localhost:4001","port":"4001","hostname":"localhost","hash":null,"search":null,"query":null,"pathname":"/","path":"/","href":"http://localhost:4001/","sslRedirect":true,"useTargetHostHeader":false},"msg":"Registered a new route","time":"2015-08-26T04:46:05.931Z","v":0}
{"name":"redbird","hostname":"sensorypanel.net","pid":1370,"level":50,"err":{"message":"socket hang up","name":"Error","stack":"Error: socket hang up\n    at TLSSocket.<anonymous> (_tls_wrap.js:664:25)\n    at TLSSocket.emit (events.js:107:17)\n    at TCP.close (net.js:485:12)","code":"ECONNRESET"},"msg":"HTTPS Client  Error","time":"2015-08-26T04:46:27.847Z","v":0}
{"name":"redbird","hostname":"sensorypanel.net","pid":1370,"level":50,"err":{"message":"socket hang up","name":"Error","stack":"Error: socket hang up\n    at TLSSocket.<anonymous> (_tls_wrap.js:664:25)\n    at TLSSocket.emit (events.js:107:17)\n    at TCP.close (net.js:485:12)","code":"ECONNRESET"},"msg":"HTTPS Client  Error","time":"2015-08-26T04:46:41.931Z","v":0}

Cannot redirect from HTTP to HTTPS

Hi @manast, I am using this module in my project. But I didn't see it redirect from HTTP to HTTPS automatically. I think it does not work.

  • Domain: example.com
  • Node.js port: 3000
  • Redbird port: 4001
  • Redbird SSL port: 4000

Here is my implementation:

/**
 * Main domain of the app.
 */

const DOMAIN_NAME = 'example.com';

/**
 * Create HTTPS proxy server.
 */

const proxy = redbird({
  port: 4001,
  ssl: {
    port: 4000,
    key: `config/ssl/${DOMAIN_NAME}.key`,
    cert: `config/ssl/${DOMAIN_NAME}.crt`,
    ca: `config/ssl/${DOMAIN_NAME}.ca-bundle`
  }
});

/**
 * Listen on provided port and map domain to the app.
 */

proxy.register(DOMAIN_NAME, 'http://localhost:3000', { ssl: true });

/**
 * Get port from environment and store in Express.
 */

const port = normalizePort(config.port);
app.set('port', port);

/**
 * Create HTTP server.
 */

const server = http.createServer(app);

/**
 * Listen on provided port, on all network interfaces.
 */

server.listen(3000);

[FEATURE] etcd backend

Hello- I am interested in implementing ETCD Backend functionality. I see that you have started the implementation of a Redis-Backend, are there any other guidelines you have for my implementing this functionality?

Verbose

Im testing this library but it keeps printing every request on the screen,
any non verbose option?

Path Based Routing

This is a great server! Just one question, I will like to route all requests to a particular path (irrespective of the host) to an upstream server. As an example

**/api -->      http://127.0.0.1:8080
**/office ---> http://127.0.0.1:9999

Is this achievable with the current version?

Another question, any plans to allow weight assignment to the servers in the case of load-balancing?

Cannot read property 'toLowerCase' of undefined

I don't know ecxactly when it happens, but i'm sure it's because 8e72b6b.
So #57 isn't really fixed


/redbird/node_modules/redbird/lib/proxy.js:392
  host = host.toLowerCase();
             ^

TypeError: Cannot read property 'toLowerCase' of undefined
    at ReverseProxy.resolve (/home/yehuda/redbird/node_modules/redbird/lib/proxy.js:392:14)
    at ReverseProxy._getTarget (/home/yehuda/redbird/node_modules/redbird/lib/proxy.js:442:20)
    at Server.<anonymous> (/home/yehuda/redbird/node_modules/redbird/lib/proxy.js:89:26)
    at emitTwo (events.js:106:13)
    at Server.emit (events.js:191:7)
    at HTTPParser.parserOnIncoming [as onIncoming] (_http_server.js:543:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:105:23)

Using node, parse, parse dash, on the same server with subdirectories

Hey there again, it is me, lol. I have tried for 2 days to get this to work before making a post, reading through all the documentation yet again, etc. I seem to be stuck, though.

I am trying to run parse-server, and parse-dashboard on the same server, but it does not seem to be working quite right. I was able to get it to the point in which the parse dash login comes up, but then gives a 404 error upon login. At the bottom though, I typed out a few scenarios in which it can / does work, but not properly all the time.

Here is my Parse config.

var express = require('express');
var ParseServer = require('parse-server').ParseServer;
var app = express();

var api = new ParseServer({
  databaseURI: 'mongodb://localhost:27017/parse',
  cloud: '',
  appId: '123',
  masterKey: '1234',
  fileKey: '',
  serverURL: 'http://syntaxlabs.io/parse'

});

// Serve the Parse API on the /parse URL prefix
app.use('/parse', api);

app.listen(3000, function() {
  console.log('parse-server running on port 3000.');
});

Here is the parse-dash config

var express = require('express');
var ParseDashboard = require('parse-dashboard');
var app = express();

var dashboard = new ParseDashboard({
  "apps": [
    {
      "serverURL": "http://syntaxlabs.io/parse",
      "appId": "123",
      "masterKey": "1234",
      "appName": "Whatevs"
    }],
    "users":[{"user":"admin","pass":"somepassword12345"}]

}, true);

app.use('/dash', dashboard);

app.listen(3001, function() {
  console.log('parse-dashboard running on port 3001.');
});

Lastly here is the config for redbird I was trying to use, which is quite basic for now.

var proxy = new require('redbird')({port: 80 });

proxy.register("syntaxlabs.io/parse", "http://syntaxlabs.io:3000/parse");
proxy.register("syntaxlabs.io/dash", "http://syntaxlabs.io:3001/dash"); 

I have tried it with http://127.0.0.1/dash, http://127.0.0.1:3001/dash, http://syntaxlabs.io:3001/dash, and http://syntaxlabs.io/dash. They all seem to have similar issues though. Currently I can get into the login screen, in which you can see the login is admin / somepassword12345, but then just gives that 404.

If I go directly to http://syntaxlabs.io:3001/dash it works just fine, but when I try to just go to http://syntaxlabs.io/dash, it will not, yet if I go to http://syntaxlabs.io/dash/ and or http://syntaxlabs.io/dash/apps it then works, but If I try to change my Redbird config to instead point proxy.register("syntaxlabs.io/dash", "http://syntaxlabs.io:3001/dash/apps"); (or just /dash/) it no longer works. It seems to work if I physically type my url as http://syntaxlabs.io/dash/ <-- with a trailing slash, but if I put that in my redbird config, it doesnt work. Any ideas?

Production usage?

This looks pretty great feature wise. Curious if it's battle tested, where and how?

async custom resolvers

Hi,

is there a way to have async/promise-based custom resolvers? This would be a useful feature for us, since have to request the target IP from a consul service.

Docker DNS question

To connect to a pre-existing Docker container, I use this:

proxy.register("www.example.com", "172.17.0.13");

Here is my question: Can I specify a container's name instead of it's private IP address?

proxy.register("www.example.com", "some-container");

I do see that there is support for brand new containers, but since mine are generic images like ubuntu and because they are pre-exisiting I don't believe this can help me:

require('redbird')
  .docker(redbird)
  .register("example.com", 'company/myimage:latest');

Cannot connect to parse server. "Cannot GET /" and 'XMLHttpRequest failed: "Unable to connect to the Parse API"

Hello,
I am not 100% sure this is an issue with redbird at all, but I am not able to figure it out. My pal and I are working on getting a store he made working using nodejs, I also am running apache on 8080 and 8443 in order for them to run side by side and am using redbird to handle the requests, but for some reason I am not able to get the store to connect to parse-server, yet parse dash is working fine.

Here is what I am using currently.

`//If URL has/.well-known/, send request to upstream API service
var customResolver1 = function(host, url) {
if(/^/.well-known//.test(url)){
return 'http://planetex.press:8080';
}
};

//assign high priority
customResolver1.priority = 100;

var proxy = new require('redbird')({
port: 80,
resolvers: [
customResolver1],
secure: true,
ssl:{ port: 443 },
})

proxy.register("www.planetex.press", "http://www.planetex.press:3000", {
ssl: {
key: "/home/planetex/ssl.key",
cert: "/home/planetex/ssl.cert",
}
});
proxy.register("api.planetex.press", "http://api.planetex.press:3002",{
ssl: {
key: "/home/planetex/domains/api.planetex.press/ssl.key",
cert: "/home/planetex/domains/api.planetex.press/ssl.cert",
}
});
proxy.register("dash.planetex.press", "http://dash.planetex.press:3001",{
ssl: {
key: "/home/planetex/domains/dash.planetex.press/ssl.key",
cert: "/home/planetex/domains/dash.planetex.press/ssl.cert",
}
});`

Proxy stalling indefinitly

So I have setup the proxy in a gulpfile:

var proxy = redbird({port: 8082});
proxy.register('http://localhost:8082', 'http://localhost:8081');
proxy.register('http://localhost:8082/api', 'http://localhost:8080/api');

Curl agains the server directly work, but trying to run curl against the redbird proxy won't work.

$ curl http://localhost:8080/api
{"endpoints":["bye","hello","resource"]}%
$ curl http://localhost:8082/api

The error from the console I'm running gulp redbird in:

{
   "name":"redbird",
   "hostname":"Franks-MBP",
   "pid":66293,
   "level":50,
   "err":{
      "message":"connect ECONNREFUSED 127.0.0.1:8080",
      "name":"Error",
      "stack":"Error: connect ECONNREFUSED 127.0.0.1:8080\n    at Object.exports._errnoException (util.js:874:11)\n    at exports._exceptionWithHostPort (util.js:897:20)\n    at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1063:14)",
      "code":"ECONNREFUSED"
   },
   "msg":"Proxy Error",
   "time":"2015-12-10T16:50:30.723Z",
   "v":0
}

Showing localhost:8082 in the browser works, but not if I go to localhost:8082/api.

Wildcard support?

I'm new to node and have recently installed redbird, the performance is superb! However, there appears no way to register all sub-domains, they have to be done individually. E.g. With example.com when I goto www.example.com I get "Not found" unless I specifically register the www sub-domain too. I note from the documentation that nodes url parser is used which also seems to offer no method of support, and the register options don't offer a solution either. Am I doing something wrong or is this a current limitation?

Socket not-found errors.

Currently (#54) we handle sockets as if they're HTTP response objects (in notFound, for example). For obvious reasons, this is not really correct. We should probably fix this, along with the rest of the socket connection handling.

Wild card for docker

Does redbird support wild card for docker?

  ...
  .docker(redbird)
  .register("example.com", 'company/myimage:*'); // <------------ possible?

Use both HTTP and HTTPS for the same FQDN

Hello,

With the default configuration, when browser request a HTTP page, it is redirected (302) to HTTPS.

Can I make redbird to accept both protocols instead of redirecting to HTTPS ?

My server.js is:

var proxy = require('redbird', {ssl:true})(
{
port: 80,
ssl: {
        port: 443,
        key: "certs/privkey1.pem",
        cert: "certs/cert1.pem",
        ca:   "certs/fullchain1.pem",
    }
});

proxy.register('sub.domain.tld', 'http://127.0.0.1:3003', {ssl:true});
proxy.register('sub.domain.tld', 'http://127.0.0.1:3003');

Thanks ! :)

load host/port data from a json file?

Any thoughts about saving host/port data in a json file, to make it easier to load in various HTTP proxy daemons?

{
    "hosts": [{
        "host": "abc.example.com",
        "targets": ["http://172.17.40.6:8080"]
    }, {
        "host": "abc.example.com/media",
        "targets": ["http://172.17.40.6:8081"]
    }, {
        "host": "abc2.example.com",
        "targets": ["http://172.17.40.6:8080", "http://172.17.41.6:8080", "http://172.17.42.6:8080"]
    }]
}

I've been playing with various HTTP reverse proxies lately, and it would be great to use a json file to store this data (or rely on CoreOS etcd like Gogeta does). It would make it easier to swap between various proxyd for testing.

onRequest and onResponse support?

Have support of onrequest and onresponse triggers? example, need send additional header to server "x-real-ip" with http.req.connection.remoteAddress and restrict access to certains urls by example /admin

mod_rewrite similar usage?

Hi,

I would like to serve http://foo.com/abc/x/y.jpg as http://foo.com/abc?first=x&second=y&type=jpg.

Is this possible with redbird? I don't see regex as an option.

Keep-Alive Http Agent for proxy server

Hi,

First of all, thank You, we use redbird and works like a charm. But there is one thing. We would like to use keep-alive connection, but right now, the connection is 'close'. I have found in Your code commented out agent for proxy server to allow keep-alive connections.

Is there any particular reason for that? Any issues it can cause? I found nothing nor in issues nor in documentation.

Best regards
Filip

subpath

Hi!

I created a web app and a redbird reverse proxy app.

Reverse proxy app:

..
var proxy = require('redbird')({port: 80});
proxy.register("127.0.0.1/web1", "http://127.0.0.1:3000");
..

Web1 app:

..
<p>Test site 1</p>
<img src="images.jpg">
..

What is wrong?

Custom resolver, host and url rewriting

Hello,

I would like to defined a custom resolver to wildcard domain routing and do some redirection.

Configuration

{
    "proxy": {
        "redirections": [
            {"from":"/foo","to":"something:9100"},
            {"from":"/bar","to":"anotherapi:9102"},
        ]
    }
}

Code

function custom_resolver(host, url)
{
  var redirections = conf.proxy.redirections

  for (var i in redirections)
  {
    var red = redirections[i];
    var start = new RegExp("^"+ red.from)
    if (start.test(url))
    {
      var rhost = "http://"+ red.to;
      var rurl = url.replace(start, "")
      return rhost + rurl;
    }
  }

};

But custom revoler only return host i guess ? So I can not "rewrite" the url.
The above code does not work as expected:
10.0.0.42/foo/folder -> http://something:9100/folder/foo/folder
Because I it return http://something:9100/folder and the original url is added at the end /foo/folder

However it is possible to "rewrite" the url with proxy.register, but not the host.
proxy.register("10.0.0.42/foo", "http://something:9100")
It do the url "rewriting" but only works when we access to 10.0.0.42, if there is another ip to connect the server, like 172.17.0.5, it does not works.

Is there any way to do this ? Did I miss something ? May be I have to return from custom_resolver another type, like an object, (an array does not works) ? Is there a maner to combine the both solution ?

King regards,
Arnaud

Websocket proxy

I'm trying to use redbird to proxy a websocket, but it won't let me do it. Is this a known issue or am I missing something here? Is there an option, or do i need to set the protocoll manually? Thanks for any hint!

// client
var ws = new WebSocket('ws://localhost:9999');

// Server
var redbird = require('redbird');
var proxy = redbird({port: 9999});
proxy.register("localhost:9999", "ws://echo.websocket.org");

// ....
// Start http server on other port

var server = http.createServer(app);
server.listen(process.env.PORT || 61475);

Booting error

I get this error with code var proxy = redbird({port: 80});

redbird/node_modules/bluebird/js/main/captured_trace.js:300
    var firstStackLines = firstLineError.stack.split("\n");
                                        ^

TypeError: Cannot read property 'displayName' of undefined

would like xfwd to be false

If I change line 55 of index.js to:

  xfwd: opts.xfwd ? opts.xfwd : false,

instead of just:

xfwd: true

Then I get the option of setting this to true if I prefer it that way. For my current use case I need this to be set to false or it breaks the process I'm connecting to. Is this a change y'all would consider making?

Thanks,

/geir

Add bower.json

Hi! I really want to use bower for my project management but currently I am using 99% bower, and 1% NPM - just for this project.

I believe all you have to do is add the following to your package.json root:
"main": "index.js",

That'd be great.

Thanks!

Can't get HTTPS working on port 443

I can't get the reverse proxy on https working at all.

I can start the destination node server on port 443 (instead of 3000) and it works immediatly, which proves that the https server is working.

But I cannot seem to be able to proxy https requests received on port 443 directed to the destination on 3000.

In your example you used 8080 as listening port, but I believe that the default for https is 443.

  function sproxy(){
    var sproxy = require('redbird')({
      port: 80,
      ssl: {
        port: 443,
        key:  fs.readFileSync('/usr/share/nodejs/ssl/ssl.key'),
        cert: fs.readFileSync('/usr/share/nodejs/ssl/ssl.crt')
      }
    });
    sproxy.register('mydomain.com', "http://localhost:3000",{ssl: true,});   
  }


https.createServer({
  key:  fs.readFileSync('/usr/share/nodejs/ssl/ssl.key'),
  cert: fs.readFileSync('/usr/share/nodejs/ssl/ssl.crt')
},app).listen(3000,function(){

  sproxy();
})

Add CORS handling in the proxy

Hi,

Thanks for the great work on redbird, we've been using it in production for about 2 weeks, and we're quite happy with it ๐Ÿป, especially the HTTPs support is great!

The only problem we had, that is more an annoyance than a bug, is that we had to disable redirect because it is not compatible with CORS, since the 302 headers do not have any CORS information.

Would it be possible to add support for CORS inside redbird? That would be most appreciated (and useful).

Thanks!

websocket proxy

This is similar to another post.

redbird is running on port 80, I am running express-ws on a server, where the http and ws ports are the same, i.e port 801.

I have proxied the hostname to the nodejs instance running on port 801, and I can make a websocket connection successfully using port 801 but I cannot make the ws connection on port 80.

I would rather not connect to ws on 801 as this means I need to expose the port, which i don't really want to do ?

The error reported by the client when trying to connect on port 80 is:

failed: Error during WebSocket handshake: Invalid status line

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.