# How to Configure TLS Settings for Iroh Connections: A Complete Guide

> Learn how to configure TLS settings for Iroh connections using rustls. Customize cipher suites, root certificates, and crypto providers with this complete guide.

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

---

**Iroh uses rustls as its TLS implementation and exposes configuration through the `CaTlsConfig` wrapper and `ClientBuilder::tls_client_config` method, allowing you to customize cipher suites, root certificates, and cryptographic providers by passing a custom `rustls::ClientConfig` to network components.**

Iroh is a Rust-based toolkit for building distributed systems that relies on secure connections for its relay and peer-to-peer networking components. Understanding how to configure TLS settings for Iroh connections enables you to customize cryptographic providers, restrict cipher suites, and manage certificate verification to meet specific security requirements. According to the n0-computer/iroh source code, all TLS configuration flows through a consistent pattern of creating a `rustls::ClientConfig` and passing it to component-specific builders.

## Understanding Iroh's TLS Architecture

Iroh delegates all TLS operations to **rustls**, a modern Rust TLS library. The codebase provides a helper structure called `CaTlsConfig` defined in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs) that wraps `rustls::ClientConfig` and manages root certificate verification.

The configuration flow follows three steps:

1. Create a `rustls::ClientConfig` with your chosen `CryptoProvider` (Ring or AWS-LC-RS) and security parameters
2. Pass the configuration to a component builder using methods like `ClientBuilder::tls_client_config` or `EndpointBuilder::tls_client_config`
3. The configuration is consumed during connection establishment by `MaybeTlsStreamBuilder::connect` in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs)

## Creating a Custom TLS Configuration

To customize TLS settings, you first construct a `rustls::ClientConfig` with your desired cryptographic provider and cipher suites. The default provider uses Ring, but you can substitute AWS-LC-RS if preferred.

### Selecting Crypto Providers and Cipher Suites

The configuration starts with selecting a `CryptoProvider` and building the client config with specific security parameters:

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

// Choose a crypto provider – the default Ring provider is usually fine.
let provider: Arc<CryptoProvider> = iroh_relay::tls::default_provider();

// Start from the default configuration and tweak it.
let mut rustls_cfg = ClientConfig::builder_with_provider(provider.clone())
    .with_safe_defaults()
    .with_custom_certificate_verifier(Arc::new(
        // Only allow TLS 1.3 and a specific cipher suite:
        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(); // no client certificates

// Wrap the config in a CaTlsConfig if you also need custom roots.
let ca_cfg = CaTlsConfig::custom_roots([]).client_config(provider)?;

```

This example demonstrates restricting connections to **TLS 1.3** only and specifying a particular cipher suite, which is critical for environments with strict compliance requirements.

## Configuring Component-Specific TLS

After creating your `ClientConfig`, you apply it to specific Iroh components through their respective builders.

### Relay Client Configuration

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

```rust
use iroh_relay::client::ClientBuilder;
use iroh_relay::client::DnsResolver;

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

```

This method stores the supplied `rustls::ClientConfig` in the builder, which is later used by `MaybeTlsStreamBuilder` when establishing the TLS session.

### High-Level Endpoint Configuration

For the high-level Iroh endpoint, the configuration is exposed through [`iroh/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/tls.rs), which re-exports `CaTlsConfig`:

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

let endpoint = Endpoint::builder()
    .tls_client_config(client_cfg)               // from previous example
    .ca_tls_config(CaTlsConfig::insecure_skip_verify()) // only for tests!
    .build()
    .await?;

```

### DNS-over-HTTPS Client

When using DNS-over-HTTPS (DoH), customize the TLS configuration via `DnsBuilder::tls_client_config`, which uses the same patterns as the relay client.

## Customizing Root Certificate Verification

Iroh provides flexible options for managing root certificate trust through `CaTlsConfig`.

### Adding Custom Root Certificates

To trust specific root certificates beyond the system defaults, load PEM-encoded certificates and build a custom root store:

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

// Load a PEM-encoded root.
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()),
);

// Build a CaTlsConfig that trusts only this root.
let ca_cfg = CaTlsConfig::custom_roots(root_store.roots.clone());

// Convert to a rustls::ClientConfig (uses the default Ring provider).
let client_cfg = ca_cfg.client_config(iroh_relay::tls::default_provider())?;

```

### Disabling Verification for Testing

For development environments, you can disable certificate verification entirely using `CaTlsConfig::insecure_skip_verify()`. **Never use this in production.** This configuration is available at the endpoint level as shown in the high-level endpoint example above.

## How TLS is Applied at Connection Time

When a connection is established, the configuration flows through to `MaybeTlsStreamBuilder::connect` in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs). This method clones the stored `ClientConfig`, creates a `tokio_rustls::TlsConnector`, and performs the actual TLS handshake with the remote relay server.

The high-level client in [`iroh/src/client.rs`](https://github.com/n0-computer/iroh/blob/main/iroh/src/client.rs) coordinates this by retrieving the custom `tls_config` and feeding it to `MaybeTlsStreamBuilder`, ensuring your custom settings apply to all outgoing connections.

## Summary

- **Iroh uses rustls** as its underlying TLS implementation, with configuration centralized in [`iroh-relay/src/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/tls.rs) through the `CaTlsConfig` structure.
- **Create custom configurations** by building a `rustls::ClientConfig` with your chosen `CryptoProvider` (Ring or AWS-LC-RS) and security parameters.
- **Apply settings to components** using `ClientBuilder::tls_client_config` for relay clients or `EndpointBuilder::tls_client_config` for the main Iroh endpoint.
- **Manage root certificates** through `CaTlsConfig::custom_roots()` or disable verification for testing with `CaTlsConfig::insecure_skip_verify()`.
- **Connection establishment** occurs in `MaybeTlsStreamBuilder::connect`, which uses the supplied configuration to create the `tokio_rustls::TlsConnector`.

## Frequently Asked Questions

### Can I use AWS-LC-RS instead of Ring for the cryptographic provider?

Yes. While Ring is the default provider, you can instantiate the AWS-LC-RS provider and pass it to `ClientConfig::builder_with_provider()`. The `CaTlsConfig::client_config` method accepts any `Arc<CryptoProvider>`, allowing you to swap cryptographic backends based on your performance or compliance requirements.

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

Use `CaTlsConfig::insecure_skip_verify()` when building your endpoint or client. This disables all certificate verification and should **only be used in development or test environments**. In production, use `CaTlsConfig::custom_roots()` to specify your trusted certificate authorities.

### Where does the actual TLS handshake occur in the codebase?

The handshake is performed in [`iroh-relay/src/client/tls.rs`](https://github.com/n0-computer/iroh/blob/main/iroh-relay/src/client/tls.rs) within the `MaybeTlsStreamBuilder::connect` method. This function clones the `ClientConfig` you provided, creates a `tokio_rustls::TlsConnector`, and initiates the TLS handshake with the remote server using your custom configuration.

### Can I configure TLS settings for the DNS resolver used by Iroh?

Yes. The DNS-over-HTTPS client supports custom TLS configuration via `DnsBuilder::tls_client_config`, which accepts a `rustls::ClientConfig` just like the relay client builder. This allows you to customize TLS settings for DNS resolution independently of your peer-to-peer connection settings.