Skip to content
GuidesDocs 1.3.x

TLS Configuration ​

Configure TLS for secure gRPC/ConnectRPC communication in Connectum services.

Outcome: the server loads a key/certificate pair and serves TLS. Clients must trust its issuer and verify its hostname. Client-certificate enforcement is a separate mTLS task; exact loading fields live in TLSOptions.

TLS Options ​

The tls option accepts either explicit key/certificate paths or a directory that contains server.key and server.crt. Do not copy this shape into application types; use the generated TLSOptions contract.

Explicit File Paths ​

Provide paths directly to the key and certificate files:

typescript
const server = createServer({
  services: [routes],
  tls: {
    keyPath: './keys/server.key',
    certPath: './keys/server.crt',
  },
});

Paths are resolved relative to the current working directory. Supply keyPath and certPath together. If either is missing, the loader uses dirPath or its default directory for both files.

Directory-Based Configuration ​

Point to a directory containing server.key and server.crt:

typescript
const server = createServer({
  services: [routes],
  tls: {
    dirPath: './keys',
  },
});

The server looks for:

  • <dirPath>/server.key
  • <dirPath>/server.crt

Environment Variable Configuration ​

When keyPath, certPath, and dirPath are not supplied, readTLSCertificates() uses TLS_DIR_PATH or its environment-dependent default. The environment schema does not define TLS_KEY_PATH or TLS_CERT_PATH; pass explicit paths through tls instead. See Environment Configuration for the directory defaults.

TLS Utility Functions ​

readTLSCertificates() ​

Reads TLS key and certificate files:

typescript
import { readTLSCertificates } from '@connectum/core';

// With explicit paths
const { key, cert } = readTLSCertificates({
  keyPath: './keys/server.key',
  certPath: './keys/server.crt',
});

// With directory path
const { key, cert } = readTLSCertificates({
  dirPath: './keys',
});

// With default TLS path (from TLS_DIR_PATH env or convention)
const { key, cert } = readTLSCertificates();

getTLSPath() ​

Returns the TLS directory path based on environment and convention:

typescript
import { getTLSPath } from '@connectum/core';

const path = getTLSPath();
// In production (NODE_ENV=production): current working directory
// In development: ../../../keys relative to cwd
// Overridden by: TLS_DIR_PATH environment variable

Self-Signed Certificates for Development ​

Generate self-signed certificates for local development:

bash
# Create keys directory
mkdir -p keys

# Generate self-signed certificate (valid for 365 days)
openssl req -x509 -newkey rsa:4096 \
  -keyout keys/server.key \
  -out keys/server.crt \
  -days 365 \
  -nodes \
  -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
  -subj "/C=US/ST=Local/L=Local/O=Dev/CN=localhost"

Use in your service:

typescript
import { createServer } from '@connectum/core';
import { Healthcheck, healthcheckManager, ServingStatus } from '@connectum/healthcheck';
import { Reflection } from '@connectum/reflection';

const server = createServer({
  services: [routes],
  port: 5000,
  protocols: [Healthcheck({ httpEnabled: true }), Reflection()],
  tls: {
    dirPath: './keys',
  },
});

server.on('ready', () => healthcheckManager.update(ServingStatus.SERVING));
await server.start();

Development only

Self-signed certificates should only be used in development. For production, use certificates from a trusted Certificate Authority (CA) or a service like Let's Encrypt.

Testing with TLS ​

When testing with grpcurl against a TLS-enabled server using self-signed certificates:

The local server above mounts Reflection for grpcurl list and HTTP health for /healthz. TLS configuration alone does not add either endpoint. The certificate includes a localhost Subject Alternative Name so the verified commands can match the server's hostname.

bash
# Skip certificate verification (development only)
grpcurl -insecure localhost:5000 list

# Or provide the CA certificate
grpcurl -cacert keys/server.crt localhost:5000 list

With curl:

bash
# Skip certificate verification
curl -k https://localhost:5000/healthz

# Or provide the CA certificate
curl --cacert keys/server.crt https://localhost:5000/healthz

Additional HTTP/2 Options ​

Use http2Options for any additional Node.js HTTP/2 secure server options:

typescript
const server = createServer({
  services: [routes],
  port: 5000,
  tls: {
    keyPath: './keys/server.key',
    certPath: './keys/server.crt',
  },
  http2Options: {
    // Minimum TLS version
    minVersion: 'TLSv1.3',
    // Cipher suites
    ciphers: 'TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256',
    // Session timeout
    sessionTimeout: 300,
  },
  // Handshake timeout
  handshakeTimeout: 30000,
});

HTTP/1.1 Support ​

By default, Connectum allows HTTP/1.1 connections (via ALPN negotiation). This is important for ConnectRPC clients that use HTTP/1.1 with JSON:

typescript
const server = createServer({
  services: [routes],
  tls: { dirPath: './keys' },
  allowHTTP1: true,    // default: true
});

To restrict to HTTP/2 only:

typescript
const server = createServer({
  services: [routes],
  tls: { dirPath: './keys' },
  allowHTTP1: false,
});