Behind a reverse proxy

Resolve the real client IP when Deno sits behind nginx, Caddy, or a cloud load balancer.

Default behavior

Without options, req.ip is the TCP peer address from Deno’s serve info. Header values cannot override it.

Trusted proxy

import { HttpServer } from "jsr:@webtools/expressapi";

const server = new HttpServer({ trustProxy: true });

server.get("/whoami", (req, res) =>
  res.json({
    ip: req.ip,
    // first hop of x-forwarded-for when trustProxy is true
  }));

if (import.meta.main) server.listen(5050);

With trustProxy: true, ExpressAPI reads the first entry of x-forwarded-for (trimmed). If the header is absent, it falls back to the TCP address (or null in tests without serve info).

Example nginx snippet

location / {
  proxy_pass http://127.0.0.1:5050;
  proxy_set_header Host $host;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  proxy_set_header X-Forwarded-Proto $scheme;
}

API details: Advanced, HttpServer.