Tuwunel Documentation

repository·main·Indexed 25 days ago

https://github.com/matrix-construct/tuwunel

A high-performance, scalable, and enterprise-ready Matrix homeserver written in Rust. As the official successor to conduwuit, Tuwunel provides a low-cost alternative to Synapse with support for automatic database adoption from Conduit-lineage homeservers. Documentation covers installation across Debian, Ubuntu, Red Hat-based distributions, Arch Linux, NixOS, and Alpine, as well as Docker deployment, systemd service management, SELinux configuration, and TLS setup via Caddy.

Tokens
75.1K
Snippets
123
Records
330
Agent score
81%

What's inside Tuwunel

  1. Overview of Tuwunel authentication systems

    main

    Tuwunel provides fine-grained control over user registration and authentication through several distinct mechanisms:

    • Legacy Authentication: Includes password login, token-based invitations, guest access, and registration controls.
    • OIDC Authorization Server: A built-in OAuth 2.0 / OpenID Connect server designed for next-generation Matrix clients. It manages refresh tokens, device grants, and account management by fronting identity providers.
    • Identity Providers: Supports Single Sign-On (SSO) via upstream OAuth/OIDC providers like GitHub, Google, and Keycloak. These providers also serve as the human authentication step for the OIDC server.
    • LDAP Delegation: Allows delegating user management and password authentication to an external LDAP directory.
    • Enterprise JWT: Provides an operator-controlled signing key capable of minting tokens to authenticate as any user.
  2. Overview of Synapse Admin API support in Tuwunel

    main

    Tuwunel implements the Synapse administration API under the /_synapse/admin path. This compatibility allows existing Matrix administration tools (like synapse-admin, ketesa, Draupnir, and Meowlnir) to function with Tuwunel.

    Important Notes:

    • Authentication: Most endpoints require an administrator access token.
    • Unimplemented Endpoints: If an endpoint is not supported, Tuwunel returns a 404 M_UNRECOGNIZED error.
    • MAS (Matrix Authentication Service): Certain endpoints related to registration and password resets are not served when MAS is active.
  3. Important deployment requirements

    main

    When deploying Tuwunel, keep the following technical requirements in mind:

    • Port 8448: While clients connect via port 443, other Matrix homeservers use port 8448 for federation. Both ports must be reachable.
    • Minimal Container Images: Docker and Podman images contain only the binary, tini, and CA certificates. They do not include a shell. To inspect a running container, you must exec into it using the binary directly.
    • Rootless Podman: If running rootless Podman, you must enable loginctl enable-linger to prevent containers from stopping when the user logs out.
    • NixOS: Using the community services.matrix-conduit module requires manual workarounds for UNIX socket support and potential conflicts with jemalloc when using hardened profiles.
  4. Understand the Tuwunel Delivery Pipeline

    main

    The Tuwunel delivery pipeline is organized into four sequential, gated phases. A failure in any phase prevents subsequent phases from executing, ensuring that only fully validated deliverables reach users.

    PhaseAccessDescription
    Linteverything (unless masked)format, spelling, security audit, dead links, clippy
    Testeverything (unless masked)unit, integration, smoke, Complement, Matrix SDK
    Packagemain, test, releases, PRs (limited)binaries, containers, distro packages, docs
    Publishmain and tagged releases onlycontainer registries, GitHub Pages
  5. Avoid reload-safety hazards in Tuwunel

    main

    Because hot reloading involves unloading and reloading code in memory, you must follow specific patterns to avoid memory corruption or crashing the server.

    1. Manage Async Tasks and Lifetimes

    Code is memory. You must ensure you do not attempt to execute code that has been unloaded.

    • Never spawn a task without receiving and storing its JoinHandle.
    • Always wait on join handles before leaving a scope or in another cleanup function called by an owning scope.

    2. Use the correct Runtime Handle

    Do not use tokio::spawn directly. Due to internal implementation details and potential bugs in how tokio handles thread-local variables in unsafe {} blocks, you must use the Tuwunel Handle defined in core/server.rs. This handle is typically accessible via the services() method or other state objects in the codebase.

  6. Select the appropriate image tag for your environment

    main

    Tuwunel provides three rolling tags that balance update frequency against stability:

    • :latest: The most recent tagged release (updated ~monthly). Recommended for Production.
    • :preview: Selected higher-confidence updates (updated ~weekly). Use this if you need fixes between official releases but want more stability than the development branch.
    • :main: Every reviewed merge to the main branch (updated ~daily). Use this if you want to track development and accept the risk of unknown changes.
  7. How JWT account registration works

    main

    When a user authenticates via JWT for the first time:

    • If register_user = true: Tuwunel creates a new account with the origin "jwt" and a placeholder password. The user can only re-authenticate using a valid JWT; the local password field is never used.
    • If register_user = false: The login request fails with M_NOT_FOUND and no account is created.

    Note: JWT only handles authentication. It does not synchronize admin status, group membership, or display names. For ongoing identity attribute synchronization, use LDAP or OIDC.

  8. Understand Tuwunel's dynamic library architecture

    main

    Tuwunel's hot reloading relies on a modular architecture where the application is structured as a Directed Acyclic Graph (DAG) of crates.

    Core Principles

    • Global Bindings: The system uses RTLD_GLOBAL to allow crates to share symbols. This requires that the application is a DAG.
    • Dependency Rule: No crate is allowed to call a function or use a variable from a crate below it.
    • Unloading Order: Because symbols are bound between crates, crates cannot be unloaded until their calling crates are first unloaded. The reloading process starts from the crate that has no callers (the top of the graph).
    • The Executable Exception: To prevent the main executable from being tied to all modules (which would prevent unloading), the link between the main executable and the first crate uses an RTLD_LOCAL binding. This ensures the executable remains independent of the dynamic modules.
  9. How Tuwunel storage providers work

    main

    Tuwunel uses a provider layer to abstract media storage, supporting both the local filesystem and S3-compatible object storage.

    Key concepts:

    • media_storage_providers: A list of all active providers. Tuwunel reads media from all providers in this list. If a file is not found in the first provider, Tuwunel falls back to the next.
    • store_media_on_providers: A list of providers where new uploads are written. If this list is empty, all providers in media_storage_providers receive new uploads.
    • Implicit Provider: By default, Tuwunel uses an implicit provider named "media" which points to a media/ subdirectory inside your database_path on the local filesystem.
    # Default behavior (implicit local storage)
    media_storage_providers = ["media"]
    store_media_on_providers = []
  10. Manage Tuwunel Versions and Container Tags

    main

    When using Docker, it is strongly advised to track the :latest tag for automatic updates.

    Tagging Strategy:

    • :latest: Stable release (recommended for production).
    • :preview: Updates with higher confidence between major releases.
    • :main: Most frequent updates (daily), reviewed but carries higher risk.
  11. How the OIDC Authorization Code flow works

    main

    For interactive clients (those with a browser), the authorization-code grant follows these steps:

    1. Discovery: The client finds the issuer via /_matrix/client/v1/auth_issuer and fetches metadata to locate endpoints.
    2. Authorization Request: The client sends the user to GET /_tuwunel/oidc/authorize using a PKCE code_challenge.
    3. Identity Provider Redirect: Tuwunel redirects the browser to the configured upstream identity provider's SSO flow (/_matrix/client/v3/login/sso/redirect/<provider>). A specific provider can be requested via the idp_id query parameter.
    4. Authentication: The user authenticates with the provider. The provider redirects back to Tuwunel, which completes the exchange at GET /_tuwunel/oidc/_complete.
    5. Token Exchange: Tuwunel returns an authorization code, which the client then exchanges at POST /_tuwunel/oidc/token for an access token, a refresh token, and an ID token (if requested).