Multimedia and storage provision
Tuwunel handles media uploads, remote media fetching, thumbnail generation, URL previews, and blurhash generation. This chapter covers configuration for all of these features, as well as the storage backends that back them.
-
Storage providers — Local filesystem and S3-compatible object storage backends.
-
Media management — Commands for inspecting, deleting, and bulk-removing media, including spam response.
Upload limits
| Option | Default | Description |
|---|---|---|
max_request_size | 24 MiB | Maximum size of a single media upload. Accepts SI/IEC units, e.g. "50 MiB". |
max_pending_media_uploads | 5 | Maximum number of in-progress asynchronous uploads a single user can have at once. |
media_create_unused_expiration_time | 86400 | Seconds before an unused pending MXC URI is expired and removed (default: 24 hours). |
media_rc_create_per_second | 10 | Maximum media-create requests per second from a single user before rate limiting applies. |
media_rc_create_burst_count | 50 | Maximum burst size for media-create rate limiting per user. |
Legacy media endpoints
Matrix spec version 1.11 introduced authenticated media endpoints. The older unauthenticated endpoints are deprecated but some clients and servers still use them.
| Option | Default | Description |
|---|---|---|
allow_legacy_media | false | Serve the unauthenticated /_matrix/media/*/ endpoints locally. The authenticated equivalents are always enabled. |
request_legacy_media | false | Fall back to unauthenticated requests when fetching media from remote servers. Unauthenticated remote media was removed around 2024Q3; enabling this adds federation traffic that is unlikely to succeed. |
Blocking remote media
prevent_media_downloads_from is a list of regex patterns matched against
server names. Tuwunel refuses to download media originating from any matching
server.
prevent_media_downloads_from = [
"badserver\\.tld$",
"spammy-phrase",
]
This is useful as a reactive measure after a spam incident. See the Management page for bulk-deletion commands to pair with it.
URL previews
URL previews are disabled unless at least one allowlist is configured. All allowlist checks are evaluated before the denylist check.
| Option | Default | Description |
|---|---|---|
url_preview_domain_explicit_allowlist | [] | Exact domain matches allowed for previewing. "google.com" matches https://google.com but not https://subdomain.google.com. Set to ["*"] to allow all domains. |
url_preview_domain_contains_allowlist | [] | Substring domain matches. "google.com" matches any URL whose domain contains that string — including unrelated domains. Set to ["*"] to allow all domains. |
url_preview_url_contains_allowlist | [] | Substring match against the full URL (not just the domain). Set to ["*"] to allow all URLs. |
url_preview_domain_explicit_denylist | [] | Exact domain matches explicitly blocked. The denylist is checked first. Setting to ["*"] has no effect. |
url_preview_check_root_domain | false | When enabled, domain allowlist checks are applied to the root domain. Allows all subdomains of any allowed domain — e.g. allowing wikipedia.org also allows en.m.wikipedia.org. |
url_preview_max_spider_size | 256000 | Maximum bytes fetched from a URL when generating a preview (default: 256 KB). |
url_preview_max_media_size | 52428800 | Maximum size of a single media item fetched or relayed for a URL preview: the og:image measurement fetch and the lazy-media relay. Media larger than this is not registered, and an over-cap relay is refused (default: 50 MiB). |
url_preview_bound_interface | — | Network interface name or IP address to bind when making URL preview requests. Example: "eth0" or "1.2.3.4". |
url_preview_user_agent | — | User-Agent header sent when fetching pages to extract their OpenGraph tags. Defaults to the versioned server User-Agent, e.g. "Tuwunel/1.8.1 preview". |
url_preview_media_user_agent | — | User-Agent header sent when fetching and relaying preview media files themselves. Falls back to url_preview_user_agent. |
Note
Setting any allowlist to
["*"]opens significant attack surface — a malicious client could cause the server to make requests to arbitrary URLs on the local network. Use explicit allowlists wherever possible.
og:image, og:video, and og:audio (and direct links to image, video,
and audio files) resolve to an mxc:// URI on this server rather than the
third-party URL, and none of the content is stored: requests for that
mxc:// URI are relayed — the server fetches the source URL on the client’s
behalf (subject to the same SSRF/CIDR checks as everything else on this
page, and capped at max_response_size) and passes the content through, so
the third party sees the server’s address rather than the client’s, and the
server hosts nothing. Images are additionally downloaded once while
generating the preview to measure og:image:width/og:image:height and
matrix:image:size, then discarded. og:video:width/og:video:height are
populated when the page declares them. Clients cache the results themselves
per the immutable cache headers on media downloads. Because nothing is
stored, a preview’s mxc:// URI is only as durable as its source URL: if
the source expires or changes, later fetches reflect that, unlike uploaded
media. Upstream error responses are never relayed as media.
Blurhash
Tuwunel can generate blurhashes for uploaded images,
which clients use to show a blurred placeholder before the full image loads.
This requires the blurhashing compile-time feature.
Blurhash settings live in a dedicated config section:
[global.blurhashing]
components_x = 4
components_y = 3
blurhash_max_raw_size = 33554432
| Option | Default | Description |
|---|---|---|
components_x | 4 | Horizontal detail components. Higher values produce more detailed hashes at the cost of a larger hash string. |
components_y | 3 | Vertical detail components. |
blurhash_max_raw_size | 33554432 | Maximum raw image size (after decoding to pixel data) that will be blurhashed, in bytes (default: ~32 MiB). Set to 0 to disable blurhashing entirely. Should be at or above max_request_size to avoid silently skipping large uploads. |