Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
174 commits
Select commit Hold shift + click to select a range
05a0448
test(tls): tighten and speed up existing TLS coverage
Jarred-Sumner Oct 5, 2026
9c876dc
tls: ignore setSession() once the handshake has started (#41671)
Jarred-Sumner Oct 6, 2026
9e61151
tls: apply sessionTimeout to TLS 1.3 sessions too (#38145)
Jarred-Sumner Oct 6, 2026
19c771d
tls: report the real getCipher().version and getEphemeralKeyInfo() (#…
Jarred-Sumner Oct 6, 2026
7f8d82c
node: Node's text for four ERR_* codes, throw ERR_TLS_PROTOCOL_VERSIO…
Jarred-Sumner Oct 6, 2026
004fd6c
tls: refuse privateKeyEngine/privateKeyIdentifier instead of ignoring…
Jarred-Sumner Oct 6, 2026
849ccf2
tls: list supported ciphers in getCiphers(), make tls.SecureContext t…
Jarred-Sumner Oct 6, 2026
2edcd63
tls: make tls.rootCertificates non-configurable (#34748)
Jarred-Sumner Oct 6, 2026
fc8806c
tls: print one warning for a NODE_EXTRA_CA_CERTS file that cannot be …
Jarred-Sumner Oct 6, 2026
6b1699c
tls: read a pipe or FIFO in SSL_CERT_FILE once for both CA stores (#4…
Jarred-Sumner Oct 6, 2026
eb26fe7
docs: document SSL_CERT_FILE and SSL_CERT_DIR (#42970)
Jarred-Sumner Oct 6, 2026
7e67ad7
test(tls): tie the bundled roots to certdata.txt
Jarred-Sumner Oct 6, 2026
d48f967
tls: serve every identity from the array form of key/cert (#33534)
Jarred-Sumner Oct 6, 2026
c55e4fe
tls: free a stream TLS engine's SSL after its pass has unwound (#44462)
Jarred-Sumner Oct 6, 2026
177f7af
http2: keep frames whole and sent once over a TLS socket that wraps a…
Jarred-Sumner Oct 6, 2026
16475ca
tls: pause and resume a wrapped Duplex with the TLS socket's reads (#…
Jarred-Sumner Oct 6, 2026
33e5f04
node:https: https.Server always speaks TLS (#41672, #33539)
Jarred-Sumner Oct 6, 2026
186a181
node:https: forward crl, sessionTimeout, ecdhCurve, sigalgs and honor…
Jarred-Sumner Oct 6, 2026
5d2396a
node:http: enforce server.blockList (#38261)
Jarred-Sumner Oct 6, 2026
d130e1f
node:https: name the Agent pool by what every TLS option holds (#42498)
Jarred-Sumner Oct 6, 2026
0311140
node:https: give the request what tls.connect() throws over a proxy t…
Jarred-Sumner Oct 6, 2026
b2406b4
tls: one translation from tls.connect() options to the native tls option
Jarred-Sumner Oct 6, 2026
e4ed4d4
node-fetch: apply the TLS options of the agent (#35609)
Jarred-Sumner Oct 6, 2026
5485364
ws: forward the TLS options of the constructor and of the agent (#313…
Jarred-Sumner Oct 6, 2026
a2d571b
websocket: honor tls.serverName and call tls.checkServerIdentity on t…
Jarred-Sumner Oct 6, 2026
ceed2d0
websocket: close the connection of a wss:// client that is done with …
Jarred-Sumner Oct 6, 2026
5256d08
test(ws): servername, checkServerIdentity and crl reach the native We…
Jarred-Sumner Oct 6, 2026
045220d
node:tls: keep every addContext() entry for the next listen() (#43080)
Jarred-Sumner Oct 6, 2026
f4baf75
node:tls: build the tls.Server SecureContext in setSecureContext() (#…
Jarred-Sumner Oct 6, 2026
c7a2de9
tls: one SNI matcher: ASCII case folding, last registration wins, HTT…
Jarred-Sumner Oct 6, 2026
6c4d2f7
tls: select the certificate by server name for connections accepted b…
Jarred-Sumner Oct 6, 2026
bc40063
Bun.serve: graceful stop() also drains TLS connections parked in the …
Jarred-Sumner Oct 6, 2026
8052c96
tls: pin that HTTP/3 and TCP select the same serverName entry, docume…
Jarred-Sumner Oct 6, 2026
970c461
node:tls: apply addContext() to connections the server wraps itself (…
Jarred-Sumner Oct 6, 2026
00832de
node:tls: keep ALPN across an SNI SecureContext selection (#33253)
Jarred-Sumner Oct 6, 2026
f0e7efd
node:tls: addContext() with a NUL in the name matches nothing (#37013)
Jarred-Sumner Oct 6, 2026
f0dbe41
sql(postgres): send the plaintext startup when sslmode=prefer and the…
Jarred-Sumner Oct 6, 2026
dbffcd7
sql: close a TLS connection without waiting for the peer's close_noti…
Jarred-Sumner Oct 6, 2026
fe93b45
sql: a setting that only asks for TLS never lowers a stated verify-ca…
Jarred-Sumner Oct 6, 2026
d4eaa63
redis, sql: RedisClient sends SNI and honours tls.serverName; Bun.SQL…
Jarred-Sumner Oct 6, 2026
a523703
bindgen: a dictionary refuses an array (#41490)
Jarred-Sumner Oct 6, 2026
d5be1aa
tls: refuse a NUL in keyFile/certFile/caFile/dhParamsFile and pin the…
Jarred-Sumner Oct 6, 2026
ff9fb67
crypto: X509Certificate.ca is false without basicConstraints (#31811)
Jarred-Sumner Oct 6, 2026
c6394de
tls, net: an IPv6 address with a zone id is matched on its address (#…
Jarred-Sumner Oct 6, 2026
5dc09f5
tls: a server asks for a client certificate with requestCert only (#3…
Jarred-Sumner Oct 6, 2026
71fbff5
tls: NODE_TLS_REJECT_UNAUTHORIZED=0 does not weaken a server (#35245)
Jarred-Sumner Oct 6, 2026
04847e2
tls: tls.DEFAULT_CIPHERS applies to every context built without ciphe…
Jarred-Sumner Oct 6, 2026
4d029a5
tls: accept Ed25519 and ECDSA P-521 signatures from a peer (#32235)
Jarred-Sumner Oct 6, 2026
b73dfc9
tls: trust a pinned self-issued certificate whose keyUsage lacks keyC…
Jarred-Sumner Oct 6, 2026
661fa7c
sql, quic: refuse a NUL in the hostname of Bun.SQL and the servername…
Jarred-Sumner Oct 6, 2026
2c64641
process.env: a write to an object that inherits from the shared env m…
Jarred-Sumner Oct 6, 2026
8cfefe2
types: declare crl on Bun.TLSOptions (#38092)
Jarred-Sumner Oct 6, 2026
5d4f209
test(tls): a standalone server-side TLSSocket asks for a client certi…
Jarred-Sumner Oct 6, 2026
778f46a
redis: an IPv6 address with a zone id is not sent as SNI (#42054, #43…
Jarred-Sumner Oct 6, 2026
eec8791
tls: pin a relative keyFile/certFile/caFile/dhParamsFile without reso…
Jarred-Sumner Oct 6, 2026
213719e
node:tls: stop the Server prototype from pinning the last tls.Server …
Jarred-Sumner Oct 6, 2026
870fb23
test(tls): count the server names' SSL_CTXs in a process of its own (…
Jarred-Sumner Oct 6, 2026
cfd715b
test(tls): make "frees the context it replaces" exact and independent…
Jarred-Sumner Oct 6, 2026
b52eda8
node:tls: attach the onConnectEnd 'end' listener once per connect() (…
Jarred-Sumner Oct 6, 2026
699cf56
node:net: emit 'close' when the handle was detached before the deferr…
Jarred-Sumner Oct 6, 2026
ca91b2f
node:tls: call checkServerIdentity with the connect options as `this`…
Jarred-Sumner Oct 6, 2026
54d8417
node:tls: ignore onread when the TLS socket wraps an existing socket …
Jarred-Sumner Oct 6, 2026
9e213fb
node:tls: link a TLSSocket to the socket it wraps when it is made, no…
Jarred-Sumner Oct 6, 2026
10e282d
node:tls: keep the handle attached while a client handshake protocol …
Jarred-Sumner Oct 6, 2026
e853a87
node:tls: refuse connect(port) on a TLSSocket that runs over a caller…
Jarred-Sumner Oct 6, 2026
deadf37
node:http2: destroy the accepted socket with the TLS proxy of an inje…
Jarred-Sumner Oct 6, 2026
009b6e2
node:tls: follow node's `connecting` rule and emit 'connect' on a TLS…
Jarred-Sumner Oct 6, 2026
d3c5e20
node:tls: report a wrapped net.Socket's error on the TLS socket (#43791)
Jarred-Sumner Oct 6, 2026
d4e6fcf
tls: do not attach an SSL to a socket that was not adopted
Jarred-Sumner Oct 6, 2026
4e3a703
node:tls: hand a wrapped socket over whole (#36534)
Jarred-Sumner Oct 6, 2026
a048b97
node:tls: run a server-side TLSSocket's own ALPNCallback, and report …
Jarred-Sumner Oct 6, 2026
bd25bb2
node:tls: honor setServername() called before connect() (#39040)
Jarred-Sumner Oct 6, 2026
01ede97
node:tls: let a pause() or a pauseOnConnect around the handshake neit…
Jarred-Sumner Oct 6, 2026
8491fa8
node:tls: bind the wrapped stream's 'error' listener instead of closi…
Jarred-Sumner Oct 6, 2026
5d40e79
tls: the close of a TLS socket over a Duplex no longer resumes the tr…
Jarred-Sumner Oct 6, 2026
5ac00b8
usockets: resume a paused TLS socket when its graceful close waits fo…
Jarred-Sumner Oct 6, 2026
31ac850
fetch: do not pick sendfile for a Bun.file() body when the environmen…
Jarred-Sumner Oct 6, 2026
9347756
usockets: split the failed-send classification out of us_socket_write…
Jarred-Sumner Oct 6, 2026
9773527
usockets(tls): a write that can never succeed is an error, not backpr…
Jarred-Sumner Oct 6, 2026
16c1ab1
usockets(tls): drop the "no spill progress after the peer's EOF means…
Jarred-Sumner Oct 6, 2026
74ab348
Bun.serve: the idle timeout closes a TLS connection whatever its clie…
Jarred-Sumner Oct 6, 2026
2a0a98a
test(tls): a failing write of the outer socket inside fetch's proxy t…
Jarred-Sumner Oct 6, 2026
990225e
types: Socket.shutdown()'s JSDoc had the two halves reversed (#44192)
Jarred-Sumner Oct 6, 2026
82eae1c
node:tls: a handshake that did not complete is never an established s…
Jarred-Sumner Oct 6, 2026
960d3c2
tls: report why a handshake over a Duplex failed, and send our alert …
Jarred-Sumner Oct 6, 2026
9a1360c
tls: a close_notify that ends the first handshake is a peer that left…
Jarred-Sumner Oct 6, 2026
b288de2
tls: report a renegotiation when it ends, and the first handshake it …
Jarred-Sumner Oct 6, 2026
f341708
tls: report a fatal TLS error on an established session, then close (…
Jarred-Sumner Oct 6, 2026
8568b90
test(tls): every owner's connection closes on a bad record, and nothi…
Jarred-Sumner Oct 6, 2026
18dd88b
node:tls: report an accepted socket that closes before its handshake …
Jarred-Sumner Oct 6, 2026
c7e6f8f
tls: over a Duplex, deliver parked sessions before the data decrypted…
Jarred-Sumner Oct 6, 2026
edc438b
node:tls: a client that refuses the server in its handshake callback …
Jarred-Sumner Oct 6, 2026
726e79f
Bun.connect: terminate() in the handshake callback sends no client ce…
Jarred-Sumner Oct 6, 2026
c263e96
test(node:tls): a TLS 1.2 client whose certificate the server refuses…
Jarred-Sumner Oct 6, 2026
89a997e
node:tls: a failed write on an established session keeps its syscall
Jarred-Sumner Oct 6, 2026
0677185
test(tls): a throwing ALPNCallback over a Duplex sends its alert; a w…
Jarred-Sumner Oct 6, 2026
5888cfc
node:tls: run the built-in name check inside the handshake too (#43946)
Jarred-Sumner Oct 6, 2026
6ba27cd
usockets(tls): the write BIO never refuses a record, so write() count…
Jarred-Sumner Oct 6, 2026
adeb160
usockets(tls): a close that waits for unsent ciphertext ends at a fix…
Jarred-Sumner Oct 6, 2026
8fc60ab
usockets(tls): drop the WANT_WRITE arms the write BIO can no longer p…
Jarred-Sumner Oct 6, 2026
929f169
websocket: call tls.checkServerIdentity once when the server renegoti…
Jarred-Sumner Oct 6, 2026
3679468
test(websocket): move the TLS server identity tests into websocket-cl…
Jarred-Sumner Oct 6, 2026
fcfe22d
tls: a config that took tls.DEFAULT_CIPHERS needs its own context (#4…
Jarred-Sumner Oct 6, 2026
cfc40b2
fetch: follow tls.DEFAULT_CIPHERS without a tls option (#41810)
Jarred-Sumner Oct 6, 2026
3525065
tls: several identities send their intermediates again (#33534)
Jarred-Sumner Oct 6, 2026
2e29ff2
ws, node-fetch: take TLS 1.3 suite names out of ciphers like node:tls
Jarred-Sumner Oct 6, 2026
05f7ebf
ws, node-fetch: apply secureProtocol
Jarred-Sumner Oct 6, 2026
9103073
node:https: keep listening with the options Node takes and Bun ignored
Jarred-Sumner Oct 6, 2026
9a08768
node:https: a server takes TLS 1.3 suite names in ciphers
Jarred-Sumner Oct 6, 2026
961260d
test: fold the new ws, node-fetch and https.Agent TLS tests into the …
Jarred-Sumner Oct 6, 2026
f046bf8
ws, node-fetch: drop an OpenSSL security level from ciphers
Jarred-Sumner Oct 6, 2026
c1a336e
node:net: type the TLS-only _emitTLSError call
Jarred-Sumner Oct 6, 2026
1833947
test(fetch): protocol: http3 is refused once tls.DEFAULT_CIPHERS is a…
Jarred-Sumner Oct 6, 2026
c808ca1
tls: the default client context follows tls.DEFAULT_CIPHERS (#41810)
Jarred-Sumner Oct 6, 2026
7c4d804
usockets(tls): hold the client's final flight whatever the other sock…
Jarred-Sumner Oct 6, 2026
f3d94cf
uws: HttpContext::onHandshake ignores the report of an established se…
Jarred-Sumner Oct 6, 2026
9af7883
usockets: us_socket_close_now, one place for "send what the kernel ta…
Jarred-Sumner Oct 6, 2026
d7b42e1
node:tls: a write over a Duplex completes when the Duplex has complet…
Jarred-Sumner Oct 6, 2026
5643564
node:tls: report what the EOF probe of a wrapped Duplex throws (#42332)
Jarred-Sumner Oct 6, 2026
8c93d50
tls: SSLWrapper queues its ciphertext in one BIO of its own (#44464)
Jarred-Sumner Oct 6, 2026
20698bf
sql: read options.ssl once
Jarred-Sumner Oct 6, 2026
44b34b4
node:tls: a tls.Server has one SSL_CTX, which its listener serves too
Jarred-Sumner Oct 6, 2026
d72f397
node:tls: a read error under the stream-level engine is the TLS socke…
Jarred-Sumner Oct 6, 2026
1adb7fc
ws, node-fetch: a lone pfx sends its intermediates (#42325)
Jarred-Sumner Oct 6, 2026
8d4040f
usockets(tls): say what ssl_batch_spills bounds now that a handshake …
Jarred-Sumner Oct 6, 2026
db75896
sql: read options.tls and options.ssl once each
Jarred-Sumner Oct 6, 2026
7cdcefa
websocket: the TLS inside a proxy tunnel follows tls.DEFAULT_CIPHERS …
Jarred-Sumner Oct 6, 2026
ef999e9
s3: follow tls.DEFAULT_CIPHERS (#41810)
Jarred-Sumner Oct 6, 2026
768e131
fetch: preconnect() dials nothing once tls.DEFAULT_CIPHERS is assigne…
Jarred-Sumner Oct 6, 2026
41429e2
node:tls: destroy the TLS socket ahead of the fd its wrapped socket's…
Jarred-Sumner Oct 6, 2026
2ae839b
node:tls: do not forward a wrapped socket's error to a TLS socket tha…
Jarred-Sumner Oct 6, 2026
81e9acb
Bun.listen, Bun.connect: tls.secureContext alone asks for TLS, and mu…
Jarred-Sumner Oct 6, 2026
621f1e8
node:tls: the listener never keeps the context setSecureContext() rep…
Jarred-Sumner Oct 6, 2026
1b9e48b
node:tls: comments that described a listener built from the raw key a…
Jarred-Sumner Oct 6, 2026
b6425cb
test(tls): drop the in-process WeakRef check of a dropped tls.Server
Jarred-Sumner Oct 6, 2026
44b287e
node:tls: what a wrapped Duplex passes to its write callback only say…
Jarred-Sumner Oct 6, 2026
7b1a1ed
node:tls: say that a write over a Duplex completes a tick later, not …
Jarred-Sumner Oct 6, 2026
e92a938
[autofix.ci] apply automated fixes
autofix-ci[bot] Oct 6, 2026
736afd7
usockets: the TLS read path does not bind NULL to its _Nonnull socket…
Jarred-Sumner Oct 6, 2026
92ebf92
http2, postgres: move the parts that do not use the type parameter ou…
Jarred-Sumner Oct 6, 2026
35bb62e
test(tls): four tests asserted what only the Linux kernel does
Jarred-Sumner Oct 6, 2026
8bb2a01
Bun.listen: the client certificate policy of tls.secureContext holds
Jarred-Sumner Oct 6, 2026
1db91e1
tls: the first record leaves with the held handshake flight beside a …
Jarred-Sumner Oct 6, 2026
711e6c8
test: two tests that depended on timing
Jarred-Sumner Oct 6, 2026
c9df1f0
test(tls): the peer of a failed handshake over SSLWrapper gets the al…
Jarred-Sumner Oct 7, 2026
c9207c8
test(tls): room for the sockets that linger in the Duplex teardown le…
Jarred-Sumner Oct 7, 2026
1ca1ae1
Revert "node:tls: say that a write over a Duplex completes a tick lat…
Jarred-Sumner Oct 7, 2026
d0c5057
Revert "node:tls: what a wrapped Duplex passes to its write callback …
Jarred-Sumner Oct 7, 2026
149d8a8
Revert "node:tls: a write over a Duplex completes when the Duplex has…
Jarred-Sumner Oct 7, 2026
03827c8
node:tls: a socket that a TLS socket wraps is not destroyed over what…
Jarred-Sumner Oct 8, 2026
b6119ad
node:tls: count a falsy key, cert, ca or crl on tls.Server as absent
robobun Oct 7, 2026
abf5515
test: no type errors in the tests this branch adds or changes
Jarred-Sumner Oct 10, 2026
e370cb5
node:tls: selectServerName stops at an exception
Jarred-Sumner Oct 10, 2026
55c2423
node:tls: selectServerName throws when its list of contexts cannot grow
Jarred-Sumner Oct 10, 2026
346274c
test(tls): the connectionListener count test says what became of a mi…
Jarred-Sumner Oct 10, 2026
9f0bc74
usockets: a FIN does not end a socket that waits in the low-priority …
Jarred-Sumner Oct 10, 2026
64e75cd
test: squid is healthy when it listens, not when its process exists
Jarred-Sumner Oct 10, 2026
68de4be
test(http3): the rejection that stop(true) causes is handled from the…
Jarred-Sumner Oct 10, 2026
2fbae9b
test(tls): the close deadline test no longer counts on what the kerne…
Jarred-Sumner Oct 10, 2026
1646526
test: await the assertion that fetch rejects an array for tls
Jarred-Sumner Oct 10, 2026
e85d136
test(tls): the close deadline test checks when the closes came
Jarred-Sumner Oct 10, 2026
94b39de
test(tls): the close deadline test times each close from its own end()
Jarred-Sumner Oct 10, 2026
949c2d9
tls: a send that the kernel rejects costs nothing that the peer sent
Jarred-Sumner Oct 10, 2026
009de1a
node:https: closeAllConnections() does not wait for a client that sto…
Jarred-Sumner Oct 10, 2026
f552265
node:tls: a rejected write is held only while the reads go on, and ho…
Jarred-Sumner Oct 10, 2026
4f41d3f
tls: the retry of a parked write does not come behind the owner's end()
Jarred-Sumner Oct 10, 2026
4f78ad2
test(tls): the end() test does not ask the side that ended for an 'end'
Jarred-Sumner Oct 10, 2026
2f998ea
node:tls: a reader that stopped has one turn to go on before its reje…
Jarred-Sumner Oct 10, 2026
2f75cb6
test(tls): Windows drops what is unread in the kernel at a reset
Jarred-Sumner Oct 10, 2026
c3caf03
node:https: closeAllConnections() in the middle of a request does not…
Jarred-Sumner Oct 10, 2026
0799cb5
tls: the wait of a close for the peer's close_notify has a deadline too
Jarred-Sumner Oct 10, 2026
de95ca8
test(https): a client that exits early fails the closeAllConnections(…
Jarred-Sumner Oct 10, 2026
41e5dab
tls: the deadline of a close counts from the close, whatever the peer…
Jarred-Sumner Oct 10, 2026
6d4db22
test(tls): an upload survives a renegotiation under write backpressure
robobun Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions docs/runtime/environment-variables.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,15 @@ Bun reads these environment variables to configure aspects of its behavior.
| Name | Description |
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `NODE_TLS_REJECT_UNAUTHORIZED` | `NODE_TLS_REJECT_UNAUTHORIZED=0` disables SSL certificate validation. Useful for testing and debugging, but be very hesitant to use it in production. Node.js introduced this variable; Bun keeps the name for compatibility. |
| `SSL_CERT_FILE` | Path to a PEM file of CA certificates that Bun trusts in addition to its bundled root certificates. If unset, Bun reads `/etc/ssl/cert.pem`. If set to an empty string, Bun reads no file. |
| `SSL_CERT_DIR` | Directories of CA certificates that Bun trusts in addition to its bundled root certificates, each file named by its subject hash (`<hash>.0`, as `openssl rehash` creates). Separate directories with `:` (`;` on Windows). If unset, Bun reads `/etc/ssl/certs`. |
| `BUN_CONFIG_VERBOSE_FETCH` | If `BUN_CONFIG_VERBOSE_FETCH=curl`, then fetch requests log the URL, method, request headers and response headers to the console. This also works with `node:http`. `BUN_CONFIG_VERBOSE_FETCH=1` is equivalent to `BUN_CONFIG_VERBOSE_FETCH=curl` except without the `curl` output. |
| `BUN_RUNTIME_TRANSPILER_CACHE_PATH` | The runtime transpiler caches the transpiled output of source files larger than 4 KB, which makes CLIs using Bun load faster. If `BUN_RUNTIME_TRANSPILER_CACHE_PATH` is set, Bun writes the cache to that directory. If it is set to an empty string or the string `"0"`, caching is disabled. If it is unset, Bun writes the cache to the platform-specific cache directory. |
| `TMPDIR` | Bun occasionally requires a directory to store intermediate assets during bundling or other operations. If unset, defaults to the platform-specific temporary directory: `/tmp` on Linux, `/private/tmp` on macOS. |
| `NO_COLOR` | If `NO_COLOR=1`, then ANSI color output is [disabled](https://no-color.org/). |
| `FORCE_COLOR` | If `FORCE_COLOR=1`, then ANSI color output is forced on, even if `NO_COLOR` is set. |
| `BUN_CONFIG_MAX_HTTP_REQUESTS` | Sets the maximum number of concurrent HTTP requests sent by fetch and `bun install`. Defaults to `256`. Lower it if you run into rate limits or connection issues. |
| `BUN_CONFIG_WS_CLOSE_TIMEOUT` | Sets how many seconds a `WebSocket` client waits for the server to close the connection after the closing handshake. Bun then closes it. Defaults to `30`. `0` disables the timeout. |
| `BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD` | If `BUN_CONFIG_NO_CLEAR_TERMINAL_ON_RELOAD=true`, then `bun --watch` does not clear the console on reload |
| `DO_NOT_TRACK` | Disable uploading crash reports to `bun.report` on crash. On macOS & Windows, crash report uploads are enabled by default. Bun sends no other telemetry, though we plan to add some. If `DO_NOT_TRACK=1`, then auto-uploading crash reports and telemetry are both [disabled](https://do-not-track.dev/). |
| `BUN_OPTIONS` | Prepends command-line arguments to any Bun execution. For example, `BUN_OPTIONS="--hot"` makes `bun run dev` behave like `bun --hot run dev`. |
Expand Down
9 changes: 9 additions & 0 deletions docs/runtime/http/server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,9 @@ interface TLSOptions {
/** Server certificate */
cert?: string | Buffer | BunFile | Array<string | Buffer | BunFile>;

/** Certificate revocation lists */
crl?: string | Buffer | BunFile | Array<string | Buffer | BunFile>;

/** Path to DH parameters file */
dhParamsFile?: string;

Expand All @@ -753,6 +756,12 @@ interface TLSOptions {
/** Private key passphrase */
passphrase?: string;

/** Refuse a peer whose certificate does not verify (default: true) */
rejectUnauthorized?: boolean;

/** Ask clients for a certificate (default: false) */
requestCert?: boolean;

/** OpenSSL options flags */
secureOptions?: number;

Expand Down
35 changes: 35 additions & 0 deletions docs/runtime/http/tls.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,39 @@ Bun.serve({
});
```

### Client certificates (mTLS)

A server asks clients for a certificate only when `requestCert` is `true`. `ca` on its own does not: it names the CAs that client certificates are verified against.

```ts
Bun.serve({
tls: {
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
ca: Bun.file("./client-ca.pem"), // CA that issues the client certificates
requestCert: true, // [!code ++]
},
});
```

With `requestCert: true`, the server refuses a client that sends no certificate or one that `ca` does not verify. Set `rejectUnauthorized: false` to accept those clients too. The `NODE_TLS_REJECT_UNAUTHORIZED` environment variable does not change this for a server.

### Certificate revocation lists

Pass `crl` to refuse peer certificates that a CA has revoked. It takes the PEM contents of one or more CRLs, in the same value types as `ca`. On a server it applies to client certificates, so use it with `requestCert`.

```ts
Bun.serve({
tls: {
key: Bun.file("./key.pem"),
cert: Bun.file("./cert.pem"),
ca: Bun.file("./client-ca.pem"),
requestCert: true,
crl: Bun.file("./client-ca.crl.pem"), // [!code ++]
},
});
```

### Diffie-Hellman

To override Diffie-Hellman parameters:
Expand Down Expand Up @@ -99,3 +132,5 @@ Bun.serve({
],
});
```

If two entries share a `serverName`, the later entry replaces the earlier one. This matches `tls.Server#addContext()`. A trailing dot is ignored, so `my-server1.com.` and `my-server1.com` name the same host. Names are compared case-insensitively, and a `*` stands for exactly one label on every transport: `*.my-server1.com` matches `a.my-server1.com` but not `a.b.my-server1.com`.
1 change: 1 addition & 0 deletions docs/runtime/redis.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ const client = new RedisClient("redis://localhost:6379", {
// ca: "path/to/ca.pem",
// cert: "path/to/cert.pem",
// key: "path/to/key.pem",
// serverName: "redis.example.com", // SNI and the name the certificate must match (default: the URL host)
// }
});
```
Expand Down
6 changes: 5 additions & 1 deletion docs/runtime/sql.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,10 @@ Without a connection URL, Bun checks these individual parameters:
| `PGDATABASE` | - | username | Database name |
| `PGSSLMODE` | - | `disable` | SSL mode (`disable`, `allow`, `prefer`, `require`, `verify-ca`, `verify-full`) |

`PGSSLMODE` also applies next to a connection URL. A URL from a `TLS_*` variable uses at least `require`; `PGSSLMODE=verify-ca` and `PGSSLMODE=verify-full` raise that.

An `sslmode` in the URL takes priority over both, and a mode in the `tls` or `ssl` option takes priority over the URL. `tls: true` and a `tls` object ask for at least `require` and never lower a stricter mode.

### SQLite Environment Variables

You can configure SQLite connections with `DATABASE_URL` when it contains a SQLite-compatible URL:
Expand Down Expand Up @@ -926,7 +930,7 @@ const sql = new SQL({
| SSL Mode | Description |
| ------------- | -------------------------------------------------------------------------------------------------------------------- |
| `disable` | No SSL/TLS used. Connections fail if server requires SSL. Default mode if none specified. |
| `prefer` | Tries SSL first, falls back to non-SSL if SSL fails. |
| `prefer` | Tries SSL first, falls back to non-SSL if the server does not support it. |
| `require` | Requires SSL without certificate verification. Fails if SSL cannot be established. |
| `verify-ca` | Verifies server certificate is signed by trusted CA. Fails if verification fails. |
| `verify-full` | Most secure mode. Verifies certificate and hostname match. Protects against untrusted certificates and MITM attacks. |
Expand Down
70 changes: 58 additions & 12 deletions packages/bun-types/bun.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4767,6 +4767,11 @@ declare module "bun" {
*/
serverName?: string;

/**
* Alias of {@link serverName}, the `node:tls` spelling. `serverName` wins if both are set.
*/
servername?: string;

/**
* Sets `OPENSSL_RELEASE_BUFFERS` to 1.
* Reduces overall performance but saves some memory.
Expand All @@ -4776,12 +4781,16 @@ declare module "bun" {

/**
* If set to `false`, any certificate is accepted.
* Default is `$NODE_TLS_REJECT_UNAUTHORIZED` environment variable, or `true` if it is not set.
*
* For a server, the default is `true`. `$NODE_TLS_REJECT_UNAUTHORIZED` does not change it.
* For a client, the default is the `$NODE_TLS_REJECT_UNAUTHORIZED` environment variable, or `true` if it is not set.
*/
rejectUnauthorized?: boolean;

/**
* If set to `true`, the server requests a client certificate.
* If set to `true`, the server requests a client certificate, and refuses
* a client without a valid one unless `rejectUnauthorized` is `false`.
* This option alone decides it: `ca` does not request a certificate.
*
* Default is `false`.
*/
Expand All @@ -4791,8 +4800,17 @@ declare module "bun" {
* Optionally override the trusted CA certificates. Default is to trust
* the well-known CAs curated by Mozilla. Mozilla's CAs are completely
* replaced when CAs are explicitly specified using this option.
*
* On a server these verify client certificates, which it requests only
* with `requestCert: true`.
*/
ca?: string | BufferSource | BunFile | Array<string | BufferSource | BunFile> | undefined;
/**
* PEM formatted CRLs (Certificate Revocation Lists). A peer certificate
* listed in one of them fails verification: a client certificate when a
* server sets `requestCert`, or the server certificate when connecting.
*/
crl?: string | BufferSource | BunFile | Array<string | BufferSource | BunFile> | undefined;
/**
* Cert chains in PEM format. One cert chain should be provided per
* private key. Each cert chain should consist of the PEM formatted
Expand Down Expand Up @@ -4999,7 +5017,24 @@ declare module "bun" {
* });
* ```
*/
tls?: TLSOptions;
tls?: TLSOptions & {
/**
* The Node.js spelling of `serverName`.
*/
servername?: string;
/**
* Replaces the built-in hostname check, as in `fetch()` and `tls.connect()`.
* Any truthy return value rejects the server, including the Promise of an
* `async` function.
* Through an HTTPS proxy it runs for the target's certificate only.
* With `rejectUnauthorized: false` it still runs when the certificate
* chain verified, but its result is not enforced.
* @param hostname - The name the certificate is verified against: `serverName` if set, else the URL host
* @param cert - The leaf certificate of the server, as in `fetch()`. Unlike in `tls.connect()`, it has no `issuerCertificate`
* @returns An error if the server is unauthorized, otherwise undefined
*/
checkServerIdentity?: NonNullable<import("node:tls").ConnectionOptions["checkServerIdentity"]>;
};
};

type WebSocketOptionsHeaders = {
Expand Down Expand Up @@ -6814,6 +6849,9 @@ declare module "bun" {
* It uses `SO_LINGER` with `l_onoff=1` and `l_linger=0` before calling `close(2)`.
* Consider using {@link close close()} or {@link end end()} for graceful shutdowns.
*
* In the `handshake` callback of a TLS 1.3 client, this refuses the server
* before the client certificate is sent.
*
* @example
* ```ts
* socket.terminate();
Expand All @@ -6822,20 +6860,19 @@ declare module "bun" {
terminate(): void;

/**
* Shuts down the write-half or both halves of the connection.
* This allows the socket to enter a half-closed state where it can still receive data
* but can no longer send data (`halfClose = true`), or close both read and write
* (`halfClose = false`, similar to `end()` but potentially more immediate depending on OS).
* Shuts down one half of the connection.
* With no argument, sends a FIN: the socket can still receive data but can no longer send it.
* With `true`, stops receiving data.
* Calls the `shutdown(2)` syscall internally.
*
* @param halfClose If `true`, only shuts down the write side (allows receiving). If `false` or omitted, shuts down both read and write. Defaults to `false`.
* @param halfClose If `true`, shuts down the read side. If `false` or omitted, shuts down the write side. Defaults to `false`.
* @example
* ```ts
* // Stop sending data, but allow receiving
* socket.shutdown(true);
*
* // Shutdown both reading and writing
* socket.shutdown();
*
* // Stop receiving data
* socket.shutdown(true);
* ```
*/
shutdown(halfClose?: boolean): void;
Expand Down Expand Up @@ -7162,7 +7199,11 @@ declare module "bun" {
getSession(): void;

/**
* Sets the session of the socket.
* Sets the TLS session to offer for resumption.
*
* Only has an effect before the handshake starts: in `open`, before any
* `write()`, on a client socket that also has a `handshake` handler. A later
* call is ignored.
*
* @param session The session to set.
*/
Expand Down Expand Up @@ -7251,6 +7292,11 @@ declare module "bun" {
*/
open?(socket: Socket<Data>): void | Promise<void>;
close?(socket: Socket<Data>, error?: Error): void | Promise<void>;
/**
* Called when a handler throws, and when an established TLS session fails
* (a record that does not decrypt, a fatal alert from the peer). After a
* TLS failure the socket closes, with or without this handler.
*/
error?(socket: Socket<Data>, error: Error): void | Promise<void>;
data?(socket: Socket<Data>, data: BinaryTypeList[DataBinaryType]): void | Promise<void>;
drain?(socket: Socket<Data>): void | Promise<void>;
Expand Down
3 changes: 2 additions & 1 deletion packages/bun-types/redis.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ declare module "bun" {
enableOfflineQueue?: boolean;

/**
* TLS options
* TLS options. `serverName` sets the SNI and the name the certificate is
* verified against, which default to the URL host.
*/
tls?: boolean | Bun.TLSOptions;

Expand Down
6 changes: 1 addition & 5 deletions packages/bun-usockets/src/context.c
Original file line number Diff line number Diff line change
Expand Up @@ -308,9 +308,6 @@ struct us_socket_t *us_socket_adopt(struct us_socket_t *s, struct us_socket_grou
us_internal_socket_group_link_connecting_socket(group, c);
}
}
if (old_group != group && new_s->ssl) {
us_internal_ssl_socket_left_group(new_s);
}
new_s->group = group;
new_s->kind = kind;
new_s->timeout = 255;
Expand Down Expand Up @@ -359,8 +356,7 @@ static void us_internal_init_listen_socket(struct us_listen_socket_t *ls,
ls->accept_kind = kind;
ls->ssl_ctx = ssl_ctx;
if (ssl_ctx) us_internal_ssl_ctx_up_ref(ssl_ctx);
ls->sni = NULL;
ls->on_server_name = NULL;
ls->server_names = NULL;
ls->socket_ext_size = socket_ext_size;
ls->deferred_accept = 0;
ls->accept_paused = (options & LIBUS_SOCKET_OPEN_PAUSED) && !ssl_ctx;
Expand Down
Loading
Loading