Files
twenty/packages
Charles Bochet 68c33a37ad feat(server): configurable HTTP keep-alive/headers timeouts to prevent proxy 502s (#22327)
## What & why

Node's HTTP server defaults `keepAliveTimeout` to **5s**, which is
shorter than the idle keep-alive timeout of common reverse proxies /
load balancers (nginx `upstream-keepalive-timeout` and AWS ALB both
default to **60s**). twenty-server currently calls `app.listen()`
without overriding these, so it runs on the 5s default.

When Node closes an idle keep-alive socket that the proxy still has
pooled, the proxy's next request races the close and gets a TCP reset.
nginx logs:

```
recv() failed (104: Connection reset by peer) while reading response header from upstream
```

and returns a **502** to the client. This is payload- and
endpoint-independent: in prod it hit `/graphql`, `/metadata`, `/mcp` and
the app-publish tarball upload alike, at a low continuous rate, on
healthy pods (no restarts, ~64% memory, no CPU throttling).

This is the well-documented "Node behind ALB/nginx 502" race. The fix is
the standard one: make the **server** idle timeout **longer** than the
proxy's, so the proxy is always the side that closes idle connections.

## Changes

- Set `server.keepAliveTimeout` / `server.headersTimeout` in `main.ts`
from config.
- Add two env-overridable config vars (`SERVER_CONFIG` group), with safe
defaults above the typical 60s proxy timeout:
  - `SERVER_KEEP_ALIVE_TIMEOUT_MS` (default **65000**)
  - `SERVER_HEADERS_TIMEOUT_MS` (default **66000**)
- `headersTimeout` is clamped to `keepAliveTimeout + 1s` at startup,
since Node requires `headersTimeout >= keepAliveTimeout` (otherwise it
re-introduces the same race).
- Document both in `.env.example`.

Defaults fix the issue out of the box. The env vars exist because
self-hosters sit behind many proxies (Cloudflare, Traefik, ALB, nginx)
with different idle timeouts — mirroring how Next.js exposes
`--keepAliveTimeout`, and how Fastify (72s) and Kestrel (130s) ship
safe-by-default values.

## Test

- `environment-config.driver.spec.ts` passes.
- `nx typecheck twenty-server` clean for the changed files (only a
pre-existing, unrelated `ical-generator` module-resolution error
remains).


<!-- This is an auto-generated description by cubic. -->
<a
href="https://cubic.dev/pr/twentyhq/twenty/pull/22327?utm_source=github"
target="_blank" rel="noopener noreferrer"
data-no-image-dialog="true"><picture><source
media="(prefers-color-scheme: dark)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source
media="(prefers-color-scheme: light)"
srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img
alt="Review in cubic"
src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a>
<!-- End of auto-generated description by cubic. -->
2026-06-30 11:06:53 +02:00
..