TLS
Fairyfly ships its own TLS stack (BearSSL) — no OpenSSL dependency, no system libraries. The same http.serve code serves plain HTTP and HTTPS. TLS is enabled per server, and WebSocket (wss://) rides on it for free. For HTTP/2 over the same port, see the HTTP/2 guide.
TLS here means two things: encrypting your server so browsers see https://, and trusting other servers when you call fetch or new WebSocket against https:// URLs.
Enable TLS from JavaScript
Create tls-server.js:
Run it:
What happens:
tls.certandtls.keyaccept a file path or inline PEM text. Anything starting with-----BEGINis treated as PEM content, otherwise as a path.- Cert files are capped at 512KB, key files at 256KB. Larger files fail to load.
- A bad cert or key throws a
TypeErrorand the server never starts half-configured — you see the error, never a silent plain-HTTP fallback.
Enable TLS from the CLI
If your entrypoint is ff.json, skip the tls object and pass paths at startup:
Environment fallback:
Rules:
--certand--keymust be given together. One without the other prints an error and exits.- When both CLI flags and the JS
tlsobject are set, the JS object wins at listener start. - A binary built with
-Dbearssl=falsehas no TLS: starting with cert/key printsbuilt without TLSand exits.
WebSocket over TLS
Nothing extra — same port, wss:// scheme, and the upgrade happens automatically exactly like plain WS (no { status: 101 } branch in the handler):
Create wss-client.js:
Binary frames arrive as Uint8Array; send them with socket.sendBinary.
Trusting your own certificate
Browsers and fetch reject self-signed certs by default. Three cases:
1. Same process serves and fetches. Starting with --cert cert.pem (or FF_CERT) auto-trusts that cert for the process's own fetch and WebSocket clients — no extra flags:
2. Separate client script. Pass the cert as a CA:
3. External tools. curl -k https://localhost:8443/ skips verification (-k = local testing only). For Node: NODE_EXTRA_CA_CERTS=cert.pem node client.mjs.
Generate a dev certificate
SubjectAltNames matter — the client verifies the hostname, so mint for localhost (and the IP when you dial it numerically):
This creates cert.pem and key.pem in the current directory. Then:
Limits you will hit
- One listener is TLS-or-plain per
tlsblock. No client-certificate auth. - Cert ≤ 512KB, key ≤ 256KB.
- RSA or EC keys; RSA is the well-trodden path.
- Outbound
fetchstays HTTP/1.1 even against HTTPS hosts.
Try it
- Generate a cert with the openssl command above.
- Start
tls-server.js, thencurl -k https://localhost:8443/. - Connect
wss-client.jsand confirm echo works over TLS. - Start a second script with
--ca cert.pemand fetch your own server without-k.
