Home / Modules / yoja-reverse-proxy
yoja-reverse-proxy
Host- and path-based routing to one or many upstreams, with least-loaded port selection, path rewriting, SSL termination and a token-protected admin API to swap rules at runtime.
Installation
implementation 'com.easygoingapi:yoja-reverse-proxy:VERSION'
Quick start
import com.easygoingapi.yoja.reverse.proxy.*;
import com.easygoingapi.yoja.reverse.proxy.ReverseProxyRule.Url;
YojaApp.start();
ReverseProxyServer.builder(8080)
.silent(false)
.admin(9090, "secret-token")
.rule(new ReverseProxyRule(
Url.from("app.example.com", "/api"),
Url.to(false, "backend.internal")
.port(8081, 8082) // least-loaded wins
.cutsPathWith("/api")
.startsPathWith("/v1")
.build()))
.start();
ReverseProxyServer
ReverseProxyServer class (Certificatable)
Owns two Vert.x HTTP servers: the public proxy and an optional admin server.
Factory (Builder)| Signature | Returns | Description |
|---|---|---|
static builder(int proxyPort) | Builder | |
Builder.admin(int port, String token) | Builder | Enable the admin server on the given port, protected by token |
Builder.ssl(Path key, Path cert) | Builder | TLS with PEM files |
Builder.sslSelfSigned() | Builder | TLS with an auto-generated self-signed certificate |
Builder.options(HttpServerOptions) | Builder | Override Vert.x options |
Builder.sslProxy(boolean) | Builder | Whether upstream-facing HTTP engines dial over TLS |
Builder.silent(boolean) | Builder | Drop unresolved requests silently instead of returning 404 |
Builder.rule(ReverseProxyRule) | Builder | Register a routing rule |
Builder.rules(Set<ReverseProxyRule>) | Builder | Register multiple rules at once |
Builder.elseRule(Function<HttpUrl, HttpUrl>) | Builder | Fallback resolver when no rule matches |
Builder.onResolve(Handler<ReverseProxyResult>) | Builder | Listener invoked on every resolution |
Builder.start() | Future<ReverseProxyServer> | Bind both servers |
| Signature | Returns | Description |
|---|---|---|
start() | Future<Void> | Start both servers |
stop() | Future<Void> | Stop both servers |
startAdmin() | Future<Void> | Start the admin server independently |
stopAdmin() | Future<Void> | Stop the admin server independently |
proxyState() | State | stopping | stopped | starting | started |
adminState() | State | |
updateCertificate(Path key, Path cert) | Future<Boolean> | Hot-swap TLS material on both servers |
| Signature | Returns | Description |
|---|---|---|
proxyPort() | int | |
adminPort() | Integer | null when the admin server is not enabled |
certificate() | HttpCertificate | |
static adminTokenHeaderKey() | String | Header name carrying the current admin token (Reserve-Proxy-Token) |
static adminNewTokenHeaderKey() | String | Header name carrying the new token on rotation (New-Reserve-Proxy-Token) |
static defaultOptions(HttpCertificate) | HttpServerOptions | HTTP/2 with ALPN fallback |
ReverseProxyRule
ReverseProxyRule class
Mapping from an inbound URL pattern to an upstream target. JSON-serialisable for admin API exchange. Identified by its from (host + path).
| Signature | Returns | Description |
|---|---|---|
ReverseProxyRule(Url.From, Url.To) | ||
from() | Url.From | Inbound host + path pattern |
to() | Url.To | Upstream target description |
ReverseProxyRule.Url · Url.From · Url.To nested classes
Url.From — inbound pattern factory
| Signature | Returns | Description |
|---|---|---|
Url.from(String host) | Url.From | Match any path on this host |
Url.from(String host, String path) | Url.From | Match a specific path prefix on this host |
| Signature | Returns | Description |
|---|---|---|
Url.to(boolean ssl, String host) | Url.To.Builder | Start building an upstream target |
port(int [, int...]) | Url.To.Builder | Load-balanced port set; least-loaded port wins |
ports(Set<Integer>) | Url.To.Builder | Bulk-set load-balanced ports |
cutsPathWith(String) | Url.To.Builder | Strip this prefix from the inbound path before forwarding |
startsPathWith(String) | Url.To.Builder | Prepend this prefix to the path after stripping |
build() | Url.To |
| Signature | Returns | Description |
|---|---|---|
ssl() | boolean | Whether the upstream connection uses TLS |
host() | String | Upstream hostname |
ports() | Set<Integer> | Load-balanced port pool |
cutsPathWith() | String | |
startsPathWith() | String | |
apply(String path) | String | Apply the configured rewriting to an inbound path |
Resolution results
ReverseProxyResult · ReverseProxyRuleResult classes
Outcome of resolving an inbound URL. ReverseProxyRuleResult extends ReverseProxyResult and is emitted when a registered rule matched.
| Signature | Returns | Description |
|---|---|---|
fromUrl() | HttpUrl | The original inbound URL |
toUrl() | HttpUrl | The resolved upstream URL; null on a miss |
isResolved() | boolean | true when a target URL was produced |
reverseProxyRule() (RuleResult only) | ReverseProxyRule | The rule that produced this resolution |
Admin API
When admin is enabled, six endpoints are exposed on the admin port:
POST /update/token— rotate the admin token. New value in theNew-Reserve-Proxy-Tokenheader.POST /put/rule— add or replace a single rule (JSON body).POST /put/rules— batch upsert (JSON array).POST /remove/rule— drop a rule by itsUrl.From(JSON body).POST /remove/rules— batch drop (JSON array).GET /load/rules— list every active rule.
Every request must carry the current admin token in the
Reserve-Proxy-Token header. Operations are serialised
through a single worker keyed by the proxy port so concurrent updates
and lookups never race.
ReverseProxySwitcher · ReverseProxySwitcherWebClient internal classes
Dispatch engine wired by ReverseProxyServer.start(). Documented for completeness; not normally instantiated directly.
| Signature | Returns | Description |
|---|---|---|
resolve(HttpServerRequest) | ReverseProxyResult | Resolve an inbound request to an upstream URL |
adminRouter() | Router | Vert.x router carrying the admin endpoints |
proxyRouter() (subclass) | Router | Vert.x router that forwards requests upstream |
isSilent() | boolean | |
getProxyPort() | int |
ReverseProxyException runtime exception
Raised for invalid rules and malformed URIs. Extends YojaAppException.
Module README: yoja-reverse-proxy/README.md.