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)
SignatureReturnsDescription
static builder(int proxyPort)Builder
Builder.admin(int port, String token)BuilderEnable the admin server on the given port, protected by token
Builder.ssl(Path key, Path cert)BuilderTLS with PEM files
Builder.sslSelfSigned()BuilderTLS with an auto-generated self-signed certificate
Builder.options(HttpServerOptions)BuilderOverride Vert.x options
Builder.sslProxy(boolean)BuilderWhether upstream-facing HTTP engines dial over TLS
Builder.silent(boolean)BuilderDrop unresolved requests silently instead of returning 404
Builder.rule(ReverseProxyRule)BuilderRegister a routing rule
Builder.rules(Set<ReverseProxyRule>)BuilderRegister multiple rules at once
Builder.elseRule(Function<HttpUrl, HttpUrl>)BuilderFallback resolver when no rule matches
Builder.onResolve(Handler<ReverseProxyResult>)BuilderListener invoked on every resolution
Builder.start()Future<ReverseProxyServer>Bind both servers
Lifecycle
SignatureReturnsDescription
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()Statestopping | stopped | starting | started
adminState()State
updateCertificate(Path key, Path cert)Future<Boolean>Hot-swap TLS material on both servers
Accessors
SignatureReturnsDescription
proxyPort()int
adminPort()Integernull when the admin server is not enabled
certificate()HttpCertificate
static adminTokenHeaderKey()StringHeader name carrying the current admin token (Reserve-Proxy-Token)
static adminNewTokenHeaderKey()StringHeader name carrying the new token on rotation (New-Reserve-Proxy-Token)
static defaultOptions(HttpCertificate)HttpServerOptionsHTTP/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).

SignatureReturnsDescription
ReverseProxyRule(Url.From, Url.To)
from()Url.FromInbound host + path pattern
to()Url.ToUpstream target description

ReverseProxyRule.Url · Url.From · Url.To nested classes

Url.From — inbound pattern factory
SignatureReturnsDescription
Url.from(String host)Url.FromMatch any path on this host
Url.from(String host, String path)Url.FromMatch a specific path prefix on this host
Url.To.Builder — upstream target
SignatureReturnsDescription
Url.to(boolean ssl, String host)Url.To.BuilderStart building an upstream target
port(int [, int...])Url.To.BuilderLoad-balanced port set; least-loaded port wins
ports(Set<Integer>)Url.To.BuilderBulk-set load-balanced ports
cutsPathWith(String)Url.To.BuilderStrip this prefix from the inbound path before forwarding
startsPathWith(String)Url.To.BuilderPrepend this prefix to the path after stripping
build()Url.To
Url.To — accessors
SignatureReturnsDescription
ssl()booleanWhether the upstream connection uses TLS
host()StringUpstream hostname
ports()Set<Integer>Load-balanced port pool
cutsPathWith()String
startsPathWith()String
apply(String path)StringApply 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.

SignatureReturnsDescription
fromUrl()HttpUrlThe original inbound URL
toUrl()HttpUrlThe resolved upstream URL; null on a miss
isResolved()booleantrue when a target URL was produced
reverseProxyRule() (RuleResult only)ReverseProxyRuleThe 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 the New-Reserve-Proxy-Token header.
  • 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 its Url.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.

SignatureReturnsDescription
resolve(HttpServerRequest)ReverseProxyResultResolve an inbound request to an upstream URL
adminRouter()RouterVert.x router carrying the admin endpoints
proxyRouter() (subclass)RouterVert.x router that forwards requests upstream
isSilent()boolean
getProxyPort()int

ReverseProxyException runtime exception

Raised for invalid rules and malformed URIs. Extends YojaAppException.