Tuwunel for NixOS
Tuwunel can be acquired by Nix from various places:
- The
flake.nixat the root of the repo - The
default.nixat the root of the repo - From Tuwunel’s binary cache
A community maintained NixOS package is available at tuwunel
Binary cache
Tuwunel publishes prebuilt store paths, so building from the flake does not have to compile RocksDB and the Rust toolchain locally. The cache is public and reading from it needs no account.
| Substituter | Public key | |
|---|---|---|
| Self-hosted | https://cache.tuwunel.chat | cache.tuwunel.chat-1:ZafUaXiRMozDa9N2SWim6EdzH0EEjWjwfvlTxXvcjLA= |
| Cachix | https://tuwunel.cachix.org | tuwunel.cachix.org-1:VRecUeDcaPxtYDA6bnMF3snPM7VYX8K605z4uuG2nWc= |
Both are live and either works on its own. Prefer cache.tuwunel.chat: it
stores the whole closure, stock nixpkgs paths included, so a build can be
satisfied from it without reaching cache.nixos.org at all. The Cachix cache
holds only Tuwunel’s own binaries and forked dependencies.
On NixOS, add them to nix.settings:
{
nix.settings = {
extra-substituters = [
"https://cache.tuwunel.chat"
"https://tuwunel.cachix.org"
];
extra-trusted-public-keys = [
"cache.tuwunel.chat-1:ZafUaXiRMozDa9N2SWim6EdzH0EEjWjwfvlTxXvcjLA="
"tuwunel.cachix.org-1:VRecUeDcaPxtYDA6bnMF3snPM7VYX8K605z4uuG2nWc="
];
};
}
Everywhere else, put the same two settings in /etc/nix/nix.conf and restart
the daemon:
extra-substituters = https://cache.tuwunel.chat https://tuwunel.cachix.org
extra-trusted-public-keys = cache.tuwunel.chat-1:ZafUaXiRMozDa9N2SWim6EdzH0EEjWjwfvlTxXvcjLA= tuwunel.cachix.org-1:VRecUeDcaPxtYDA6bnMF3snPM7VYX8K605z4uuG2nWc=
sudo systemctl restart nix-daemon
Nix falls through to another substituter or a source build when a cache returns HTTP 404 for a missing path. A reachable cache that returns HTTP 5xx is different: Nix treats that as a transfer error, retries it, and can fail the build. The Tuwunel cache therefore converts reverse-proxy backend failures to 404 for narinfo and NAR reads while continuing to serve cached responses.
With the cachix client installed, cachix use tuwunel writes the Cachix half
of that configuration for you.
The repository flake also declares the cache in its nixConfig, but do not
rely on that alone. Nix treats a flake’s configuration as untrusted: an
interactive build asks whether to accept it, and a non-interactive one skips
it with ignoring untrusted flake configuration setting, so an unattended
deployment that configured nothing else would quietly build everything from
source. Set the two values as shown above, or pass --accept-flake-config.
cache.tuwunel.chat is self-hosted on Tuwunel’s own infrastructure, behind a
caching proxy that keeps serving already-fetched paths even if the cache
application itself is down.
NixOS module
A NixOS module ships with Nixpkgs as services.matrix-tuwunel,
available in 25.11 and unstable. It generates tuwunel.toml from a settings attrset
and runs the server under a hardened systemd unit (DynamicUser, ProtectSystem=strict,
strict SystemCallFilter).
Minimal configuration:
{
services.matrix-tuwunel = {
enable = true;
settings.global = {
server_name = "example.com";
address = [ "127.0.0.1" "::1" ];
port = [ 6167 ];
allow_federation = true;
};
};
}
Notable defaults:
- User and group
tuwunel(override viaservices.matrix-tuwunel.user/.group). - Database under
/var/lib/tuwunel/(override viaservices.matrix-tuwunel.stateDirectory). - Listens on
127.0.0.1and::1port6167.
Anything placed under settings.global is written verbatim into the [global] table of
tuwunel.toml, so the configuration reference applies directly.
UNIX sockets
The module exposes unix_socket_path and unix_socket_perms directly:
services.matrix-tuwunel.settings.global = {
unix_socket_path = "/run/tuwunel/tuwunel.sock";
unix_socket_perms = 660;
};
Leave address unset (or null) when using a socket. The systemd unit already permits
AF_UNIX, so no further overrides are needed.
Migrating from services.matrix-conduit
services.matrix-tuwunel replaces the legacy services.matrix-conduit
module that older guides reference. Most settings carry over because both render the
same TOML schema. When migrating:
- Disable
services.matrix-conduitand enableservices.matrix-tuwunel. - Confirm the database is RocksDB. Tuwunel dropped SQLite in favor of RocksDB; if you ran a SQLite Conduit, migrate first with conduit_toolbox.
- Either set
services.matrix-tuwunel.stateDirectoryto match your existingdatabase_path, or move the database under/var/lib/tuwunel/.