Node.js Runtime
Node.js Runtime is code the platform loads before a deployed Node.js application's server starts, called the runtime harness. It checks incoming requests, routes outbound connections through the platform's proxy, records outbound connections, and enforces request deadlines. The platform injects the settings that turn these protections on at every deploy and promote, so the harness behaves the same in every environment the application has. Deploy an application describes each step of a deploy.
Use it when
Every application deployed through the platform's image build uses Node.js Runtime automatically. Supply a Node.js HTTP server that listens on PORT. You install nothing and export nothing special. Read this page when you choose an HTTP client, handle request cancellation, or diagnose refused and interrupted requests.
The manifest's egress list defines the outbound destinations, and the platform's proxy applies its own checks on authentication, destination, and port. Egress firewall and request limits describes both. Node.js Runtime points supported clients at that proxy. It does not replace the proxy's checks or the hosting network's rules.
What it provides
- Incoming-request checks on the Node.js HTTP server. A request from another machine without the serving router's mark receives 403
router_mark_requiredbefore the application's listener runs. A loopback request is accepted without a mark. The checks also cover HTTP upgrade andCONNECTrequests. A separate HTTPS or HTTP/2 server is not covered. The harness removes the mark header from every request it accepts, so the application's request listener never sees it. It also removes the mark setting from the application's environment and keeps the value in a file only the container's own user can read. - A check on scheduled-handler paths. A request to a schedule's path without the router's schedule-invocation header receives 404
scheduled_handler_only. The mark check runs first. The configured paths are the schedule declarations the deploy or the promote read when it applied the container. A declaration added later reaches the container at the environment's next deploy or promote, and the platform fires a declaration only against a container applied at or after it. - Proxy settings: the environment variables
HTTPS_PROXY,HTTP_PROXY, andNO_PROXY, and an undici global dispatcher. Globalfetch, undici-based clients, and clients that read those variables use the proxy. Platform endpoints and loopback names bypass it. - Records of outbound connections under the log source
harness: oneegress_establishmentsrecord per host, port, and outcome per minute, with the count and the first and last instants. Each connection whose outcome is notconnectedalso gets its ownegress_establishmentrecord. The harness sends the records through the logging client under the application's own credential, so they outlive the process. - An abort signal at
request.signal. Requests and scheduled runs can have different deadlines. If the response has not ended within the grace interval after the signal, the harness ends the process. A watchdog also ends a process whose event loop is blocked. harness_refusal,window_ended, andprocess_endedlog records, written to the process's standard output and read with thecontainersource. When a process ends, the serving router responds to each other request in flight with 502upstream_endedif no response header had gone out.
The mark's removal has limits. Monitoring or tracing code that loads before the harness can read the mark: code loaded with --require, or with an --import your start command puts ahead of the harness's in NODE_OPTIONS. So can code that wraps the server to watch upgrade requests. Set such code to capture no x-turnzero-cloud- header. A server in a worker thread is not covered when the thread runs code passed as a string, or when its environment lacks NODE_OPTIONS.
If the harness cannot write the mark's file, the setting stays in the environment and one router_mark_setting_kept record appears under the container source. If the file exists but cannot be read, one router_mark_file_unread record appears there and that process runs unguarded. Your application's own code must never read that file.
The connection records miss some connections:
- Connections opened by native add-ons and child processes.
- Connections to platform endpoints and to the logging service's own origin, which are left out on purpose.
- The minute still open when the process ends. The harness writes it to standard output at exit, so it reaches the process's console and not the log stream.
A stack trace from your handler can end with frames in file:///harness/harness.mjs, after your own, because the harness hands each request to your listener.
Availability
Version 0.10.6 is the package's current version, and list_library reports the version the platform currently publishes. The library publishes only the package's documents. The platform loads the harness ahead of your code, so no application copies or installs it.
A local run loads no harness, so these protections exist only in a deployed copy. A local run's keyed external calls go through the public gateway at TURNZERO_CLOUD_GATEWAY_URL, so the machine stores no provider key. Run locally states what else a local run uses.
The platform injects every setting the harness reads, so your application sets none of them. If a setting is missing or invalid, the protection it controls is off: no router-mark check, no deadline, or no proxy routing.
Related feature packages
Database and Storage use platform endpoints outside the proxy. Secrets provides named credentials for your application's calls. Egress calls external APIs on a stored key through the gateway.
What an application must do
Declare the outbound HTTPS destinations your application calls in the manifest's egress list. Egress firewall and request limits states the hostname rules and the port. Platform endpoints need no entry.
Read the application's mode as egress_mode in the read_status response. A new application starts in observe mode, where the proxy records undeclared destinations and permits them. In enforce mode, the proxy refuses them with 403 egress_undeclared and an X-Egress-Refusal header. Platform staff change the mode with set_egress_mode, an action your tool does not call. The manifest is not a complete network allowlist: the proxy's own checks apply in both modes, and the deployed network rules include separate platform allowances.
Recognize a proxy refusal in your code. Through the harness's dispatcher, global fetch rejects with TypeError: fetch failed, and its cause is an EgressRefusedError. An undici client called on the dispatcher directly receives the EgressRefusedError itself. Every proxy refusal takes this form, among them a wrong credential (407 proxy_authentication_required), a refused port, and a refused address class. Read the error's members:
| Member | What it contains |
|---|---|
error.cause.code === 'EGRESS_REFUSED' |
True for a proxy refusal. |
cause.refusal |
The refusal's name. |
cause.status |
The proxy's status. |
cause.host, cause.port |
The target. |
cause.remedy |
For egress_undeclared, the manifest edit for a hostname or a fixed sentence for an address literal. Null for every other refusal. |
Use a covered HTTP client. Global fetch, undici, and SDKs built on them use the harness's dispatcher, and axios uses the proxy variables. Clients such as node:https, node-fetch, got, and ws need an explicit proxy agent. Without one, a call may fail with a connection error or reach the destination directly, depending on the network rules, rather than meet a named proxy refusal.
Handle request.signal, and end the response when it fires. Do no application work outside a handler: the harness does not detect a detached promise, timer, or child process that runs on after the response. A handler that does not end after cancellation can make the harness end the process, which interrupts other requests. WebSockets are not supported: an upgrade request does not reach your server as an upgrade, so no WebSocket connection opens.
Keep the platform credential secret. The platform injects it as TURNZERO_CLOUD_TOKEN, one credential per environment, bound to the environment it was minted for. The proxy's authentication and the harness's own log writes use it. Do not put it in source code or print it in logs.
Read the harness's records with read_logs and the harness, egress, router, and container sources. Read logs and counters states what each source contains, which environment read_logs reads, and how to filter the records by declared and undeclared destinations.
A request past the router's deadline receives 504 window_ended, or its streaming response is cut. A client address past the router's per-address limit receives 429 rate_capped, and its request never reaches the process. Egress firewall and request limits states the deadline and the bound.