A library to build modern http reverse proxies. By default supports http/http2, TLS terminaison, circuit breaker, retry, weighted round robin load balancing, api key access, etc .... Provides a pluggable module system to add new features easily.
Experimental project to try new things on http reverse proxies. Do not use in production ... yet, or not ;)
you can fetch the last Heimdallr build from bintray an run it
wget -q --show-progress https://dl.bintray.com/mathieuancelin/heimdallr/heimdallr.jar/snapshot/heimdallr.jar
java -jar heimdallr.jar --proxy-config=/path/to/heimdallr.conf
or you can use the latest Docker image
docker run -p "8080:8080" mathieuancelin-docker-heimdallr-docker.bintray.io/heimdallr:latest
Heimdallr is designed to be embedded and enhanced through pluggable modules
import io.heimdallr.Proxy
object MyOwnProxy {
def main(args: Array[String]): Unit = {
Proxy.defaultFromConfigPath("./heimdallr.conf") match {
case Left(e) => println(s"error while parsing config. $e")
case Right(proxy) => proxy.stopOnShutdown()
}
}
}
import io.heimdallr.Proxy
import java.io.File
object MyOwnProxy {
def main(args: Array[String]): Unit = {
Proxy.defaultFromConfigPath("https://foo.bar/heimdallr.conf") match {
case Left(e) => println(s"error while parsing config. $e")
case Right(proxy) => proxy.stopOnShutdown()
}
}
}
import io.heimdallr.Proxy
import java.io.File
object MyOwnProxy {
def main(args: Array[String]): Unit = {
Proxy.defaultFromConfigFile(new File("./heimdallr.conf")) match {
case Left(e) => println(s"error while parsing config. $e")
case Right(proxy) => proxy.stopOnShutdown()
}
}
}
import io.heimdallr.Proxy
import io.heimdallr.models._
object MyOwnProxy {
def main(args: Array[String]): Unit = {
val proxy = Proxy.defaultWithConfig(ProxyConfig(
http = HttpConfig(
httpPort = 8080,
httpsPort = 8443,
listenOn = "0.0.0.0",
),
api = ApiConfig(
httpPort = 9080,
httpsPort = 9443,
listenOn = "127.0.0.1",
certPath = Some("./cert/foo.bar-cert.pem"),
keyPath = Some("./cert.foo.bar-key.pem"),
certPass = Some("foo")
),
services = Seq(
Service(
id = "load-balancing-test",
domain = "test.foo.bar",
targets = Seq(
Target("http://127.0.0.1:8081"),
Target("http://127.0.0.1:8082"),
Target("http://127.0.0.1:8083")
),
additionalHeaders = Map(
"Authorization" -> "basic 1234"
),
publicPatterns = Set("/*")
)
)
)).stopOnShutdown()
}
}
Heimdallr provides extension points to add new feature on top of basic http proxies
sh ./scripts/build.sh server
or to build everything
sh ./scripts/build.sh all
for http2
sbt
~reStart --- -javaagent:/Users/mathieuancelin/.ivy2/cache/org.mortbay.jetty.alpn/jetty-alpn-agent/jars/jetty-alpn-agent-2.0.6.jar
curl2 -k -H 'Host: test.foo.bar' https://127.0.0.1:8443 --include
curl2 -k --http2-H 'Host: test.foo.bar' https://127.0.0.1:8443 --include
curl2 -k -v -H 'Host: test.foo.bar' https://127.0.0.1:8443 --include
wrk -t1 -c1 -d20s -H "Host: test.foo.bar" http://127.0.0.1:8080/ >> /dev/null
wrk -t2 -c200 -d60s -H "Host: test.foo.bar" --latency http://127.0.0.1:8080/
docker kill $(docker ps -q)
docker run -d -p "8081:80" emilevauge/whoami
docker run -d -p "8082:80" emilevauge/whoami
docker run -d -p "8083:80" emilevauge/whoami
- built-in kafka support as commands input
- built-in kafka support as logs output
- implements more statsd measure points
- dynamic TLS
- add extra typesafe attributes to services and apikey for modules ???
- write some usage docs in readme
- statsd support
- handle wildcard matching hosts
- otoroshi config poll module
- find a name for the project
- admin API complete on another port. Add service to serve this api
- api based on diff commands
- scan config file for changes and reload
- docker dev
- session.sh
- build.sh
- travis.yml
- upload on bintray
- API to change state of a Proxy instance
- API to get one service per command
- read API rest style to get services
- read API rest style to get one service
- disable api from config
- config for state file (period for writes, enabled or not, etc ...)
- demo mode (--demo) or use config file ./proxy.conf
- remote config file
- remote state (with polling support from conf)
- ProxyConfig object for Api integration
- withConfig(ProxyConfig)
- withConfigFrom(path)
- additional headers
- metrics JMX or statsd with metrics (maybe statsd integration already provided)
- apikeys on the service (no quotas), clientId, clientSecret, enabled, name
- pass if public or apikey
- api integration + main class
- save state to file periodically
- circuit breaker config in service
- config for ssl
- matching root
- target root
- public / private stuff
- support for WS
- support JWT auth
- start https only if certificate provided
- smaller https password
- pass --proxy.config=???
- pass --proxy.config=???
- shutdown hook in main
- handle service access preconditions with pluggable modules
- handle service access with pluggable modules (apikey + throttling, global throtthling, ip filtering)
- handle headers out manipulation with pluggable modules
- handle errors rendering with pluggable modules
- handle target set choice with pluggable modules