Skip to content

Proxy ​

The Proxy plugin extracts client information from proxy headers when your application is behind a reverse proxy, load balancer, or CDN. It handles IP address extraction, protocol detection, and hostname reconstruction from common proxy headers like X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host.

Installation ​

The plugin is included with the @minimajs/server package and can be imported from @minimajs/server/plugins.

typescript
import { proxy } from "@minimajs/server/plugins";

Usage ​

Basic Usage ​

By default, calling proxy() with no arguments trusts all proxies and extracts IP, host, and protocol information from proxy headers. It is recommended to register it in your root module.

typescript
import { proxy } from "@minimajs/server/plugins";
import { request, type Routes, type Meta } from "@minimajs/server";

// Trust all proxies - extracts IP, host, and proto
export const meta: Meta = {
  plugins: [proxy()],
};

function getClientInfo() {
  const clientIp = request.ip();
  const info = request.url();
  return {
    ip: clientIp,
    host: info.host,
    proto: info.protocol,
  };
}

export const routes: Routes = {
  "GET /client-info": getClientInfo,
};

Disabling Features ​

Set any feature to false to disable it within your module configuration:

typescript
import { proxy } from "@minimajs/server/plugins";
import { type Meta } from "@minimajs/server";

export const meta: Meta = {
  plugins: [
    proxy({
      host: false, // Only extract IP, disable host and proto
      proto: false,
    }),
  ],
};

Configuration ​

trustProxies ​

Determines whether to trust proxy headers from the incoming request. When omitted or undefined, all proxies are trusted by default.

  • Type: boolean | string[] | ((ctx: Context) => boolean) | undefined
  • Default: undefined (trusts all proxies)
typescript
import { proxy } from "@minimajs/server/plugins";
import { request, type Meta } from "@minimajs/server";

export const meta: Meta = {
  plugins: [
    // Don't trust any proxies - extraction is disabled
    proxy({ trustProxies: [] }),

    // Trust specific proxy IP addresses (Node.js runtime only)
    proxy({
      trustProxies: ["127.0.0.1", "10.0.0.0/8"],
    }),

    // Custom trust validator
    proxy({
      trustProxies: (ctx) => {
        const ip = request.remoteAddr();
        return ip?.startsWith("10.") || ip === "127.0.0.1";
      },
    }),
  ],
};

ip ​

Configures IP address extraction from proxy headers. Enabled by default. Set to false to disable.

  • Type: IpSettings | ((ctx: Context) => string | null) | false
  • Default: Enabled with default settings

IpSettings Interface ​

typescript
interface IpSettings {
  header?: string | string[]; // Custom header(s) to check
  depth?: number; // 1-based index from the right (server-side) of the X-Forwarded-For header.
  strategy?: "first" | "last"; // Selection strategy for x-forwarded-for
}

Disabling IP Extraction ​

typescript
export const meta: Meta = {
  plugins: [proxy({ ip: false })],
};

When you specify depth, the plugin automatically uses it to extract the IP at that position in the X-Forwarded-For chain. depth is a 1-based index from the right (server-side).

For an X-Forwarded-For header of "client, proxy1, proxy2":

  • depth: 1 extracts proxy2
  • depth: 2 extracts proxy1
  • depth: 3 extracts client
typescript
// Extract the client IP, assuming 2 trusted proxies
// x-forwarded-for: "client, proxy1, proxy2"
export const meta: Meta = {
  plugins: [
    proxy({
      ip: { depth: 3 },
    }),
  ],
};

host ​

Configures hostname extraction from proxy headers. Enabled by default. Set to false to disable.

  • Type: HostSettings | ((ctx: Context) => string | null) | false
  • Default: Enabled with default settings

HostSettings Interface ​

typescript
interface HostSettings {
  header?: string | string[]; // Header(s) to check (default: "x-forwarded-host")
}

Disabling Host Extraction ​

typescript
export const meta: Meta = {
  plugins: [proxy({ host: false })],
};

Using Settings Object ​

typescript
// Multiple header fallback
export const meta: Meta = {
  plugins: [
    proxy({
      host: {
        header: ["x-forwarded-host", "x-original-host"],
      },
    }),
  ],
};

proto ​

Configures protocol extraction from proxy headers. Enabled by default, set to false to disable.

  • Type: ProtoSettings | ProtoCallback | false
  • Default: Enabled (uses default settings)

Note: proto and host are always extracted together. To disable both, you must set both proto: false and host: false.

