/** * Host-facing addressing for the local Ory stack — which ports it publishes on * the host, and which host name everything else should use to reach it. * * Two kinds of port live in this stack, and conflating them is the bug this * module exists to prevent: * * - **Container-internal ports** are what each service listens on *inside* the * compose network, and what one service uses to address another * (`http://kratos:4433`). They live on a private bridge network, so they can * never collide with anything on the host and there is no reason to make them * configurable. They are fixed constants below. * - **Host ports** are the left-hand side of a compose `ports:` mapping — the * only ports that are actually claimed on the developer's machine, and so the * only ones that can collide. Every one of them is overridable. * * The defaults are the stock upstream Ory ports (4433/4434, 4444/4445, * 4466/4467, …), which is deliberate — they are the ports every Ory doc and * tutorial uses. It also means a developer who already runs Ory locally, which * is precisely this stack's audience, collides on first run. Before #63 there * was no override and no diagnosis: `docker compose up` failed with Docker's * raw "port is already allocated" and the only apparent fix was to hand-edit * the generated compose file, which the next `local up` regenerates away. * * Three levels of control, cheapest first: * * 1. `ORY_LOCAL_PORT_OFFSET=100` shifts *every* default by a constant, which is * the common case ("something else owns the Ory ports, move the whole * stack"). Relative spacing is preserved, so the set stays collision-free * with itself. * 2. `ORY_LOCAL__PORT` pins one service exactly, and wins over the * offset. * 3. `ORY_LOCAL_HOST` changes the host every generated URL advertises, for a * remote Docker daemon or an agent running inside a container. It defaults * to the host parsed out of `DOCKER_HOST` when that points somewhere other * than this machine, so the remote-daemon case usually needs no flag at all. */ export declare const KRATOS_PUBLIC_CONTAINER_PORT = 4433; export declare const KRATOS_ADMIN_CONTAINER_PORT = 4434; export declare const KETO_READ_CONTAINER_PORT = 4466; export declare const KETO_WRITE_CONTAINER_PORT = 4467; export declare const HYDRA_PUBLIC_CONTAINER_PORT = 4444; export declare const HYDRA_ADMIN_CONTAINER_PORT = 4445; export declare const HYDRA_TOKEN_USER_CONTAINER_PORT = 5555; export declare const GATEWAY_CONTAINER_PORT = 4000; export declare const LOGIN_UI_CONTAINER_PORT = 4455; export declare const OATHKEEPER_PROXY_CONTAINER_PORT = 4456; export declare const OATHKEEPER_API_CONTAINER_PORT = 4457; /** Console Lite's Dockerfile sets `ENV PORT=3000`. */ export declare const CONSOLE_CONTAINER_PORT = 3000; /** Every host port the stack publishes, in the order `local status` lists them. */ export declare const LOCAL_PORT_NAMES: readonly ["gateway", "console", "loginUi", "kratosPublic", "kratosAdmin", "ketoRead", "ketoWrite", "hydraPublic", "hydraAdmin", "hydraTokenUser", "oathkeeperProxy", "oathkeeperApi"]; export type LocalPortName = (typeof LOCAL_PORT_NAMES)[number]; export type ResolvedLocalPorts = Record; interface PortSpec { /** Default host port — the stock Ory port, and the container port it maps to. */ default: number; /** Env var that pins this port exactly. */ envVar: string; /** Human label used in conflict messages and banners. */ label: string; } /** * The port table. `default` doubles as the container-internal port for every * service, which is what keeps the generated mapping readable * (`"4433:4433"` by default, `"5433:4433"` once overridden). */ export declare const LOCAL_PORT_SPECS: Record; /** Shifts every default port by a constant. Overridden per-port by the specific var. */ export declare const PORT_OFFSET_ENV_VAR = "ORY_LOCAL_PORT_OFFSET"; /** Overrides the host name every generated URL advertises. */ export declare const LOCAL_HOST_ENV_VAR = "ORY_LOCAL_HOST"; /** * Skips every port probe — the pre-start preflight *and* the post-failure * diagnosis. * * Both open real sockets, which is the right thing before starting containers * and the wrong thing in a unit test (the core suite sets this so no test * depends on which ports happen to be free on the machine running it) or in a * sandbox that forbids listening. The sandbox case is why this covers the * diagnosis too: where binding is denied, `isPortAvailable` answers "taken" for * every port, so an unrelated startup failure would otherwise be reported as a * confident and completely wrong "every port is in use". */ export declare const SKIP_PORT_CHECK_ENV_VAR = "ORY_LOCAL_SKIP_PORT_CHECK"; export declare function portCheckDisabled(env?: Env): boolean; type Env = Record; /** * Resolve every host port from the environment. * * Invalid values are **ignored with a warning** rather than throwing: this runs * on the way into `local up`, and refusing to start because one env var has a * typo would be a worse outcome than starting on the documented default and * saying so. Warnings are returned rather than printed so the caller controls * the output stream. */ export declare function resolveLocalPorts(env?: Env): { ports: ResolvedLocalPorts; warnings: string[]; }; export type LocalHostSource = "env" | "docker-host" | "default"; export declare const DEFAULT_LOCAL_HOST = "localhost"; /** * Pull the host out of a `DOCKER_HOST` value. * * `unix://` and `npipe://` sockets are this machine, so they yield nothing and * the default stands. A `tcp://` or `ssh://` daemon publishes the stack's ports * on *its* host, not ours, so that host is what generated URLs have to * advertise — otherwise every URL we print and persist points at a machine that * isn't running the stack. */ export declare function hostFromDockerHost(dockerHost: string | undefined): string | undefined; export declare function isLoopbackHost(host: string): boolean; /** * The host name every generated URL should advertise: config files, banners, * the health probe, and the `projectUrl` that `local configure` persists. */ export declare function resolveLocalHost(env?: Env): { host: string; source: LocalHostSource; }; /** * True when the Docker daemon publishes ports on *this* machine, which is the * only case where probing a local socket says anything about whether the stack * will be able to bind. With a remote daemon the probe would test the wrong * host, so callers skip the preflight entirely rather than report a conflict * that isn't there (or miss one that is). */ export declare function isLocalDockerDaemon(env?: Env): boolean; /** Build an `http://host:port` origin, bracketing bare IPv6 literals. */ export declare function hostUrl(host: string, port: number): string; export interface PortConflict { name: LocalPortName; port: number; label: string; envVar: string; } /** * Can we bind this port? Docker publishes on all interfaces, so we test the * same thing it will do. A port held on loopback alone still fails a * wildcard bind, so this catches both. * * Anything other than a clean listen counts as unavailable: `EADDRINUSE` is the * case we are looking for, and `EACCES` (a privileged port without rights) * would fail the container just the same. */ export declare function isPortAvailable(port: number, timeoutMs?: number): Promise; /** * Which of the stack's host ports are already taken. Probed concurrently — * twelve sequential binds would add noticeable latency to every `local up`. */ export declare function findPortConflicts(ports: ResolvedLocalPorts): Promise; /** * The message a user gets instead of Docker's "port is already allocated": * which service wanted which port, and the two ways to move it. */ export declare function describePortConflicts(conflicts: PortConflict[]): string; export {};