# How to Configure Custom TLS Settings in Iroh: A Complete Guide to rustls Integration

> Learn to configure custom TLS settings in Iroh using rustls. Gain precise control over cryptographic providers, cipher suites, and root certificate verification with this complete guide.

- Repository: [number zero/iroh](https://github.com/n0-computer/iroh)
- Tags: how-to-guide
- Published: 2026-06-18

---

**Iroh leverages the rustls library for all TLS operations and exposes custom configuration through `ClientBuilder::tls_client_config` and the `CaTlsConfig` helper, enabling precise control over cryptographic providers, cipher suites, and root certificate verification.**

Iroh, the open-source distributed networking toolkit developed by n0-computer, delegates Transport Layer Security (TLS) to the memory-safe rustls crate, providing Rust-native implementations of TLS 1.2 and 1.3. When you need to configure custom TLS settings in Iroh—whether to comply with strict security policies, integrate with private PKI infrastructure, or optimize connection performance—you interact directly with `rustls::ClientConfig` objects passed through component builders. This guide examines the specific implementation paths in the `n0-computer/iroh` repository that enable fine-grained TLS customization.

## Understanding Iroh's TLS Architecture

Iroh's TLS implementation follows a layered architecture where high-level builders accept raw `rustls::ClientConfig` instances and propagate them to underlying connection code. According to the source code in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs), the `CaTlsConfig` struct serves as a wrapper for root-certificate verification logic, converting to a standard `rustls::ClientConfig` via its `client_config` method.

The architecture separates concerns between:
- **Cryptographic provider selection** (Ring vs. AWS-LC-RS)
- **Certificate verification** (root store management via `CaTlsConfig`)
- **Connection establishment** (TLS handshake execution in `MaybeTlsStreamBuilder`)

In [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs), the `MaybeTlsStreamBuilder::connect` method clones the stored `ClientConfig` and creates a `tokio_rustls::TlsConnector` to perform the handshake, ensuring your custom settings apply to every encrypted relay connection.

## Creating a Custom rustls::ClientConfig

To begin configuring custom TLS settings, you instantiate a `rustls::ClientConfig` with your chosen cryptographic provider and security parameters. The default configuration uses the Ring provider, though you can substitute AWS-LC-RS for FIPS compliance or specific hardware acceleration.

The configuration process involves selecting a `CryptoProvider`, defining allowed TLS versions and cipher suites, and configuring certificate verification behavior. In [`iroh-relay/src/client.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client.rs), the `ClientBuilder::tls_client_config` method stores your custom configuration, which later flows into the `MaybeTlsStreamBuilder` when establishing connections.

## Managing Root Certificates with CaTlsConfig

For scenarios requiring custom root certificate stores—such as connecting to private relay servers or adding enterprise CA certificates—Iroh provides the `CaTlsConfig` utility defined in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs). This helper abstracts root store management while producing standard `rustls::ClientConfig` instances through its conversion method.

The `CaTlsConfig` offers several factory methods:
- **`CaTlsConfig::custom_roots`** – Supplies additional certificates to trust alongside the system store
- **`CaTlsConfig::insecure_skip_verify`** – Disables verification for testing (available in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs))
- **`CaTlsConfig::from_der`** – Loads certificates from DER-encoded bytes

When you invoke `ca_cfg.client_config(provider)`, the method returns a fully configured `rustls::ClientConfig` that incorporates your root certificate specifications with the cryptographic provider's implemented algorithms.

## Applying Custom TLS to Iroh Components

Once you have constructed a `rustls::ClientConfig` or `CaTlsConfig`, you apply it to specific Iroh components through their respective builder methods.

### Relay Client Configuration

For the relay client implemented in [`iroh-relay/src/client.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client.rs), use `ClientBuilder::tls_client_config` to inject your custom configuration:

```rust
use iroh_relay::client::ClientBuilder;
use rustls::ClientConfig;

let client = ClientBuilder::new(
        "https://relay.example.com".parse::<iroh_relay::RelayUrl>().unwrap(),
        secret_key,
        dns_resolver,
    )
    .tls_client_config(client_cfg)
    .build()
    .await?;

```

### High-Level Endpoint Configuration

In the top-level `iroh` crate, `EndpointBuilder::tls_client_config` accepts your custom configuration. The [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs) module re-exports `CaTlsConfig` for convenient access, while [`iroh/src/client.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/client.rs) demonstrates how the high-level client forwards TLS settings to the underlying relay implementation.

For DNS-over-HTTPS resolution, the `DnsBuilder::tls_client_config` method similarly accepts custom configurations, ensuring consistent TLS behavior across all external network calls.

## Complete Configuration Examples

### Custom Cipher Suites and TLS Versions

This example demonstrates restricting the relay client to TLS 1.3 with specific cipher suites using the Ring provider:

```rust
use std::sync::Arc;
use iroh_relay::client::ClientBuilder;
use rustls::{
    client::ClientConfig,
    crypto::CryptoProvider,
    version::TLS13,
};

let provider: Arc<CryptoProvider> = iroh_relay::tls::default_provider();

let rustls_cfg = ClientConfig::builder_with_provider(provider.clone())
    .with_safe_defaults()
    .with_custom_certificate_verifier(Arc::new(
        rustls::client::WebPkiServerVerifier::builder_with_provider(
            rustls::RootCertStore::empty(),
            provider.clone(),
        )
        .with_allowed_versions(&[TLS13])
        .with_cipher_suites(&[rustls::cipher_suite::TLS13_AES_256_GCM_SHA384])
        .build()
        .unwrap(),
    ))
    .with_no_client_auth();

let client = ClientBuilder::new(
        "https://my.relay.example".parse::<iroh_relay::RelayUrl>().unwrap(),
        SecretKey::generate(),
        DnsResolver::new(),
    )
    .tls_client_config(rustls_cfg)
    .build()
    .await?;

```

### Loading Custom Root Certificates

To connect to a relay using a private CA, load the root certificate and wrap it in `CaTlsConfig` as implemented in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs):

```rust
use iroh_relay::tls::CaTlsConfig;
use rustls::RootCertStore;
use rustls::internal::pemfile::certs;
use std::fs::File;

let mut file = File::open("my_root.pem").unwrap();
let mut root_store = RootCertStore::empty();
root_store.add_parsable_certificates(
    certs(&mut file).unwrap().into_iter().map(|c| c.into()),
);

let ca_cfg = CaTlsConfig::custom_roots(root_store.roots.clone());
let client_cfg = ca_cfg.client_config(iroh_relay::tls::default_provider())?;

```

### Endpoint with Insecure Verification (Testing Only)

For local development or testing against self-signed certificates, use `CaTlsConfig::insecure_skip_verify` exposed in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs):

```rust
use iroh::{Endpoint, tls::CaTlsConfig};

let endpoint = Endpoint::builder()
    .tls_client_config(client_cfg)
    .ca_tls_config(CaTlsConfig::insecure_skip_verify())
    .build()
    .await?;

```

## Summary

- **Iroh uses rustls** for all TLS operations, exposing configuration through standard `rustls::ClientConfig` objects passed to builder methods.
- **The `CaTlsConfig` helper** in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs) simplifies root certificate management and converts to `rustls::ClientConfig` via the `client_config` method.
- **Component builders** including `ClientBuilder::tls_client_config` and `EndpointBuilder::tls_client_config` accept custom TLS configurations that propagate to `MaybeTlsStreamBuilder::connect` in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs).
- **Cryptographic flexibility** allows selection between Ring and AWS-LC-RS providers, with control over cipher suites and TLS versions through the `CryptoProvider` API.
- **Security customization** ranges from adding enterprise root certificates to complete verification bypass for testing scenarios using `CaTlsConfig::insecure_skip_verify`.

## Frequently Asked Questions

### What cryptographic providers can I use when configuring TLS in Iroh?

Iroh supports both the **Ring** and **AWS-LC-RS** cryptographic providers for rustls. The Ring provider is used by default and provides excellent performance for most use cases. The AWS-LC-RS provider offers FIPS 140-2 compliance for environments requiring validated cryptography. You pass your chosen provider to `ClientConfig::builder_with_provider` and to `CaTlsConfig::client_config` when converting the helper to a client configuration.

### How do I disable TLS certificate verification for local testing?

Use `CaTlsConfig::insecure_skip_verify()` when building your endpoint or client, as re-exported in [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs). This creates a configuration that accepts any server certificate, which is useful for testing against self-signed certificates or local development servers. Never use this in production environments, as it completely disables protection against man-in-the-middle attacks.

### Can I configure different TLS settings for the relay client and the main endpoint?

Yes. Each component builder maintains its own TLS configuration. You can create distinct `rustls::ClientConfig` instances—one for the relay client via `ClientBuilder::tls_client_config` in [`iroh-relay/src/client.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client.rs) and another for the endpoint via `EndpointBuilder::tls_client_config`. This allows you to enforce stricter cipher requirements for relay connections while using different parameters for direct peer connections.

### Where does Iroh apply the custom TLS configuration during connection establishment?

According to [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs), the `MaybeTlsStreamBuilder::connect` method clones the stored `ClientConfig` and creates a `tokio_rustls::TlsConnector` to execute the TLS handshake. This occurs when the relay client establishes WebSocket connections or when the endpoint negotiates secure channels, ensuring your custom certificate verification and cipher preferences are active for all encrypted traffic.