Releases: matrix-construct/tuwunel
Release list
Release v1.9.0
Tuwunel 1.9.0
August 18, 2026
New Features & Enhancements
-
URL previews are richer and more reliable, shipped by @x86pup. The fetch budget rises from 256,000 to 786,432 bytes, each request gets its own
User-Agent, and oEmbed recovers pages that otherwise yield nothing. YouTube links now show their title, channel and thumbnail instead of a bare hostname. Previews remain disabled until at least oneurl_preview_*_allowlistoption is non-empty. Seedocs/media/url-previews.md. -
TLS now uses aws-lc-rs and the platform trust store, courtesy of @dasha-uwu.
ringleaves the build, while SMTP, LDAPS, S3 media, client and federation pools share one crypto provider.allow_invalid_tls_certificatesnow covers LDAP TLS too. Operators running the published standalone binary in a chroot, distroless image or hand-rolledFROM scratchimage must install a CA bundle or setSSL_CERT_FILEbefore upgrading. Unlike 1.8.3, version 1.9.0 will not start without one. The container image and both packages already include a bundle. -
Push rules can now match related events (MSC3664), graciously contributed by @x86pup and raised by @OxiOverlord in (#544). The default
.im.nheko.msc3664.replyrule is added to every account on upgrade regardless of configuration, so nheko users get reply notifications immediately through client-side evaluation. Server-side evaluation for notification counts and pusher delivery requiresmsc3664_related_event_match, which defaults tofalse. The default covers replies;.m.rule.reactionstill suppresses reactions, but custom rules can now matchm.annotation. -
Tuwunel can now rewrite your configuration file. The new command-line regeneration mode and
!admin server regenerate-configrender the example document from the live schema with your values, canonical option names, and unknown keys preserved under# DEPRECATED,# UNKNOWNor# UNDOCUMENTED. Regenerate and diff to review the result. Nothing is applied or reloaded, and the default output is a new file beside the original. A separate mode emits a clean example. Seedocs/configuration/regeneration.md. -
Migrating a conduwuit-lineage database now preserves account state, with appreciation to @x86pup. On the next boot, passwordless accounts no longer appear deactivated, deactivated accounts remain inactive with their old passwords disabled, and email addresses keep their owners.
-
!admin query oauth adopt <provider_id>converts a migrated conduwuit-lineage database's OIDC subject map into durable identity associations in one pass. Without it, each migrated user's next login creates a fresh account with a generated localpart. -
Thanks to @x86pup, FreeBSD and OpenBSD arm64 build without custom
CXXFLAGS, while NetBSD arm64 selects hardware CRC32C at runtime. New guides cover FreeBSD, NetBSD, OpenBSD, RISC-V 64 and 32-bit ARM, each with a verified build and its remaining limits: OpenBSD needs Rust from-current, ARMv6 lacks a working C++ runtime here, and none of the five is covered by CI or ships an artifact. -
Nine cache-capacity options that previously read "This item is undocumented" now explain that their values are entry counts, not byte sizes, graciously contributed by @byteflavour in (#541).
-
Startup now warns when write-ahead log preallocation is enabled on btrfs or ZFS, where it reserves much more disk than the logs use. Raised by @byteflavour in (#535).
rocksdb_allow_fallocatestill defaults totrue; the server warns without changing the engine setting. -
Thanks to @x86pup, each account's push ruleset is capped at 10,000 rules, with each serialized rule capped at 1024 bytes. The limits apply only when the ruleset grows; deletes and disables remain unconditional.
-
force_migrationis now hidden from generated configuration. If it is still set at boot, Tuwunel warns and waits fifteen seconds. Tip of the hat to @x86pup. -
With appreciation to @x86pup, the
.deband.rpminstall checks now resolve their dependencies, and the.debcheck confirms that the programs invoked by the unit exist. -
Credit to @dasha-uwu for reworking registration-token handling and correcting two admin API responses: deleting a config-file token now returns 403 instead of 500, and updating one returns 403 instead of 404.
-
RocksDB advances to 11.8.1 and jemalloc to 5.3.1-2. Eleven low-traffic cache columns now share a pool, while five hot columns retain dedicated pools sized by four new options. Failed write-ahead log flushes and syncs are now logged.
-
Fifteen subsystems moved their multi-row writes into single database transactions, so a related group of rows is either all visible or none.
-
One option added in 1.8.3 went undocumented.
refresh_token_reuse_gracecontrols how long a rotated refresh token remains valid; setting it to 0 treats any reuse as a compromise. The option is not new, and its behavior is unchanged in this release. -
The Matrix Authentication Service guide now distinguishes MAS as a login provider from MAS as a provisioner and lists all twelve provisioning routes.
-
The reverse-proxy guide now correctly explains that the
/_synapse/admin/v1/registerpair uses an HMAC overregistration_shared_secret, not an admin token. Restrict this path to trusted networks. -
Internal Rust API documentation now covers the public surfaces of
tuwunel-coreand the database crate. Complement gains shared-secret registration and an advanced fork pin. Dependencies also advance, includingh20.4.16 for RUSTSEC-2026-0258.
Bug Fixes
-
LDAP logins broken by 1.8.3 work again. That release rejected binds for existing local accounts without LDAP origin, locking out deployments that added LDAP after creating accounts. The gate is reverted (bf1ba04), with only its deactivation check restored (b1eee03). Before upgrading, confirm that
[global.ldap] base_dnandfilter, or thebind_dnsubtree in direct-bind mode when no search runs, resolve only principals allowed to log in as that localpart. Ifadmin_filteris set, a directory entry can now promote an existing local account to admin. Use!admin query users search-ldapon 1.8.3 to check. Sincere apologies to everyone locked out by 1.8.3. -
@dasha-uwu removed the LDAP
name_attributeoption and stopped directory searches bygivenName; an entry must put the Matrix localpart inuid_attributeto allow login. A leftover[global.ldap] name_attributeproduces no boot warning. Regenerate and diff the configuration to reveal it as# DEPRECATED, then remove it manually. -
Push notifications reach gateways again, and failures are now retried. Rejected pushes were counted as delivered and deleted, leaving nothing to retry and permanently sidelining the pushkey. Tuwunel now deletes only accepted events, arms the destination's retry timer, and logs the user, pushkey and error chain on failure. Reported by @xcysy32 in (#543), which remains open pending confirmation. Thanks also to @NekoCWD for separating the proxy case into (#554).
-
Three related push defects are also fixed: rules combining
notifywith historical actions the spec says to ignore are accepted; gateway path stripping now matches only at the URL's end; and pushes during shutdown no longer panic. -
Thanks to @haydonryan for reporting the stale iOS unread badge in (#538) and fixing it in (#539). Read advances refreshed pushers only when the stored count cleared from nonzero, so a badge left nonzero after server counts reached zero never received the explicit zero. Refresh is now unconditional, bounded by each pusher's record of the last count the gateway accepted. Leaving or being banned from an unread room updates it too.
-
A one-time migration repairs two kinds of latent database damage on the first 1.9.0 boot. Releases before 1.8.3 could assign two short ids to one identity, leaving state entries that later removal could not cancel. Every release through 1.8.3 also cached auth chains truncated when an ancestor was missing, a normal backfill gap. Those chains are cleared once, and incomplete walks are now marked. A narrower cross-room case is a genuine regression first shipped in 1.5.0 (944f165).
-
Expect a longer first boot before the listener opens while a clean database performs four full column scans once. The duration is unknown; this was found internally and not reported by a user.
-
A federation disclosure is fixed.
/state,/state_idsand/event_authlooked up an event by id alone, allowing a server that held any event id from a room it had never been in, and could pass the access check on any other room here, to read the first room's state through the second room's URL. Tuwunel now validates the stored event's room, and wrong-room responses are byte-identical to missing-event responses. The issue dates to the server ACL implementation in early 2022. -
timestamp_to_eventpreviously ran only an ACL check, letting any server we federate with obtain a real event id from a room it had not joined and satisfying the disclosure's precondition. It now runs the shared access check. -
Federated events that authorize at their own position but not against current room state are now soft-failed and re-examined on a widening schedule, as the spec requires, instead of being permanently rejected.
-
Remote joins and inbound transactions acquired the room-state and federation mutexes in opposite orders, so joining an active room could freeze it until timeout. The order is now consistent everywhere.
-
The
get_missing_eventswalk now has its own bound, preventing a large response limit from forcing unbounded timeline lookups. Ingest also no longer panics when a signed event'sauth_eventsnames a non-state event we already hold; the caught panic previously returned 500. -
Element X can again preview or open an unjoined room, fixing the retry-dialog loop reported by @utop-top in (#...
Release v1.8.3
Tuwunel 1.8.3
August 5, 2026
New Features & Enhancements
-
QR-code login π² Take a picture of Element Web with Element X: login instantly. (MSC4108). Rendezvous sessions are served over the MSC4388 transport, with bounded in-memory payloads, a session cap and TTL, and their own rate limit. The native OIDC server grows to meet it, serving account login for the device authorization grant and account management with no identity provider configured at all. Raised by @rjwalters in (#525).
-
Video thumbnails. A client that uploads a video without a thumbnail left the server nothing to preview, so
media_video_thumbnail_commandnames a program that extracts one still frame for the image thumbnailer to scale and crop. Inspired by @az4521 in (#397) and implemented by @x86pup, who also caps what the thumbnailer will decode at all withmedia_thumbnail_max_pixels, checked against the image header before any decoder allocates. Requests whose thumbnail would only reproduce the source skip generation entirely, shipped by @lhjt in (#521). -
Native journald logging. Under systemd every line landed in the journal at info priority, so priority filtering in
journalctlwas blind to Tuwunel's warnings and errors. Events are now submitted natively with their severity, target, and source location, under alog_journaldoption that defaults on. Shipped by @byteflavour in (#534) and extended by @x86pup, whose layer streams the console-formatted line into each entry and records tracing fields under anF_prefix, so the journal can be filtered by room or event id. -
systemd socket activation and configuration reload, courtesy of @x86pup. A socket unit ships for activation,
systemctl reloadis wired into the Debian and Red Hat units, the Arch unit refreshes its systemd credentials on reload, and a reload now replays the startup command line, so a server started with-cor-Orebuilds the configuration it actually had. TURN and registration secrets are re-read at each use, so rotating either file no longer needs a restart, and an in-place restart strips the activation variables it can no longer honor. Documented alongside. -
Android builds work, courtesy of @x86pup. The TLS segment is aligned for bionic's loader, SMTP and client TLS verify against bundled webpki roots,
dns_serversbecomes a requirement where the system resolver would need a JVM, and jemalloc and rust-rocksdb are advanced for the libgcc fix. -
LDAP login hardening from @x86pup. Filter and bind-DN metacharacters in the login localpart are escaped, an empty password is rejected before the bind is attempted, accounts that did not originate in LDAP and deactivated accounts are refused, and error handling, timeouts, and password-file IO are tightened.
-
Appservices gain third-party network lookup forwarding: the client
/thirdparty/*endpoints fan out to every registered bridge, carrying protocol metadata verbatim. One-time keys are proxied ahead of the fallback key and appservice device keys are overlaid across client and federation paths (MSC3983, MSC3984). A stalled transaction is retried after a ping, and appservice users are excluded from user-directory search. -
Push badges carry the account-wide unread count, derived across joined rooms at delivery, refreshed on demand, recovered from the queue at startup, and hooked into the read paths that change it. An explicit zero is preserved and only a true opt-out is honored. Reported and diagnosed by @lhjt.
-
State resolution gets a reworked conflicted-subgraph walker, an event-ID sha256 codec with a matching map hasher, mainline positions read from a map, an auth difference hashed by event ID, and short hashes persisted with their state diffs.
-
A Matrix Authentication Service provider guide documents the integration end to end, with a startup warning when
mas_secretis set but no MAS identity provider is configured. -
@dasha-uwu adds a
rooms infocommand,users set-profile-key, and a historical filter onadmin query users iter-users, and removes the abandoned MSC4373 EDU-type preference endpoint from the unstable surface. -
The room directory admin commands accept a room alias and surface it in public-rooms responses ahead of the canonical alias, while publishing an unknown room is refused. Contributed by @x86pup, who also falls URL previews back to
twitter:card tags when theog:values are empty, and newline-delimitslist-backupsoutput. -
Thank you @Xerusion for documenting Traefik root-domain delegation in (#529), and @byteflavour for raising the btrfs WAL fallocate disk-usage footgun in (#535), now documented.
-
Compliance status pages for the Complement test families join the documentation,
admin query raw flushforces a RocksDB memtable flush, room-scoped policy recovery lands as an admin command, database writes go through atomic batches that watcher notifications take as their single source of truth, the runtime can report tokio scheduler latency histograms, and the pool-thread and cache defaults are relaxed. -
Admin
rebuild-relation-indexandrebuild-thread-indexmove from!admin serverto the debug suite; existing invocations need the new path.
Bug Fixes
-
Thank you @lhjt for catching in (#515) that appservice-authenticated client requests inferred presence and activity for the user they act as; the exclusion landed in (#517), with activity context passed through the ping arguments behind it.
-
Reopening the database in-process, which a module reload does, restored the configured backup a second time over everything written since; the restore is now claimed rather than read (cd71003). Separately, the
-Oloop that sets the restore option ran after the check meant to refuse it, so a database could roll back on every start (8e3e339). Both repaired by @x86pup. Sincere apologies to anyone who restored a 1.8.2 backup more than they meant to. -
Public read receipts are monotonic again. A re-posted receipt took a fresh stream position and re-sent the EDU to appservices and over federation; the stored position now gates the write. Reported by @lhjt in (#516), who shipped the first fix in (#518). Private read markers are monotonic too, and the sender's own send is marked read without publishing a receipt for it. The deletion sweep is bounded by the encoded room prefix, which had let it cross into a sibling room whose id merely shared a prefix (7190ab8).
-
Soft-failed events are handled correctly in three places. A withheld membership or power-level change is kept out of current state instead of being applied locally, which is the outcome withholding it exists to prevent (cb03606). The rejection marker used to reject every later attempt, so an event withheld over a policy refusal could never return once that refusal lapsed; it now expires on the shared upgrade backoff and reports to the origin as withheld rather than failed (5b1fc2d). Policy-server refusals expire after 24 hours (6651f9e), and a corrupt state-after room is contained rather than failing the whole
/syncresponse (b565d92). -
Left rooms stay in sync when their cached leave state came from a sibling conduwuit-lineage server, thanks to @x86pup: a lone event object is lifted into a one-element array and anything else read as no cached state. To-device events are handled only for local active or appservice-claimed recipients, so a bridge still receives its own.
-
Non-unix and BSD builds are repaired again, courtesy of @obodnikov: the signals trace import (#526), the in-place restart import (#527), the
cfg(unix)gating that the listener refactor dropped (#528), and thesys/limitsnix imports and page size (#536). Device major and minor conversion is fixed for the BSD builds alongside. -
Native OIDC against Matrix Authentication Service completes. MAS's policy allowlist rejects any scope past
openidandemail, so our unconfigured default ofopenid email profilefailed every authorization. Reported by @utop-top in (#530). -
Short-id allocation is serialized, so a racing or repeated caller observes the winner's rows instead of minting a second short id for one identity; a repeated event id inside a single batch reached this deterministically (5cff8b8). Room search tokens are purged by shortroomid prefix, in one atomic pass (59d7224, 423fbce).
-
Keyed mutex entries are reaped on every release path. A contender that never became a guard, through cancellation or a failed
try_lock, left its entry in the map forever (a2bac8d). -
Federation retry wakes land uniformly across the backoff interval rather than within a fixed three-second jitter, so a cohort of destinations that failed together stops retrying together (2600024). A stale queue wake is rejected, and the resolver's in-flight deduplication is actually awaited, so concurrent lookups for one destination share a single resolution.
-
@okias reported a broken documentation link in (#522), fixed along with the packaging READMEs, which now use absolute rendered-docs links.
-
@x86pup landed several more fixes: the admin console is skipped when standard input is not a terminal, appservice response-body read failures are logged, and a failure to notify an appservice of an invite returns a generic error. @dasha-uwu repaired
get_all_user_mxcs, which left a trailing user-id record unconsumed and panicked debug builds for any user with uploaded media. Elsewhere,admin debugreports per-column errors instead of panicking on an invalid property name, an unchecked float conversion is guarded, a defaulted listen address that fails to bind is skipped rather than taking the whole listener down, and the RocksDB environment is held in one process-global slot so one database's shutdown cannot strand another mid-close.
Release v1.8.2
Tuwunel 1.8.2
July 17, 2026
New Features & Enhancements
-
URL preview media proxying relays link-preview media through the server, now covering
og:videoandog:audioalongside images, so the third party sees Tuwunel rather than the requesting client. Nothing is stored permanently: preview media becomes a lazymxc://reference fetched from source on demand. Aurl_preview_user_agentoption, with a separateurl_preview_media_user_agent, lets previews work for sites that block the default agent. Shipped by @az4521 in (#508), closing their own request for video previews (#394). The preview store is rebuilt on CBOR at the same time, replacing a byte-separated format that could shear fields. -
Distribution packaging expands to RPM with a COPR build pipeline (fixes #251) and a SELinux policy module shipped as a
selinuxsubpackage (#412), plus an apt repository published from CI and Debian packaging that adopts an existing conduwuit or Conduit database in place. Courtesy of @x86pup. -
Online backups can now be restored and verified, joined by a
delete-backupsadmin command, graciously contributed by @x86pup. -
MatrixRTC transport discovery (MSC4143) is served without an access token, so Element Call can find a server's transports; contributed by @basnijholt in (#512).
-
A container
HEALTHCHECK, backed by a new liveness-probe mode, lets orchestrators track readiness, with appreciation to @x86pup. -
A
dns_serversconfig option makes the/etc/resolv.confdependency optional, tip of the hat to @x86pup. -
The Synapse-compatible admin API grows again (#38): server-notice endpoints, user redaction and login-as, federation destination management, and media info, purge, and statistics.
-
Appservice transaction extensions deliver richer data to appservices: device-list changes and one-time-key counts with unused fallback key types (MSC3202), and to-device events (MSC4203). Opened by @dark-collective in (#502) and (#501).
-
Forward-extremity capping and pruning guards against extremity blowup with a scored prune engine that always leaves a survivor and protects the local server's own leaves, a cap applied on the federation receive path, and admin
roomcommands to list and prune a room's extremities. -
Local state derivation for incoming federation events lands in observation mode (#419). The server derives an event's state from local ancestry and calls
/state_idsonly for physically absent events, running alongside the existing fetch and comparing while the fetched result stays authoritative. -
Long admin command output is split across chained reply or thread events, and oversized output is attached as an uploaded file, raised by @grinapo in (#471).
-
Pushers rejected by the push gateway are now removed, backed by push-gateway conformance tests and UnifiedPush documentation, raised by @NinekoTheCat in (#20).
-
Support for Matrix v1.18 and v1.19 is declared in
/versions. -
The
max_fetch_prev_eventsdefault is raised to 1024.
Bug Fixes
-
Federation delivery no longer runs hot against a peer that has come back. The per-server backoff gate consulted only the current time bucket, so it re-authorized attempts at every timeout boundary and never honored the computed earliest retry, and a stale set of reachability rows could keep muting a recovered server. The verdict now derives from a server's full failure history, a returning peer clears the whole streak, and the old rows are cleared once on upgrade (da0c3f6, ec049f6). Sincere apologies to anyone whose outbound federation lagged to a server that had recovered.
-
A proxy or CDN answering a federation request with non-JSON is treated as transient rather than evicting the route outright, and route override eviction is fixed for well-known and SRV-delegated topologies where it was a no-op (b33415d).
-
Tuwunel refuses to initialize over the remnants of a database that lacks a readable manifest, instead of treating them as obsolete files and deleting them on open (fixes #510). Reported and diagnosed by @ItsLiyua, whose detail on the two parallel database directories localized the cause.
-
Native OIDC login completes again: the redirect-completion path returned 405 and produced a redirect Chrome refused (fixes #504, #505). Reported by @isniz and @achetronic.
-
One-time-key counts match Synapse's shape, and an explicit zero count is preserved, so a client whose key pool is drained still sees
signed_curve25519and replenishes instead of starving (007033c, 164b8da). Contributed by @basnijholt in (#511). -
A soft-failed inbound event could compute an empty forward-extremity set and, once persisted, remove every leaf and wedge local sends until a remote event arrived; the previous band is now preserved, and a detached non-create local event on an empty frontier is refused rather than silently forking the room (e0f1034, 1f1dea6).
-
The inbound federation profile query returns 404
M_NOT_FOUNDfor an unknown user instead of an empty 200 (76ea07f). -
The room ephemeral section is always present in
/syncresponses now, thanks to @x86pup (79bb4af). -
An empty
device_idis treated as unspecified and a device id is generated (cfe73cb). -
A systemd unit no longer sticks in the deactivating state after an in-place admin restart, fixed by @x86pup (68e034d).
-
Non-Linux builds get several repairs, courtesy of @obodnikov: resource-usage reporting compiles on non-unix and no longer panics in macOS thread usage (#509), Ctrl+C actually shuts the server down on non-unix targets (#507), and platform-gated admin commands compile on every target (#506).
-
Backup requests that cannot create a backup error instead of reporting success, and backup engine errors propagate rather than being swallowed (f6de800, 9b54209). Credit to @x86pup.
-
@x86pup corrected documented config defaults that disagreed with the code (bb9dfb2), and the
notification_push_pathdescription is set right (e16a3ae).
Release v1.8.1
Tuwunel 1.8.1
July 9, 2026
New Features & Enhancements
-
Synapse-compatible admin API. The Synapse admin surface is served: user, room, media, device and access-token endpoints, the version and event-fetch endpoints, and room deletion, purge, and background-task tracking, backed by an in-memory task tracker and documented on a coverage status page. Opened by @iwalkalone69 in (#38). The user endpoints include listing a user's joined rooms, opened by @ngophuocloi-miracle-aavn in (#494).
-
Threads list (MSC3856). The
/threadsendpoint now orders threads by latest activity, honors aninclude=participatedfilter, serves per-requester views that respect ignored users, guards its inputs upfront, and carries the newest edit on each thread'slatest_event. -
Stable threading (MSC3440). Threading is advertised in
/versions, therelated_by_sendersandrelated_by_rel_typesevent filters are implemented, and nested thread relations are rejected at the send endpoint. -
Sender erasure (MSC4025). An erasure marker lands with admin surfacing, erased senders' events are served as pruned copies, and federation serving of those events is gated accordingly.
-
Native OIDC account registration and login, so Tuwunel can act as its own identity provider. Requested by @temp1403-oss (#479).
-
Configurable default power-level override for newly created rooms, courtesy of @basnijholt in (#496).
-
User suspension is now enforced at the API boundary, contributed by @dasha-uwu.
-
OAuth falls back to Apple
id_tokenclaims when the userinfo endpoint fails, shipped by @basnijholt in (#495). -
The
admin query rawcommands gain aputcommand and hex key decoding, from @dasha-uwu. -
A
SECURITY.mdwith a detached PGP signature, along with issue and pull-request templates and contact links, graciously added by @x86pup. -
Event bundling advances across three proposals: aggregations bundled on search context events (MSC3666),
m.referencechildren bundled as an event-id chunk (MSC3267), and the latestm.replaceedit bundled as a full event (MSC3925). -
Private read receipts now carry a timestamp.
-
Rust is bumped to 1.95.0.
Bug Fixes
-
Sliding sync silently dropped
m.spacerooms, so spaces were absent from the room list where Synapse showed them; the list filters a client omits are now cleared before applying (MSC4186, fixes #503). Reported by @sdenike. -
Rooms made space-visible did not appear in the space overview for new users. The room hierarchy cache is now evicted on any state change (fixes #498). Reported by @Lazalatin.
-
Registration with OIDC and LDAP configured together was broken: LDAP users are now provisioned even when provider registration is disabled (fixes #499). Reported by @balintbarna.
-
Tuwunel builds on FreeBSD again, with rust-rocksdb vendoring RocksDB there (fixes #492). Reported by @syobocat.
-
The MatrixRTC/Livekit setup docs were missing the Docker address-advertisement configuration, now explained (fixes #493). Reported by @Wanja-L.
-
Conduit database import gains several repairs: the
roomuserid_joinedrepair runs in a single pass, the conduwuit-era membership repairs are skipped for Conduit imports, and systemd's start timeout is extended so long startup migrations are not killed (#41). Thanks to @x86pup. -
The remote-server version endpoint returns our own version for a self-query instead of failing, with appreciation to @x86pup.
-
Unauthenticated TURN access was possible with
turn_allow_guestsenabled; guest access is now gated and appservice users are excluded from the guest TURN credentials check, credit to @dasha-uwu. -
Federation delivery is steadier: a stale resolver route is evicted on a non-JSON response (9bac544), the sender flushes when an unhealthy peer shows inbound activity (2d9c684), a first-failure retry grace precedes the backoff curve (e7f5769), and the sender wakes to retry a failed destination (93a772e).
-
EDU delivery is more reliable: selected device-list and receipt EDUs persist until acknowledged (ffdfc1b), EDU selections queue past the transaction budget (7091f84), and fresh EDUs are selected on the post-response path (3569317).
-
/messagesis forbidden on a room the requester cannot see (a791d7e). -
An unsupported method on a known path returns 405 instead of 404 (cd0513a).
-
The request extractor separates an empty body from a malformed one (80727f8).
-
is_directis omitted from member events unless it is true (adb78b9). -
The registration email binds regardless of UIA stage order (9b58cae).
-
The error log on undecodable presence data is restored (d81f340).
-
FIFO cache column TTLs are bounded to each column's validity window, with intra-L0 compaction enabled for those columns (9b3011a, e9004c9).
-
Release builds could fail to compile the room-summary layout after a 1.8.0 change; boxing the membership format at the invite edge cuts the recursion (regression d2c473f).
Release v1.8.0
Tuwunel 1.8.0
June 27, 2026
New Features & Enhancements
-
Conduit database migration available again courtesy of @x86pup. Open Tuwunel with an existing Conduit (or foreign-lineage) database directory and it migrates in-place: rooms, original media including S3-backed objects, pending knocks, and suspended or locked users all carry over, media is attributed to its local owners, and conduit-migrated rooms become usable. Raised by @Korvox in (#41).
-
Third-party-identifier (3pid) email support (MSC2290) arrives with outbound email, 3pid storage, the email-3pid request and management endpoints, and admin commands to manage and query email 3pids.
-
Matrix Authentication Service (MAS) support is implemented: the provisioning API endpoints, synced provisioned email bindings, and SSO redirect-action forwarding (MSC3824, so a
registeraction becomesprompt=createon the upstream OIDC request). Opened by @CEbbinghaus in (#266). -
A remote-server version API, a new client endpoint exposing the versions reported by remote servers, shipped by @dasha-uwu (d038c5b).
-
SSLKEYLOGFILEsupport for the outbound client, for debugging federation TLS, also from @dasha-uwu (5f00e39). -
User reports can post to a configurable room instead of the admin room, so operators can moderate without holding server-admin, graciously contributed by @x86pup. Opened by @iwalkalone69 in (#180).
-
The nginx reverse-proxy example collapses its duplicate 443 and 8448 server blocks into one, tip of the hat to @Daniel15 in (#487).
-
Push gateway resolution now runs through the validating resolver, so the private-IP CIDR denylist (
ip_range_denylist) applies to pusher delivery, including redirect hops (28e08c2). Operator note: this silently stops delivery to any push gateway on a private or loopback address (a localhost Sygnal, a LAN ntfy or UnifiedPush) untilip_range_denylistis adjusted to permit it. -
Spec compliance advanced across many endpoints: stable
/v1/mutual_roomswith count and paging (MSC2666, cd5004e); rich-text room topics preferring them.topicblock with legacy fallback and indexed for search (MSC3765, fc29fe4); extended profile fields with enforced size and grammar limits (MSC4133, 03b9909); invite and knock stripped state carried as full federation PDUs so a receiver can bind the create event (MSC4311, d2c473f); a registration terms stage (MSC1692, opened by @erebion in #289); appservice device management (MSC4190, opened by @ngophuocloi-miracle-aavn in #488); the user-report endpoint returning 200 for unknown users to deter enumeration (MSC4277, 6ddd590); per-requester thread bundles withcurrent_user_participatedand the fulllatest_event(MSC3816, 3c3e65a); search results populating surrounding event context and pagination tokens (945e79c); device-list updates flushed to federation on key change (eff8e52); and federationget_missing_eventsserving stored canonical JSON so unmodeled fields survive (e2eca44).
Bug Fixes
-
The local server is now always exempt from
allowed_remote_server_namesandforbidden_remote_server_names. A 1.7.x allow-list that omitted the local name classified a local user's own events as coming from a forbidden remote and dropped them (fixes #489). Reported by @BurningEnlightenment. Sincere apologies to anyone whose own users went quiet. -
/timestamp_to_event(MSC3030) returnedM_NOT_FOUNDfor valid searches because the room-scoped scan stopped on the first foreign-room key; fixed by @lingbohome in (#477). -
make-user-admin now grants the correct power level when the target is already in the admin room, with appreciation to @x86pup. Reported by @mio-19 in (#84).
-
LDAP is skipped during UIA reauth for non-LDAP accounts, so resetting device keys on a non-LDAP account no longer triggers a filterless LDAP search, credit to @x86pup. Reported by @kuhnchris in (#255).
-
A lost-wakeup in
until_shutdownthat could stall a service worker is fixed (22676a3). -
/timestamp_to_eventfalls back to federation for local misses and forward start-edge queries (MSC3030, 914b16c). -
Several federation membership fixes: a re-invite over a stale local ban is honored, an out-of-band invite rescission is applied,
join_authorised_via_users_serveris ignored for an existing member, custom/joinbody keys are merged into the member event, and kicking a non-member returns 403 (a37bd24, b5101ac, 836831c, 8e135be, fae1595). -
Lazy-loaded incremental sync no longer drops changed members other than the syncing user (MSC4222, 0e5800c).
-
State resolution for pre-v12 rooms now begins iterative auth checks from an empty initial state, matching the handling used for version 12 rooms (954b0c3).
-
Per-room push rules now carry across a room upgrade (c852ae2).
-
A device's local notification settings are removed on every device-deletion path (MSC3890, e0283e0).
-
The single-event endpoint returns 404 rather than 403 for an event hidden from the requester (404b516).
-
A client invite to a server lacking the room version returns
M_UNSUPPORTED_ROOM_VERSION(MSC1866, 5869123). -
Version 12 room upgrades omit the deprecated
predecessor.event_id(MSC4291, 6625065). -
The
/contextend token is positioned so a backward page still includes the base event (f3fe502). -
The
[global.smtp]config section is fixed (6061c5c). -
Notable for operators: the RocksDB storage engine is bumped to 11.1.1 (ab32765), and the first 1.8.0 boot on an existing database performs a one-time timestamp-index rebuild from
pduid_pdu, which lengthens first startup on large instances (41f0de0, 873f670).
Release v1.7.1
Tuwunel 1.7.1
June 5, 2026
New Features & Enhancements
-
A new federation data-fetching service improves reliability in rooms whose history is spread across many servers by locating missing events through concurrent queries. It ranks candidate servers by room-membership popularity and recent reachability, and reuses requests already in flight instead of issuing duplicates. Resolved state for outlier events, fetch and backoff decisions, and per-server reachability ("Peer Status") are now cached persistently, and auth-chain, state, prev-event, and backfill fetches all run through it. Servers that used to re-request the same uncacheable lookups should see far less repeated federation traffic.
-
OIDC device authorization grant (RFC 8628) lets users sign in on input-constrained devices. The MSC4191 account-management action set is now complete with a deep-linked cross-signing reset, and MSC3861 OAuth 2.0/OIDC is advertised on
/versions. The token endpoints and refresh-token lifecycle were reworked, dynamic client registration is opt-in and validates submitted client metadata, and device-scope binding requires PKCE. The OIDC authorization-server chapter of the documentation was expanded to match. -
Several additional MSCs land this cycle: MSC3980 (
event_fieldstrimming on/sync), MSC3860 (media download redirects), MSC4311 (origin_server_tson the stripped create event), MSC1219 (key backup storage conformance), MSC2659 (appservice ping error codes), MSC3550 (403 M_FORBIDDENallowed on profile lookup), and a stablem.forget_forced_upon_leavecapability (MSC4267). MSC4380 invite blocking now also covers invites delivered through/syncandcreateRoom. -
Support-contact discovery gains a PGP field and policy links (MSC4439, MSC4266), graciously contributed by @x86pup. The
/.well-known/matrix/supportendpoint can now advertise apgp_keyper contact (with raw key material rejected) and link support policies, and multiple support contacts can be configured with validation. -
@dasha-uwu added an
admin media previewcommand for debugging URL previews, retired blurhashing, dropped the legacy media-preview redirect, and removed the deprecated server-keys endpoint. -
Sliding sync (v5) now retracts departed and left rooms from the list and adds re-invited rooms back, so clients track membership churn without a full resync.
-
A device may now hold multiple access tokens, for easier rotation and concurrent sessions.
-
/contextcan optionally resolve events it has not yet received over federation, and outbound HTTP compression gained per-direction opt-out switches. -
An admin command to purge every room containing a given user was added, raised by @winyadepla in (#472).
-
Documentation for
ip_source_trusted_subnetsnow warns about accidentally including a proxy in the trusted set, courtesy of @BVollmerhaus in (#468). -
Diagnostic admin command suites were added for the federation fetcher and Peer Status, and the runtime can dump tokio and getrusage metrics to JSON at exit.
Bug Fixes
-
A regression introduced with
ip_sourcein 1.6.1 blocked locally-connected appservices and other loopback clients (#465). Loopback peers and trusted-peer subnets now bypass the configuredip_source, including over the Unix-socket listener, and theaxum-client-ipdependency was replaced with inlined helpers. Sincere apologies to everyone whose bridges went quiet. -
Remote room directory and summary lookups are more resilient over federation: the room-summary fallback now tries every
viaserver (5c99983), and a failed remotepublicRoomsrequest now returns a502(9a87977). -
Thank you @x86pup for reporting in (#466) that a bad
unix_socket_pathproduced an opaque startup failure; listener initialization errors now name the offending path. -
!admin query oauth associatereplied with an empty message and did nothing, reported by @Vazgen005 in (#467). It now emits a confirmation and accepts aforceflag. -
@dasha-uwu fixed a compression configuration option that could accidentally disable client-side decompression.
-
Several federation correctness fixes: the federation lock is now held across the invite residency check to close a join/unban race (add512b); a
send_joinresponse that omits state fails over to other servers (9c158d3); each transaction's PDUs are sorted topologically before handling (91218e1); and references outside the auth graph are treated as non-edges during resolution (6643919). -
Knock membership is now persisted and a remote re-knock re-drives to reconcile state; per-PDU backfill errors are isolated so one bad event no longer aborts the batch; and thread redaction walks through the redacted target.
-
Media fetches and URL previews now honor CIDR denylists for the addresses they resolve to (af1266a, 554557c). Buffered outbound responses are size-bounded, and federation key lookups are bounded and backed off.
-
Configuration handling improved: an unreadable
client_secret_filenow reports the path and IO error (844f123), matched keys can be excluded from the "unknown to tuwunel" warning (6bbfd0a), and packaged builds no longer drop theirmalloc_conftuning (de0eb1d).
Release v1.7.0
Tuwunel 1.7.0
May 21, 2026
All servers raising their cache_capacity_modifier above default must consider decreasing it to deploy this release. The default of 1.0 is now generally recommended, and up to 2.0 for systems with four or less cores. Taking no action may cost 25% to 50% more memory (#123).
Nine additional MSCs have landed. Current status is kept up to date in our documentation.
New Features & Enhancements
-
Threaded read receipts and notifications (MSC3771, MSC3773) ship across storage, federation, sync v3, SSS v5, and the push gateway. Existing users may see a one-time jump in unread or badge counts that previously sat at the main-context-only total.
-
MSC4225 one-time-key upload-order issuance is implemented. Operator note: the legacy
onetimekeyid_onetimekeyscolumn is dropped on first read-write open and existing OTKs are erased; clients re-upload on their next /sync, with MSC2732 fallback keys (where present) covering the gap. The wipe is one-way; read-only and secondary replicas tolerate the missing column until the primary recreates it. -
MSC4222
state_afteron /sync v3 as an opt-in via?use_state_after=true. Clients that don't opt in are unaffected. -
MSC4115
unsigned.membershipon served events from encrypted rooms. Informational; clients that ignore the field are unaffected. -
Synapse-compatible shared-secret register endpoint at
/_synapse/admin/v1/register, raised by @iwalkalone69 in (#38). The admin module was also split into a directory of units. -
Refresh-token expiry with optional hard logout via three new keys:
refresh_token_ttl,refresh_token_idle_only, andrefresh_token_hard_logout. All default disabled. -
Configurable extra OIDC authorization parameters, courtesy of @Batmaev in (#450). Closes the silent-relogin gap with Logto and Element X when operators set
prompt = "login". Thank you! -
MSC4452
preview_urlcapability is advertised on /capabilities. -
MSC4466
propagate_toprofile query parameter is implemented; the room fan-out also runs concurrently. -
MSC3283
m.set_displaynameandm.set_avatar_urlcapabilities are advertised. -
MSC3814 fallback keys on dehydrated-device PUT are now stored.
-
OpenTelemetry OTLP exporter replaces the deprecated
opentelemetry-jaegercrate, closing (#85);tokio-consoleis re-enabled. -
Tip of the hat to @nyakokitsu, who reported in (#460) that
turn_urisset without TURN credentials produces empty creds silently. Tuwunel now warns at startup. -
Thanks to @dasha-uwu for simplifying
servers_route_via. -
Per-cache defaults were rebalanced from observed utilization in (#123):
auth_chainup 15x to 1.5M, several shorteventid/eventid caches 4x to 400k. Closes (#123) and (#423) opened by @scanash00; an earlier report by @alythemonk in (#262) on Oracle Linux OOM-via-PGTABLE is also addressed. Operators on<= 2 GiBhosts may want to clamp the cache modifiers in their toml to restore the previous baseline. -
Admin
server memory-usageis now tabular(used / cap / util%)with per-pool block-cache rows. -
Configuration items are annotated in the generated
tuwunel-example.tomlto indicate runtime-reloadable vs restart-required. -
The KV codec's additive-tail invariant for trailing
Option<_>,&str, and&[u8]fields is documented. -
A migration upgrades legacy
mediaid_userkeys to the composite layout. -
Thank you @NiklausHofer for the Gentoo Guru ebuild in "Getting Started" (#461).
-
Docs:
enable_loopback_candidatetroubleshooting motivated by @Lama-Thematique in (#451),ip_sourcefor reverse-proxy users, and an MSC table refresh (MSC3419 verified, MSC1957 n/a, rows for MSC4461 through MSC4474). Closes (#94) opened by @MrRinkana. -
Thanks to @winyadepla for the traefik MatrixRTC config in (#462) bringing parity with nginx and caddy. Also addresses (#69) opened by @GZEI.
-
CI gained a Complement job-summary script, a Playwright stage, and drift detection so a missed
tuwunel-example.tomlregeneration fails check and clippy.
Bug Fixes
-
A v1.6.2 regression on non-S3 storage backends panicked the main thread on first upload. Reported by @Sommerwiesel in (#452); multipart is now gated on S3 only. Sincere apologies for the disruption.
-
@BVollmerhaus graciously reported in (#454) that MSC2246 asynchronous media uploads could self-deadlock on the notifier mutex; the acquisition order is fixed. Thank you!
-
Thanks to @digikar99, who reported in (#459) that the UIAA fallback acknowledgement rejected non-SSO flows; the registration token + password flow completes cleanly.
-
Sliding-sync cached list ranges refresh on every explicit list update, shipped by @lhjt in (#455); previously a scrolled-to range was ignored indefinitely. Thank you!
-
/threads and /backfill apply the visibility filter before pagination
take, so a final non-empty page still returnsnext_batch. -
GitHub OIDC default
base_pathnow aligns with their published discovery doc after they quietly changed the issuer (eb51c70, 6552f86). -
OAuth Dynamic Client Registration records are bounded to a fixed size. Thanks @CEbbinghaus! (e5f625d).
-
OAuth SSO grant params win over operator-configured extras on key collision (05dba7e).
-
Receipts and presence EDU emission is bounded below the federation budget (b4fcf58).
-
Membership tolerates stale room state on self-leave (39c72c2).
-
A missed optimization in
/stateand map-value storage was corrected (b305e6a);/statenow also propagates per-PDU read errors instead of silently skipping corrupt events. -
Five route doc-headers had incorrect HTTP verbs (a40ca8f).
-
The Docker bake file dropped the non-functional
cache_to/cache_fromdirectives (8e4bc8c). -
Thank you @pedrompcaetano for the typo fix in
tuwunel.container(#456). -
Stale comments and fan-out destructure cleanups (85e85c8, 9c4cd7c, 2cc2493).
Release v1.6.2
Tuwunel 1.6.2
May 8, 2026
We have started a specification compliance campaign which will continue over the next several releases until synced with 1.18 (or 1.19 if it takes that long). Current status will be kept up to date in our documentation.
New Features & Enhancements
-
Policy server support (MSC4284) ships; two new config keys:
enable_policy_serversandpolicy_server_request_timeout. -
Account locking and suspension (MSC3939, MSC4323, and MSC3823), plus an admin command to mass-reject pending invites.
-
MSC2732 Olm fallback keys are implemented and re-issued on each subsequent claim, so clients keep receiving after key exhaustion.
-
MSC4380 invite blocking (partial).
-
MSC4406
sender_ignoredon single-event endpoints. -
MSC4383
/versionsdiscovery. -
MSC4260 user reports.
-
MSC4373 incoming-EDU types over federation.
-
MSC4168
m.space.*state copied on upgrade. -
MSC4169 backwards-compatible redactions on send.
-
MSC3905 local-only users namespace matching for appservices.
-
MSC4025 partial erase on
/deactivate. -
MSC3391 account-data deletion.
-
MSC4361 non-federating member auth rules.
-
MSC4190 appservices now skip UIA on cross-signing key replacement.
-
MSC4254 OIDC revoke handler is tightened across request shape, error codes, and provider lookup.
-
MSC4175 Timezone-key routes have been updated to the stabilized form.
-
Thanks to @DBendit who opened (#316): a complete list of MSCs Tuwunel supports is now in the docs.
-
@dasha-uwu shipped cleanups: appservice file filter, conditional admin lookup, two-member room naming, thumbnail logging, remote media ids.
Bug Fixes
-
Sliding-sync
bump_stampis graciously fixed by @lhjt in (#449), so Element X and other clients move rooms in the sidebar on new activity. -
Thanks to @humemm for (#448), where OAuth responses returning
expires_atas a Unix timestamp tripped login; the upstream DTO is now decoupled. -
Tip of the hat to @maxrdz for the NGINX root-domain delegation example in (#446), with default port and a resilient
$backendindirection. -
State resolution corrections: knock auth v7-9 (aea509f), auth-difference (631c51a), mainline 0 (82132ee), v12 bootstrap-join (aaa6a1a). A few were upstreamed to Ruma.
-
A long-standing
/syncconcurrency heisenbug (b1ac65b), originally introduced in Conduit and made slightly worse by optimizations which took place in v1.3.0, has finally been zapped.
Release v1.6.1
Tuwunel 1.6.1
May 1, 2026
New Features & Enhancements
-
Next-gen OIDC account management, courtesy of @shaba in (#407), implements MSC2965 and provides the in-browser session list, session-end flows, and profile page for users authenticated via OIDC. The same PR fixes URL-encoding of
idp_idin the SSO redirect path and adds the SSO/OIDC bypass path through User-Interactive Authentication so that users without a password can complete UIAA-protected actions. This closes (#433) opened by @jonathanmajh. Thank you! -
Appservices with
receive_ephemeralnow receive EDUs scoped to their namespaces in (#406), shipped by @chbgdn and closing (#382).m.typingandm.receiptnow route to subscribed bridges and bots. Confirmation testing was provided by @gymnae, thank you both! -
systemd watchdog keep-alive pings were graciously added by @VlaDexa in (#415). Unit files declare
WatchdogSec=30and the runtime pings systemd, so an unresponsive process is restarted automatically; previously-tolerated long stalls (e.g., pathological state-resolution) may now trigger restarts. -
Spoofing-resistant client-IP resolution with a configurable
ip_sourcewas contributed by @theredspoon as a security finding (#427), implemented and landed across (#428) and (#429). The newConfiguredIpSourceextension andClientIpextractor replaceaxum_client_ip::InsecureClientIpacross the API, restoring trust in client IPs for rate-limiting and audit logging. Default behavior is unchanged for existing deployments; operators behind a trusted proxy should setip_sourceto opt in. -
MSC3030 (
/timestamp_to_event) is implemented (experimental), contributed by @donjuanplatinum in (#413). Clients can now jump to a specific point in time within a room. This is the third Matrix Spec Change @donjuanplatinum has shipped to Tuwunel and we are very grateful for the consistent contributions. -
MSC3824 (delegated authentication / refresh-token capability) is advertised on
/versionsandLoginType::Ssoincludesdelegated_oidc_compatibility. The config keysso_aware_preferredis renamed tooidc_aware_preferred, with the old name accepted as alias. -
Thanks to @rexbron, who contributed extensive operational documentation in (#354) and (#438): a
testmatrixexample in the troubleshooting section, podman-quadlet examples, an OIDC Keycloak provider example, refactored troubleshooting links, and clarification of how to obtainprovider_idfor the user admin commands. Thorough work! -
@valentimarco wrote a complete Authelia authentication page in (#278), closing their own (#274) on the OIDC token endpoint. Thank you!
-
Thanks to @winyadepla for reorganizing the calling chapter in (#431), clarifying TURN vs MatrixRTC and the rationale for Docker-only deployment. This addresses (#348) opened by @MadMan247. Thank you both!
-
Thank you @alametti for adding an Authentik provider section in (#437).
-
Configuration values that name byte sizes now accept SI/IEC unit strings (
64MiB,2GB, etc.) in addition to raw integers. -
A persistent LRU cache was added for
userdevicesessionid_uiaainfoto keep ongoing UIA sessions alive across restarts. -
Performance: appservice EDU conditions reworked for concurrent lazy serialization; lazy-loading witness write-back gained a mode argument; the legacy spacehierarchy runtime cache was replaced by a database-backed path (config key
roomid_spacehierarchy_cache_capacityβspacehierarchy_cache_ttl_min/spacehierarchy_cache_ttl_max). -
Admin: new commands to dump PDUs to the filesystem, query the RocksDB sequence number, and force/override or bypass database migrations.
-
Bootstrap stamps a
server_namemarker into the global column family (backfilled on first boot for pre-existing databases) so a misconfiguredserver_namepointed at the wrong database is caught on every start. -
The
media_storage_providersconfig option now validates that named providers exist; an explicit empty provider list defaults to all configured providers. -
New documentation chapters: Authentication Systems overview, JWT auth, LDAP auth, multimedia and storage, storage-provider environment variables. Identity-linking semantics for trusted vs. untrusted IdPs are now documented. The development chapter links hosted rustdocs (newly deployed via CI) and a Testing section was added. (#324) opened by @TheButlah on the NixOS Module documentation is closed.
-
OCI image labels now include accurate
org.opencontainers.image.versionand related metadata derived from the package, closing (#356) opened by @rexbron. Thank you for the detailed write-up!
Bug Fixes
-
OIDC server-contract hardening:
/_tuwunel/oidc/userinforejects plain Matrix access tokens (withWWW-Authenticate: Beareron401); the token endpoint returns400/invalid_grantinstead of500on client errors and emitsCache-Control: no-store; PKCEplainis no longer accepted (onlyS256); them.oauthUIA flow routes through/login/sso/redirectwhen no specific IdP is selected. -
Storage-provider variant naming is now consistent, with appreciation to @yonzilch for (#414). Both sub-tables use lowercase identifiers (
[global.storage_provider.<ID>.s3]), unblocking environment-variable configuration. ExistingS3configurations are still accepted. -
OpenBSD startup is fixed in (#422), tip of the hat to @Hukadan.
core_affinity_rsmisreports CPU counts on OpenBSD; Tuwunel now usesnum_cpusthere. Thank you for picking this up! -
@alaviss reported a 1.6.0 regression in (#432) where inline
[global.appservice.<ID>]config no longer worked. Fixed in (9d10230); the appservice ID from the toml section is honored again. Sincere apologies for the inconvenience. -
Multiple users reported the room-spaces hierarchy endpoint returning incomplete or invalid results: @vrisalab in (#344) and @foxing-quietly in (#399). The hierarchy unit was refactored, optimized, and corrected (including discarding
m.space.childevents with empty content per MSC1772/MSC2946). Special thanks to @TheBrigandier for testing and confirming the fixes on both threads. -
Thanks to @utop-top, who reported in (#411) that S3 uploads to Cloudflare R2 timed out for large media (~200 MiB+). Multipart uploads now kick in above a configurable
multipart_threshold(default100 MiB). We appreciate the patient testing! -
Thank you @utop-top for also reporting in (#401) that appservice E2EE was broken because
/whoamiwasn't returning adevice_idper MSC3202, crashing matrix-hookshot on startup. Tuwunel now accepts and asserts the appservice-supplieddevice_idper MSC4326. Confirmation testing was provided by @Domoel, thanks to you both! -
@BVollmerhaus reported in (#327) that mautrix bridges (e.g., mautrix-signal) couldn't upload device keys via MSC4190, blocking Element's upcoming mandatory device verification rollout. The MSC4190 path no longer stores
as_tokenas the access token, and honors the appservice-asserteddevice_idon create. Special thanks to @1matin, @Domoel, and @gymnae for active testing across the thread. -
Sliding-sync long-polls now release on client disconnect, credit to @chocycat for (#386). Refreshing a client no longer leaves the previous poll holding the connection mutex for the full timeout. Supplemented by task-detach and shutdown-timeout abstractions on main.
-
Thanks to @kodazavr for the immediate report in (#444): Tuwunel failed to start with Sentry integration enabled because the Sentry transport was missing a TLS backend. The reqwest transport is now built with merged webpki roots.
-
Thank you @dennisoderwald for catching in (#443) that OIDC discovery advertised
response_mode=fragmentwhile the authorize endpoint only acceptedquery. Both modes are now implemented through the authorize/complete path. -
@dennisoderwald also reported in (#434) that S3 storage worked over HTTP but not HTTPS. The missing
tls-webpki-rootsfeature was added to theobject_storedependency. Confirmation testing was provided by @ZoftTy and @kodazavr, thank you all! -
Thanks to @dlford for the report in (#403) that clearing the presence status message had no effect. Now implemented with correct state transitions.
-
Thank you @oly-nittka for the careful diagnosis in (#385) that federation with
matrix.orgwas failing: a stale SRV cache entry overrode the .well-known delegation, producing port8443instead of443. Theactual_dest_2/actual_dest_3_2resolver paths now parse explicit ports from delegated hosts. -
@native4don reported in (#377) that
device_lists.changedwas missing from/syncafter cross-signing key uploads or device-key changes. The per-room device-key-change row was restored and the sync path updated. Confirmation testing was provided by @rexbron and @x86pup, thank you all! -
Thanks to @Giwayume for spotting in (#376) that
GET /_matrix/client/v3/devicesreturnednullfordisplay_nameand was not spec-compliant. The RumaDevicetype now skips serializing optional fields when absent. -
Thank you @foxing-quietly for the report in (#372) that
GET /room_keys/versionreturned500instead of404for stored backups predating thealgorithmfield. A backup-algorithm serializer now migrates legacy records on the fly. -
@kuhnchris reported in (#435) that AppService regex matching was case-inconsistent. User and alias namespaces now use case-insensitive comparisons, matching how MXIDs are normalized. Thank you!
-
@Himura2la updated the LiveKit configuration documentation to the modern form in (#420), addressing (#400) reported by @Morgan-SL-PUP. Thank you both!
-
Thanks to @grinapo for noting in (#317) that the Caddy
.well-knownexample used incorrect CORS syntax. The example was corrected. -
Thank you @jameskimmel for correcting the Docker port mapping in the example to match the listener (#393).
-
A regression in
state_cachewhere the per-user transit step wa...
Release v1.6.0
Tuwunel 1.6.0
April 9, 2026
New Features & Enhancements
-
Next-Gen Auth OIDC server enhancing ElementX and SchildiNext has arrived! It all began only a month ago with (#342), a large draft PR by @lytedev assessed by the Tuwunel team to be several months away. What happened next was truly extraordinary. Starting with @chbgdn and followed by @siennathesane, @DonPrus and @shaba an entire project within this project assembled to test and iterate this branch at a rapid clip. The OIDC server now builds on existing infrastructure in Tuwunel previously used for SSO. If you have an Identity Provider configured already for use with SSO then the OIDC server Just Works. Huge thanks to everyone involved. (Implements MSC2964/2965/2966/2967)
-
S3 Storage support is now available! Starting from (#362) graciously developed by @exodrifter, Tuwunel now introduces multiple media backends with configurable sections. Support currently includes S3 endpoints and local filesystem directories. The existing media directory is now itself a configurable storage provider implied by the section
[global.storage_provider.media.local]. See the examples under[global.storage_provider.<ID>.S3]to configure your own S3 provider. Then list it inmedia_storage_providersto download media from it, andstore_media_on_providersfor uploading media to it. Experimental migration support is available with the!admin query storage synccommand. SPECIAL UPDATE: Thanks to testing by @utop-top large uploads (~200 MiB) may not work for some S3 providers until additional support is added in 1.6.1. We apologize for this limitation. -
User-Interactive Authentication for SSO accounts (MSC2454) has been made possible thanks to @chbgdn in (#389). Accounts no longer require setting a password to use features protected by UIAA flows. Users wishing to disable password authentication on their account altogether may do so by changing it to a single asterisk '*' character (use the admin room commands if your client refuses this password change).
-
User-Interactive Authentication for Next-gen OIDC (MSC4312) was implemented by serial auth-system contributor @chbgdn in (#405). This provides cross-signing/identity reset functionality for ElementX and co.
-
Asynchronous media uploads for appservices was implemented thanks to @donjuanplatinum (MSC2246) in (#347).
-
Thanks to @dasha-uwu the
appservice_dircan be configured to a directory containing all your appservice yaml files. -
@donjuanplatinum implemented the server-side for fast-joins (MSC3706) in (#349). Thank you!
-
Thanks to @ventureoo we support sockets managed by systemd after (#360) (issue #355).
-
@VlaDexa prevented duplicate reactions from being sent by a client to maintain spec compliance with (#353), thank you!
-
Thank you @alametti for adding delegation examples (e.g. example.com to matrix.example.com) to the documentation in (#352).
-
Thanks to @Lama-Thematique the admin room user registration notice was improved in (#387).
-
Thank you @dasha-uwu for implementing the MSC4143 endpoint.
-
Thank you @dasha-uwu for removing the report score per MSC4277.
-
Thank you @dasha-uwu for removing v1 send_join/leave as per MSC4376.
-
RocksDB compaction details are logged for the curious in verbose logging builds.
-
Numerous performance optimizations including JSON deserialization and allocator optimizations.
-
Sliding-sync no longer persists subscriptions across requests.
-
Configuration option
allowed_remote_server_names_experimentaladded as exclusive federation allow-listing. NOTE: the_experimentalsuffix was added to indicate the logic of this feature will change in an upcoming release and the suffix will be removed. We sincerely regret this inconvenience.
Bug Fixes
-
Thank you @jameskimmel for fixing the nginx configuration for http/2 support. (#391)
-
@exodrifter fixed various errors and typos in documentation (#343), some reported by @RhenCloud in (#338). Thank you both!
-
@VlaDexa fixed systemd reloading by sending monotonic time after consultation with @rexbron. (#359) Thank you both!
-
Thanks to @exodrifter the media delete range commands now have improved verbiage as of (#375).
-
@yefimg fixed the UIA password flow not being advertised to LDAP users due to regression (#378). Special thanks for this!
-
Thank you @proximalriver for fixing the missing
serverkeyword in the nginx example. (#383) -
@chbgdn fixed the m.change_password capability not being set based on
login_with_password. (#388) Thank you! -
Thank you @centromere for reporting cross-platform build regressions in #357 which were fixed.
-
Thank you @Ada-lave for reporting a regression with admin startup commands in #320 which we fixed.
-
@0x1af2aec8f957 reported the new systemd-friendly listener system required reuse-address flags to be set (#374). Thank you for reporting!
-
Thank you @Batmaev for reporting non-compliant minimum timeout was imposed on sliding-sync in (#402) which was corrected.
-
@dasha-uwu fixed admin room upgrade to work as expected. @dfuchss inspired with (#361) among many other informal reports. We appreciate the effort of everyone involved on this!
-
@tycrek reported the conduit user is involved in
force-join-all-local-userscommands (#373) which was fixed thanks to @dasha-uwu. -
Thanks to @dasha-uwu bugs and compliance regarding
initial_stateduring room creation were addressed.