HTTP routing on Heroku is made up of three main logical layers:
- The state synchronization layer ensures that all nodes in the routing stack are aware of the latest changes in domains, application, and dyno locations across the platform;
- The routing layer chooses which dyno will handle an HTTP request (random or sticky), performs logging, error-reporting, and so on;
- The HTTP proxying layer handles the validation, normalization, and forwarding of requests between clients and dynos.
This last part is the one the platform team is happy to open-source today with the Vegur library.
Vegur can be thought of a bit like an nginx reverse-proxy, except its entire list of hosts and configuration is fully programmable, making it easy to hardcode, use files, use databases, or push state updates directly into the proxy and router states, while also allowing the same dynamism for features such as routing algorithms, choice of debugging headers, and so on.
This turned out to be a critical feature that few or none of the existing proxying mechanisms could support at a scale the size of Heroku. Vegur has been written in such a way that any compatible router could use it for its proxying job without compromising on the routing logic itself, making it easier to focus on higher level tasks.
It allows the following parts, to name a few, to be delegated to an Erlang code base:
- domain name lookup
- selection of one out of many back-ends for a domain
- choice of interface for a given back-end
- checkout/checkin mechanism for resource management
- customizeable error pages for every potential kind of failure during the proxying of a request
- per-application (or even per-backend) control of features such as tunneling of 100-continue requests
- ability to add headers both upstream and downstream
Everything is documented in the README of the project with example code, samples, and examples.
Vegur has been used in production for over a year on the Heroku platform, and is also currently used to power the router in Heroku Private Spaces.
We hope this makes it easier for the community at large to develop interesting routing products, and enriches the ecosystem as a whole.