Disabling Proto Extraction ​

typescript
export const meta: Meta = {
  plugins: [
    proxy({
      trustProxies: true,
      proto: false, // Must also set host: false to disable both
      host: false,
    }),
  ],
};

Complete Examples ​

Default (Development) ​

typescript
import { proxy } from "@minimajs/server/plugins";
import { type Meta } from "@minimajs/server";

// Trust all proxies, extract all information
export const meta: Meta = {
  plugins: [proxy()],
};

Behind NGINX ​

typescript
import { proxy } from "@minimajs/server/plugins";
import { type Meta } from "@minimajs/server";

export const meta: Meta = {
  plugins: [
    proxy({
      trustProxies: ["127.0.0.1"], // Trust localhost NGINX
      ip: { depth: 2 }, // If NGINX is the only proxy, client IP is at depth 2
    }),
  ],
};

Behind Multiple Proxies ​

typescript
import { proxy } from "@minimajs/server/plugins";
import { type Meta } from "@minimajs/server";

export const meta: Meta = {
  plugins: [
    proxy({
      trustProxies: ["10.0.0.1", "10.0.0.2"], // Trust specific proxies
      ip: { depth: 3 }, // If there are 2 proxies, client IP is at depth 3
      host: {
        header: ["x-forwarded-host", "x-original-host"],
      },
    }),
  ],
};

Custom Logic for All Options ​

typescript
import { proxy } from "@minimajs/server/plugins";
import { type Meta } from "@minimajs/server";

export const meta: Meta = {
  plugins: [
    proxy({
      trustProxies: (ctx) => {
        const ip = ctx.incomingMessage?.socket?.remoteAddress;
        return ip === "127.0.0.1" || ip?.startsWith("10.");
      },
      ip: (ctx) => {
        // Prefer Cloudflare header, fallback to X-Forwarded-For
        return (
          ctx.request.headers.get("cf-connecting-ip") ||
          ctx.request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
          null
        );
      },
      host: (ctx) => {
        const host = ctx.request.headers.get("x-forwarded-host") || ctx.request.url.hostname;
        return host.split(":")[0]; // Strip port
      },
      proto: (ctx) => {
        const proto = ctx.request.headers.get("x-forwarded-proto");
        const ssl = ctx.request.headers.get("x-arr-ssl");
        return proto === "https" || ssl === "on" ? "https" : "http";
      },
    }),
  ],
};

Accessing Extracted Values ​

IP Address ​

typescript
import { request, type Routes } from "@minimajs/server";

function getClientIp() {
  const clientIp = request.ip();
  return { ip: clientIp };
}

export const routes: Routes = {
  "GET /client-ip": getClientIp,
};

Host and Protocol ​

The extracted host and protocol are used to reconstruct the request.url() object:

typescript
import { request, type Routes } from "@minimajs/server";

function getRequestInfo() {
  const info = request.url(); // type URL
  return {
    host: info.host,
    proto: info.protocol,
    url: info.href,
  };
}

export const routes: Routes = {
  "GET /request-info": getRequestInfo,
};

Security Considerations ​

Trust Only Known Proxies in Production ​

By default, proxy() trusts all proxies. In production, always specify which proxies to trust via meta.plugins in your root module.

typescript
import { proxy } from "@minimajs/server/plugins";
import { type Meta } from "@minimajs/server";

export const meta: Meta = {
  plugins: [
    // ✅ Production - trust specific proxies
    proxy({
      trustProxies: ["10.0.1.1", "10.0.1.2", "10.0.0.0/16"],
    }),
  ],
};

Header Spoofing ​

Without proper trust validation, clients can spoof headers. Always ensure trustProxies is correctly configured to only validate headers from your actual infrastructure.

Common Proxy Headers ​

HeaderPurposeExample Values
X-Forwarded-ForClient IP address chain203.0.113.195, 70.41.3.18
X-Forwarded-ProtoOriginal protocolhttps, http
X-Forwarded-HostOriginal hostnameexample.com
X-Real-IPClient IP (NGINX)203.0.113.195
CF-Connecting-IPClient IP (Cloudflare)203.0.113.195
X-Arr-SSLSSL indicator (Azure)on

TypeScript Types ​

typescript
import type { ProxyOptions, IpSettings, HostSettings, ProtoSettings } from "@minimajs/server/plugins";

const options: ProxyOptions = {
  trustProxies: true,
  ip: { depth: 1 },
  host: { header: "x-forwarded-host" },
  proto: {},
};