Skip to content
Shiny Controls v1.0 - The Ultra Control Suite for .NET MAUI & BlazorO...M...G!

Reverse Proxy

app.MapProxy("/api/{*path}", "https://api.example.com");

Every method on that route is forwarded to the destination, and the answer is copied back.

The reason this belongs in an embedded server rather than in a load balancer: the device is often the only thing that can reach what the caller wants.

  • A phone bridges one of its own loopback services out through a tunnel.
  • A Raspberry Pi fronts a printer or a camera that speaks HTTP with no TLS and no authentication — and the Pi adds both.
  • A dev server serves the app and forwards /api to the real backend, so the browser sees one origin and CORS never enters the picture.

The remaining path comes from the route’s catch-all parameter, so /api/{*path} sends /api/orders/7?full=1 to {destination}/orders/7?full=1. A route with no catch-all forwards to the destination exactly as written, which is what a one-to-one mapping of a single endpoint wants.

Bodies stream in both directions — nothing is buffered, so a large upload through a proxy route costs the same memory as a small one.

Headers are copied except the hop-by-hop ones (Connection, Keep-Alive, Transfer-Encoding, Upgrade, TE, Trailer, Proxy-*), which describe a connection that is not the one being made. X-Forwarded-For, -Proto and -Host describe the original caller — without them the upstream sees this server and nothing else.

Status When
502 The upstream is unreachable or answered nonsense. The caller’s request was fine; ours was not answered
504 The upstream did not answer inside Timeout (100s by default)
app.MapProxy("/printer/{*path}", "http://192.168.1.50", o =>
{
o.RewriteHost = false; // pass the caller's Host through to a virtual host
o.Timeout = TimeSpan.FromSeconds(10);
o.BeforeSend = (request, ctx) => request.Headers.Add("X-Api-Key", key);
});
Property Default Notes
Client a private one Redirects off, cookies off, no automatic decompression
Timeout 100s Exceeding it is a 504
AddForwardedHeaders true X-Forwarded-For / -Proto / -Host
RewriteHost true Sends the destination’s host, which is what most upstreams route on
RewriteUri null Replaces the whole “destination + remainder” rule
BeforeSend null Last chance to touch the outbound request
AfterReceive null First look at the upstream response

The default client does not follow redirects and does not decompress: following a redirect on the caller’s behalf hides it from them, and decompressing here only to recompress on the way out spends the device’s battery to change nothing.