fix(gateway): keep production app ports private
This commit is contained in:
@@ -337,6 +337,9 @@ export async function startGateway(opts: GatewayOptions): Promise<RunningGateway
|
||||
env: {
|
||||
...process.env,
|
||||
PORT: String(appPort),
|
||||
// App ports are private gateway internals. Loopback prevents
|
||||
// clients from bypassing gateway auth and edge middleware.
|
||||
WRNEXUS_HOSTNAME: "127.0.0.1",
|
||||
WRNEXUS_ENV: environment,
|
||||
WRNEXUS_APP_NAME: app.name,
|
||||
WRNEXUS_APP_ORIGIN: app.publicOrigin ?? `http://${app.domains[0]}:${port}`,
|
||||
|
||||
@@ -141,6 +141,15 @@ function resolvePort(explicit?: number): number {
|
||||
return Number.isFinite(parsed) ? parsed : 3000;
|
||||
}
|
||||
|
||||
/** Resolve the production bind address. Gateway-managed app servers override
|
||||
* this with loopback so only the gateway is externally reachable. */
|
||||
export function resolveProductionHostname(
|
||||
explicit?: string,
|
||||
environmentHostname = process.env.WRNEXUS_HOSTNAME,
|
||||
): string {
|
||||
return environmentHostname?.trim() || explicit || "0.0.0.0";
|
||||
}
|
||||
|
||||
/** Build the route-matching tables + a module map from the manifest. */
|
||||
function buildProdRouter(manifest: ProdManifest): {
|
||||
router: Router;
|
||||
@@ -353,7 +362,7 @@ export async function createProductionServer(manifest: ProdManifest, opts: ProdO
|
||||
|
||||
const server = Bun.serve<WsData>({
|
||||
port: resolvePort(opts.port),
|
||||
hostname: opts.hostname ?? "0.0.0.0",
|
||||
hostname: resolveProductionHostname(opts.hostname),
|
||||
development: false,
|
||||
maxRequestBodySize: opts.maxBodyBytes ?? 10 * 1024 * 1024,
|
||||
fetch: handlers.fetch,
|
||||
|
||||
@@ -6,6 +6,14 @@ import {
|
||||
gatewayProxyHeaders,
|
||||
gatewayRestartDelay,
|
||||
} from "../src/gateway.ts";
|
||||
import { resolveProductionHostname } from "../src/prod.ts";
|
||||
|
||||
test("gateway-managed production apps bind to loopback", () => {
|
||||
expect(resolveProductionHostname(undefined, "127.0.0.1")).toBe("127.0.0.1");
|
||||
expect(resolveProductionHostname("0.0.0.0", "127.0.0.1")).toBe("127.0.0.1");
|
||||
expect(resolveProductionHostname("10.0.0.5", "")).toBe("10.0.0.5");
|
||||
expect(resolveProductionHostname(undefined, "")).toBe("0.0.0.0");
|
||||
});
|
||||
|
||||
test("gateway uses platform-safe hostname defaults", () => {
|
||||
expect(defaultGatewayHostname("development")).toBe("127.0.0.1");
|
||||
|
||||
Reference in New Issue
Block a user