Conduit
A Matrix homeserver written in Rust
What is Matrix?
Matrix is an open network for secure and decentralized communication. Users from every Matrix homeserver can chat with users from all other Matrix servers. You can even use bridges (also called Matrix appservices) to communicate with users outside of Matrix, like a community on Discord.
What is the goal?
An efficient Matrix homeserver that's easy to set up and just works. You can install it on a mini-computer like the Raspberry Pi to host Matrix for your family, friends or company.
Can I try it out?
Yes! You can test our Conduit instance by opening a client that supports registration tokens such as Element web, Nheko or SchildiChat web and registering on the conduit.rs homeserver. The registration token is "for_testing_only". Don't share personal information. Once you have registered, you can use any other Matrix client to login.
Server hosting for conduit.rs is donated by the Matrix.org Foundation.
What is the current status?
Conduit is Beta, meaning you can join and participate in most Matrix rooms, but not all features are supported and you might run into bugs from time to time.
There are still a few important features missing:
- E2EE emoji comparison over federation (E2EE chat works)
- Outgoing read receipts, typing, presence over federation (incoming works)
How can I deploy my own?
If you want to connect an Appservice to Conduit, take a look at the appservices documentation.
How can I contribute?
- Look for an issue you would like to work on and make sure no one else is currently working on it.
- Tell us that you are working on the issue (comment on the issue or chat in #conduit:ahimsa.chat). If it is more complicated, please explain your approach and ask questions.
- Fork the repo, create a new branch and push commits.
- Submit a MR
Contact
If you have any questions, feel free to
- Ask in
#conduit:ahimsa.chaton Matrix - Write an E-Mail to
conduit@koesters.xyz - Send an direct message to
@timokoesters:fachschaften.orgon Matrix - Open an issue on GitLab
Security
If you believe you have found a security issue, please send a message to Timo and/or Matthias on Matrix, or send an email to conduit@koesters.xyz. Please do not disclose details about the issue to anyone else before a fix is released publicly.
Thanks to
Thanks to FUTO, Famedly, Prototype Fund (DLR and German BMBF) and all individuals for financially supporting this project.
Thanks to the contributors to Conduit and all libraries we use, for example:
- Ruma: A clean library for the Matrix Spec in Rust
- axum: A modular web framework
Donate
- Liberapay: https://liberapay.com/timokoesters/
- Bitcoin:
bc1qnnykf986tw49ur7wx9rpw2tevpsztvar5x8w4n
Logo
- Lightning Bolt Logo: https://github.com/mozilla/fxemoji/blob/gh-pages/svgs/nature/u26A1-bolt.svg
- Logo License: https://github.com/mozilla/fxemoji/blob/gh-pages/LICENSE.md
Configuration
Conduit is configured using a TOML file. The configuration file is loaded from the path specified by the CONDUIT_CONFIG environment variable.
Note: The configuration file is required to run Conduit. If the
CONDUIT_CONFIGenvironment variable is not set, Conduit will exit with an error.
Note: If you update the configuration file, you must restart Conduit for the changes to take effect
Note: You can also configure Conduit by using
CONDUIT_{field_name}environment variables. To set values inside a table, useCONDUIT_{table_name}_{field_name}. Example:CONDUIT_WELL_KNOWN_CLIENT="https://matrix.example.org"
Conduit's configuration file is divided into the following sections:
Global
The global section contains the following fields:
Note: The
*symbol indicates that the field is required, and the values in parentheses are the possible values
| Field | Type | Description | Default |
|---|---|---|---|
address | string | The address to bind to | "127.0.0.1" |
port | integer | The port to bind to | 8000 |
tls | table | See the TLS configuration | N/A |
server_name* | string | The server name | N/A |
database_backend* | string | The database backend to use ("rocksdb" recommended, "sqlite") | N/A |
database_path* | string | The path to the database file/dir | N/A |
db_cache_capacity_mb | float | The cache capacity, in MB | 300.0 |
enable_lightning_bolt | boolean | Add ⚡️ emoji to end of user's display name | true |
allow_check_for_updates | boolean | Allow Conduit to check for updates | true |
conduit_cache_capacity_modifier | float | The value to multiply the default cache capacity by | 1.0 |
rocksdb_max_open_files | integer | The maximum number of open files | 1000 |
pdu_cache_capacity | integer | The maximum number of Persisted Data Units (PDUs) to cache | 150000 |
cleanup_second_interval | integer | How often conduit should clean up the database, in seconds | 60 |
max_request_size | integer | The maximum request size, in bytes | 20971520 (20 MiB) |
max_concurrent_requests | integer | The maximum number of concurrent requests | 100 |
max_fetch_prev_events | integer | The maximum number of previous events to fetch per request if conduit notices events are missing | 100 |
allow_registration | boolean | Opens your homeserver to public registration | false |
registration_token | string | The token users need to have when registering to your homeserver | N/A |
allow_encryption | boolean | Allow users to enable encryption in their rooms | true |
allow_federation | boolean | Allow federation with other servers | false |
allow_room_creation | boolean | Allow users to create rooms | true |
allow_unstable_room_versions | boolean | Allow users to create and join rooms with unstable versions | true |
default_room_version | string | The default room version ("6"-"10") | "10" |
allow_jaeger | boolean | Allow Jaeger tracing | false |
tracing_flame | boolean | Enable flame tracing | false |
proxy | table | See the Proxy configuration | N/A |
jwt_secret | string | The secret used in the JWT to enable JWT login without it a 400 error will be returned | N/A |
trusted_servers | array | The list of trusted servers to gather public keys of offline servers | ["matrix.org"] |
log | string | The log verbosity to use | "warn" |
ip_address_detection | See the IP address detection configuration | See the IP address detection configuration | |
turn_username | string | The TURN username | "" |
turn_password | string | The TURN password | "" |
turn_uris | array | The TURN URIs | [] |
turn_secret | string | The TURN secret | "" |
turn_ttl | integer | The TURN TTL in seconds | 86400 |
ignored_keys | [string] | Server keys that should be ignored | ["l/O9hxMVKB6Lg+3Hqf0FQQZhVESQcMzbPN1Cz2nM3og"] (ESS compromised key) |
media | table | See the media configuration | See the media configuration |
emergency_password | string | Set a password to login as the conduit user in case of emergency | N/A |
well_known | table | Used for delegation | See delegation |
Media
The media table is used to configure how media is stored and where. Currently, there is only one available
backend, that being filesystem. The backend can be set using the backend field. Example:
[global.media]
backend = "filesystem" # the default backend
Filesystem backend
The filesystem backend has the following fields:
path: The base directory where all the media files will be stored (defaults to${database_path}/media)directory_structure: This is a table, used to configure how files are to be distributed within the media directory. It has the following fields:depth: The number sub-directories that should be created for files (default:2)length: How long the name of these sub-directories should be (default:2) For example, a file may regularly have the name98ea6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4(The SHA256 digest of the file's content). Ifdepthandlengthwere both set to2, this file would be stored at${path}/98/ea/6e4f216f2fb4b69fff9b3a44842c38686ca685f3f55dc48c5d3fb1107be4. If you want to instead have all media files in the base directory with no sub-directories, just setdirectory_structureto be empty, as follows:
[global.media] backend = "filesystem" [global.media.directory_structure]
Example:
[global.media]
backend = "filesystem"
path = "/srv/matrix-media"
[global.media.directory_structure]
depth = 4
length = 2
S3 backend
The S3 backend has the following fields:
endpoint: The URL of the S3 endpoint to connect tobucket: The name of the S3 bucket to use for storage. This bucket must already exist and your credentials must have access to itregion: The region where your S3 bucket is locatedpath: The base directory where all the media files will be stored (defaults to root of the bucket)key: Your Access Key IDsecret: Your Secret Access Keyduration: The time (in seconds) that signed requests to the S3 bucket will be valid (default:30)bucket_use_path: Controls the structure of the path to files in S3. Iftrue, the bucket name will be included as part of the file path. Iffalse(or omitted), it will be used as the bucket name in the domain namedirectory_structure: This is a table, used to configure how files are to be distributed within the media directory (see Filesystem backend for details)
Example:
[global.media]
backend = "s3"
endpoint = "http://minio:9000"
bucket = "test"
region = "minio"
key = "<s3_key>"
secret = "<s3_secret>"
duration = 15
bucket_use_path = false
Retention policies
Over time, the amount of media will keep growing, even if they were only accessed once. Retention policies allow for media files to automatically be deleted if they meet certain crietia, allowing disk space to be saved.
This can be configured via the retention field of the media config, which is an array with
"scopes" specified
scope: specifies what type of media this policy applies to. If unset, all other scopes which you have not configured will use this as a default. Possible values:"local","remote","thumbnail"accessed: the maximum amount of time since the media was last accessed, in the form specified byhumantime::parse_duration(e.g."240h","1400min","2months", etc.)created: the maximum amount of time since the media was created after, in the same format asaccessedabove.space: the maximum amount of space all of the media in this scope can occupy (if no scope is specified, this becomes the total for all media). If the creation/downloading of new media, will cause this to be exceeded, the last accessed media will be deleted repetitively until there is enough space for the new media. The format is specified byByteSize(e.g."10000MB","15GiB","1.5TB", etc.)
Media needs to meet all the specified requirements to be kept, otherwise, it will be deleted.
This means that thumbnails have to meet both the "thumbnail", and either "local" or "remote"
requirements in order to be kept.
If the media does not meet the accessed or created requirement, they will be deleted during a
periodic cleanup, which happens every 1/10th of the period of the shortest retention time, with a
maximum frequency of every minute, and a minimum of every 24 hours. For example, if I set my
accessed time for all media to "2months", but override that to be "48h" for thumbnails,
the cleanup will happen every 4.8 hours.
Example
# Total of 40GB for all media
[[global.media.retention]] # Notice the double "[]", due to this being a table item in an array
space = "40G"
# Delete remote media not accessed for 30 days, or older than 90 days
[[global.media.retention]]
scope = "remote"
accessed = "30d"
created = "90days" # you can mix and match between the long and short format
# Delete local media not accessed for 1 year
[[global.media.retention]]
scope = "local"
accessed = "1y"
# Only store 1GB of thumbnails
[[global.media.retention]]
scope = "thumbnail"
space = "1GB"
IP Address detection
The method used to detect the IP address of the origin of the connection, which is currently used for rate limiting, but may be used for other features in the future. Currently available methods are:
header(default): Reads the value from the specified header, assuming it has the same format as theX-Forwarded-Forheader, which is the header read by default.
WARNING: This assumes that the header will always be set by your reverse proxy and cannot be overridden by connecting clients, so make sure your reverse proxy is configured to do this (Caddy does this for
X-Forwarded-Forby default).
socket_address: Uses the IP address of the client connecting to Conduit directly. This does not work with reverse proxies, as it would just use the IP address of the reverse proxy, so this is only recommended for testing.
To use a header other than X-Forwarded-For, set the following in your configuration:
[global]
ip_address_detection.header = "A-Different-Header"
If you instead want to use socket_address:
[global]
ip_address_detection = "socket_address"
TLS
The tls table contains the following fields:
certs: The path to the public PEM certificatekey: The path to the PEM private key
Example
[global.tls]
certs = "/path/to/cert.pem"
key = "/path/to/key.pem"
Proxy
You can choose what requests conduit should proxy (if any). The proxy table contains the following fields
Global
The global option will proxy all outgoing requests. The global table contains the following fields:
url: The URL of the proxy server
Example
[global.proxy.global]
url = "https://example.com"
By domain
An array of tables that contain the following fields:
url: The URL of the proxy serverinclude: Domains that should be proxied (assumed to be["*"]if unset)exclude: Domains that should not be proxied (takes precedent overinclude)
Both include and exclude allow for glob pattern matching.
Example
In this example, all requests to domains ending in .onion and matrix.secretly-an-onion-domain.xyz
will be proxied via socks://localhost:9050, except for domains ending in .myspecial.onion. You can add as many by_domain tables as you need.
[[global.proxy.by_domain]]
url = "socks5://localhost:9050"
include = ["*.onion", "matrix.secretly-an-onion-domain.xyz"]
exclude = ["*.clearnet.onion"]
Example
Note: The following example is a minimal configuration file. You should replace the values with your own.
[global]
# YOU NEED TO EDIT THIS
#server_name = "your.server.name"
database_backend = "rocksdb"
# This is the only directory where Conduit will save its data
database_path = "/var/lib/matrix-conduit/"
# The port Conduit will be running on. You need to set up a reverse proxy in
# your web server (e.g. apache or nginx), so all requests to /_matrix on port
# 443 and 8448 will be forwarded to the Conduit instance running on this port
# Docker users: Don't change this, you'll need to map an external port to this.
port = 6167
# Max size for uploads
max_request_size = 20_000_000 # in bytes
# Enables registration. If set to false, no users can register on this server.
allow_registration = true
# A static registration token that new users will have to provide when creating
# an account. YOU NEED TO EDIT THIS.
# - Insert a password that users will have to enter on registration
# - Start the line with '#' to remove the condition
registration_token = ""
allow_check_for_updates = true
allow_federation = true
# Enable the display name lightning bolt on registration.
enable_lightning_bolt = true
# Servers listed here will be used to gather public keys of other servers.
# Generally, copying this exactly should be enough. (Currently, Conduit doesn't
# support batched key requests, so this list should only contain Synapse
# servers.)
trusted_servers = ["matrix.org"]
#max_concurrent_requests = 100 # How many requests Conduit sends to other servers at the same time
# Controls the log verbosity. See also [here][0].
#
# [0]: https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#directives
#log = "..."
address = "127.0.0.1" # This makes sure Conduit can only be reached using the reverse proxy
#address = "0.0.0.0" # If Conduit is running in a container, make sure the reverse proxy (ie. Traefik) can reach it.
[global.well_known]
# Conduit handles the /.well-known/matrix/* endpoints, making both clients and servers try to access conduit with the host
# server_name and port 443 by default.
# If you want to override these defaults, uncomment and edit the following lines accordingly:
#server = your.server.name:443
#client = https://your.server.name
Rate Limiting
Conduit rate-limits security/privacy sensitive and resource intensive endpoints, to protect against things like:
- Denial of service attacks, caused by things like overloading the media store
- Abuse by spammers, attempting to make use of your server to send spam in mass, which usually leads to your server being put in policy lists, making it unable to participate in many rooms.
Note: The easiest way to prevent this is to disable public registration, and use a strong registration token to allow selective registration.
- Brute-force attacks to guess user's password or the servers registration token, the former leading to potential impersination, as well as denial of service if an admin account is accessed.
Presets
By default, Conduit uses the rate-limiting preset private_small, but there are more available if
this isn't the type of server you're planning on running:
private_small: The default preset, designed for small private servers (i.e. single-user or for family and friends).private_medium: Designed for medium-sized private servers (e.g. for an entire school class or year-group).public_medium: For medium-sized public servers (i.e. you intend 20-100 users to actively use it).public_large: For larger public server (i.e. you intend 200-1000 users to actively use it).
Here is an example configuration using the private_medium preset:
[global.rate_limiting]
preset = "private_medium"
Overrides
Despite the variety of presets available, you may find the presets to be too restrictive and/or liberal. You can override all the preset configurations directly in the configuration, and if you think your overrides should be part of the preset, you can contribute and change them!
The overrides are split into client and federation sections, for limits that apply to the
client and
federation APIs respectively, which are both
then split into target and global sections, which apply to singular targets or to all of them respectively.
Rate-limiting is implemented as a leaky bucket algorithm, where there is a burst-capacity for each restriction, which is filled when requests are made, and emptied over time at a speed determined by the timeframe. The format is as follows:
# The burst capacity, like the timeframe, either being the number of requests
# for request restrictions, or number of bytes for media restrictions.
burst_capacity = <integer for requests/byte-size for media>
# The timeframe, with either seconds, minutes, hours, or days.
per_<second/minute/hour/day> = <integer for requests/byte-size for media>
When overriding a restriction, both the timeframe and burst capacity must be specified.
Targets
A target is any client that call's Conduit's API endpoints, and are identified by one of the following:
- A user ID
- A Server Name (domain)
- An appservice ID
- An IP address, if it cannot be addressed by any of the above (i.e. the client is not authenticated)
The rate limiting configurations under both target parts allow you to configure how many
resources/requests each unique client can access within the configured timeframe.
For example, while on a small server you might allow for all logged-in users to send out 100 invites
per day between them, you can set a cap of 5 for each individual user, not only so that they can't
use up the entire global cap, but also prevent potential spam from being spread by that user alone.
Request restrictions
Request restrictions are one-to-many mappings to endpoints that have potential for abuse. Like the
overrides mentioned above, they are split into client and federation restrictions.
The configuration format is as follows:
[global.rate_limiting.<client/federation>.<global/target>.<restriction>]
per_<second/minute/hour/day> = <number of requests>
burst_capacity = <number of requests>
# Examples:
[global.rate_limiting.client.target.registration]
per_hour = 1
burst_capacity = 4
[global.rate_limiting.federation.target.invite]
burst_capacity = 15
per_minute = 2
[global.rate_limiting.client.global.media_download]
per_second = 1
burst_capacity = 50
Each possible request <restriction> is listed below:
Client
Applies for endpoints on the client-server API, which are used by clients, appservices, and
bots. Appservices can bypass rate-limiting though if rate_limited is set to false in their
registration file.
registration
For registering a new user account. May be called multiples times for a single registration if there are extra steps, e.g. providing a registration token.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per day | 20 requests | 3 requests per day | 10 requests |
private_medium | 20 requests per day | 20 requests | 3 requests per day | 10 requests |
public_medium | 5 requests per hour | 20 requests | 3 requests per day | 10 requests |
public_large | 4 requests per minute | 25 requests | 3 requests per day | 10 requests |
login
For logging into an existing account.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per hour | 10 requests | 5 requests per day | 20 requests |
private_medium | 25 requests per hour | 15 requests | 5 requests per day | 20 requests |
public_medium | 25 requests per hour | 15 requests | 5 requests per day | 20 requests |
public_large | 10 requests per minute | 25 requests | 5 requests per day | 20 requests |
registration_token_validity
For checking whether a given registration token would allow the user to register an account.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per day | 20 requests | 10 requests per day | 20 requests |
private_medium | 20 requests per day | 20 requests | 10 requests per day | 20 requests |
public_medium | 1 requests per day | 1 requests | 10 requests per day | 20 requests |
public_large | 1 requests per day | 1 requests | 10 requests per day | 20 requests |
send_event
For sending an event to a room.
Note that this is not used for state events, but for users who are unprivliged in a room, the only state event they'll be able to send are ones to update their room profile.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 2 requests per second | 100 requests | 15 requests per minute | 60 requests |
private_medium | 10 requests per second | 100 requests | 15 requests per minute | 60 requests |
public_medium | 10 requests per second | 100 requests | 15 requests per minute | 60 requests |
public_large | 100 requests per second | 50 requests | 15 requests per minute | 60 requests |
join
For joining a room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 1 requests per minute | 30 requests | 5 requests per hour | 30 requests |
private_medium | 5 requests per minute | 30 requests | 5 requests per hour | 30 requests |
public_medium | 5 requests per minute | 30 requests | 5 requests per hour | 30 requests |
public_large | 1 requests per second | 20 requests | 5 requests per hour | 30 requests |
invite
For inviting a user to a room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per hour | 20 requests | 2 requests per hour | 20 requests |
private_medium | 1 requests per minute | 20 requests | 2 requests per hour | 20 requests |
public_medium | 1 requests per minute | 20 requests | 2 requests per hour | 20 requests |
public_large | 10 requests per minute | 40 requests | 2 requests per hour | 20 requests |
knock
For knocking on a room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 1 requests per minute | 30 requests | 5 requests per hour | 30 requests |
private_medium | 5 requests per minute | 30 requests | 5 requests per hour | 30 requests |
public_medium | 5 requests per minute | 30 requests | 5 requests per hour | 30 requests |
public_large | 1 requests per second | 20 requests | 5 requests per hour | 30 requests |
send_report
For reporting a user, event, or room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 1 requests per hour | 25 requests | 5 requests per day | 20 requests |
private_medium | 10 requests per hour | 25 requests | 5 requests per day | 20 requests |
public_medium | 10 requests per hour | 25 requests | 5 requests per day | 20 requests |
public_large | 5 requests per minute | 25 requests | 5 requests per day | 20 requests |
create_alias
For adding an alias to a room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 5 requests per hour | 20 requests | 2 requests per day | 20 requests |
private_medium | 1 requests per minute | 50 requests | 2 requests per day | 20 requests |
public_medium | 1 requests per minute | 50 requests | 2 requests per day | 20 requests |
public_large | 30 requests per minute | 20 requests | 2 requests per day | 20 requests |
media_download
For downloading a media file.
For rate-limiting based on the size of files downloaded, see the media rate-limiting configuration.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 5 requests per minute | 150 requests | 30 requests per hour | 100 requests |
private_medium | 1 requests per second | 200 requests | 30 requests per hour | 100 requests |
public_medium | 1 requests per second | 200 requests | 30 requests per hour | 100 requests |
public_large | 25 requests per second | 200 requests | 30 requests per hour | 100 requests |
media_create
For uploading a media file.
For rate-limiting based on the size of files uploaded, see the media rate-limiting configuration.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 20 requests per minute | 50 requests | 4 requests per minute | 20 requests |
private_medium | 2 requests per second | 20 requests | 4 requests per minute | 20 requests |
public_medium | 2 requests per second | 20 requests | 4 requests per minute | 20 requests |
public_large | 10 requests per second | 30 requests | 4 requests per minute | 20 requests |
authentication_failures
This request restriction is a bit different from the previous ones. This one only starts to have it's capacity used if authenticated requests are made with an invalid authentictation token.
This may happen non-maliciously, e.g. when a device is logged out. But a bad actor can keep making requests with random values as the authentication tokens until one of them are found to be valid. This restriction prevents that by preventing all authenticated (client) requests while this limit is exceeded.
Because of this, this restriction cannot be applied globally, only per-target, because an exceeded global limit would prevent all global requests, which can be exploited.
Defaults:
| Preset | Target Timeframe | Target Burst Capacity |
|---|---|---|
private_small | 1 requests per hour | 20 requests |
private_medium | 10 requests per hour | 20 requests |
public_medium | 10 requests per hour | 20 requests |
public_large | 1 requests per minute | 20 requests |
Federation
Applies for endpoints on the federation API of this server, hence restricting how many times other servers can use these endpoints on this server in a given timeframe.
join
For joining a room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per minute | 10 requests | 10 requests per hour | 10 requests |
private_medium | 25 requests per minute | 25 requests | 30 requests per hour | 10 requests |
public_medium | 25 requests per minute | 25 requests | 30 requests per hour | 10 requests |
public_large | 1 requests per second | 50 requests | 90 requests per hour | 30 requests |
knock
For knocking on a room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per minute | 10 requests | 10 requests per hour | 10 requests |
private_medium | 25 requests per minute | 25 requests | 30 requests per hour | 10 requests |
public_medium | 25 requests per minute | 25 requests | 30 requests per hour | 10 requests |
public_large | 1 requests per second | 50 requests | 90 requests per hour | 30 requests |
invite
For inviting a local user to a room.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per minute | 10 requests | 10 requests per hour | 10 requests |
private_medium | 25 requests per minute | 25 requests | 30 requests per hour | 10 requests |
public_medium | 25 requests per minute | 25 requests | 30 requests per hour | 10 requests |
public_large | 1 requests per second | 50 requests | 90 requests per hour | 30 requests |
media_download
For downloading media.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 10 requests per second | 250 requests | 10 requests per minute | 50 requests |
private_medium | 10 requests per second | 100 requests | 100 requests per minute | 50 requests |
public_medium | 10 requests per second | 100 requests | 100 requests per minute | 50 requests |
public_large | 50 requests per second | 100 requests | 100 requests per minute | 50 requests |
Media Restrictions
Media restrictions are used to limit resources used by the media endpoints, by controlling how many bytes can be used in a given timeframe for certain media actions.
Restriction limits are applied such that media requests are allowed if they are below the limit at the time of making the request. Once any restrictions are beyond the permitted limit, media requests of that type will be rejected until the restriction is below the limit again.
The configuration format is as follows:
[global.rate_limiting.<client/federation>.<global/target>.media.<restriction>]
per_<second/minute/hour/day> = <number of bytes>
burst_capacity = <number of bytes>
# Examples:
[global.rate_limiting.client.target.media.upload]
per_day = "150MB"
burst_capacity = "0.5GB"
[global.rate_limiting.federation.global.media.download]
burst_capacity = "5GB"
per_hour = "15GB"
[global.rate_limiting.client.global.media.fetch]
per_minute = "8000B"
burst_capacity = "250MB"
The format for both fields is specified by ByteSize (e.g. "10000MB", "15GiB", "1.5TB", etc.)
Client
download
This restriction is applied whenever a client downloads media from the server.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 250.0 MB per minute | 100.0 MB | 100.0 MB per minute | 50.0 MB |
private_medium | 500.0 MB per minute | 200.0 MB | 100.0 MB per minute | 50.0 MB |
public_medium | 500.0 MB per minute | 200.0 MB | 100.0 MB per minute | 50.0 MB |
public_large | 2.0 GB per minute | 500.0 MB | 100.0 MB per minute | 50.0 MB |
upload
This restriction is applied whenever a client uploads media to the server.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 50.0 MB per minute | 100.0 MB | 10.0 MB per minute | 100.0 MB |
private_medium | 100.0 MB per minute | 200.0 MB | 10.0 MB per minute | 100.0 MB |
public_medium | 100.0 MB per minute | 200.0 MB | 10.0 MB per minute | 100.0 MB |
public_large | 500.0 MB per minute | 500.0 MB | 10.0 MB per minute | 100.0 MB |
fetch
In addition to the download, the fetch restriction is also applied when the media that
a client has downloaded was had to be fetched from a remote server, due to it not already
being stored.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 250.0 MB per minute | 100.0 MB | 100.0 MB per minute | 50.0 MB |
private_medium | 500.0 MB per minute | 200.0 MB | 100.0 MB per minute | 50.0 MB |
public_medium | 500.0 MB per minute | 200.0 MB | 100.0 MB per minute | 50.0 MB |
public_large | 2.0 GB per minute | 500.0 MB | 100.0 MB per minute | 50.0 MB |
Federation
download
This restriction is applied whenever a remote server downloads media from this server.
Defaults:
| Preset | Global Timeframe | Global Burst Capacity | Target Timeframe | Target Burst Capacity |
|---|---|---|---|---|
private_small | 250.0 MB per minute | 250.0 MB | 100.0 MB per minute | 100.0 MB |
private_medium | 500.0 MB per minute | 500.0 MB | 200.0 MB per minute | 200.0 MB |
public_medium | 500.0 MB per minute | 500.0 MB | 200.0 MB per minute | 200.0 MB |
public_large | 2.0 GB per minute | 1.0 GB | 600.0 MB per minute | 300.0 MB |
Delegation
You can run Conduit on a separate domain than the actual server name (what shows up in user ids, aliases, etc.).
For example you can have your users have IDs such as @foo:example.org and have aliases like #bar:example.org,
while actually having Conduit hosted on the matrix.example.org domain. This is called delegation.
Automatic (recommended)
Conduit has support for hosting delegation files by itself, and by default uses it to serve federation traffic on port 443.
With this method, you need to direct requests to /.well-known/matrix/* to Conduit in your reverse proxy.
This is only recommended if Conduit is on the same physical server as the server which serves your server name (e.g. example.org) as servers don't always seem to cache the response, leading to slower response times otherwise, but it should also work if you are connected to the server running Conduit using something like a VPN.
To configure it, use the following options in the global.well_known table:
| Field | Type | Description | Default |
|---|---|---|---|
client | String | The URL that clients should use to connect to Conduit | https://<server_name> |
server | String | The hostname and port servers should use to connect to Conduit | <server_name>:443 |
Example
[global.well_known]
client = "https://matrix.example.org"
server = "matrix.example.org:443"
Manual
Alternatively you can serve static JSON files to inform clients and servers how to connect to Conduit.
Servers
For servers to discover how to access your domain, serve a response in the following format for /.well-known/matrix/server:
{
"m.server": "matrix.example.org:443"
}
Where matrix.example.org is the domain and 443 is the port Conduit is accessible at.
Clients
For clients to discover how to access your domain, serve a response in the following format for /.well-known/matrix/client:
{
"m.homeserver": {
"base_url": "https://matrix.example.org"
}
}
Where matrix.example.org is the URL Conduit is accessible at.
To ensure that all clients can access this endpoint, it is recommended you set the following headers for this endpoint:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: X-Requested-With, Content-Type, Authorization
Deploying
This chapter describes various ways to deploy Conduit.
Generic deployment documentation
Getting help
If you run into any problems while setting up Conduit, write an email to
conduit@koesters.xyz, ask us in#conduit:ahimsa.chator open an issue on GitLab.
Installing Conduit
Although you might be able to compile Conduit for Windows, we do recommend running it on a Linux server. We therefore only offer Linux binaries.
You may simply download the binary that fits your machine. Run uname -m to see what you need. For arm, you should use aarch. Now copy the appropriate url:
Stable/Main versions:
| Target | Type | Download |
|---|---|---|
x86_64-unknown-linux-musl | Statically linked Debian package | link |
aarch64-unknown-linux-musl | Statically linked Debian package | link |
x86_64-unknown-linux-musl | Statically linked binary | link |
aarch64-unknown-linux-musl | Statically linked binary | link |
x86_64-unknown-linux-gnu | OCI image | link |
aarch64-unknown-linux-musl | OCI image | link |
These builds were created on and linked against the glibc version shipped with Debian bullseye. If you use a system with an older glibc version (e.g. RHEL8), you might need to compile Conduit yourself.
Latest/Next versions:
| Target | Type | Download |
|---|---|---|
x86_64-unknown-linux-musl | Statically linked Debian package | link |
aarch64-unknown-linux-musl | Statically linked Debian package | link |
x86_64-unknown-linux-musl | Statically linked binary | link |
aarch64-unknown-linux-musl | Statically linked binary | link |
x86_64-unknown-linux-gnu | OCI image | link |
aarch64-unknown-linux-musl | OCI image | link |
$ sudo wget -O /usr/local/bin/matrix-conduit <url>
$ sudo chmod +x /usr/local/bin/matrix-conduit
Alternatively, you may compile the binary yourself. First, install any dependencies:
# Debian
$ sudo apt install libclang-dev build-essential
# RHEL
$ sudo dnf install clang
Then, cd into the source tree of conduit-next and run:
$ cargo build --release
Adding a Conduit user
While Conduit can run as any user it is usually better to use dedicated users for different services. This also allows you to make sure that the file permissions are correctly set up.
In Debian or RHEL, you can use this command to create a Conduit user:
sudo adduser --system conduit --group --disabled-login --no-create-home
Forwarding ports in the firewall or the router
Conduit uses the ports 443 and 8448 both of which need to be open in the firewall.
If Conduit runs behind a router or in a container and has a different public IP address than the host system these public ports need to be forwarded directly or indirectly to the port mentioned in the config.
Optional: Avoid port 8448
If Conduit runs behind Cloudflare reverse proxy, which doesn't support port 8448 on free plans, delegation can be set up to have federation traffic routed to port 443:
# .well-known delegation on Apache
<Files "/.well-known/matrix/server">
ErrorDocument 200 '{"m.server": "your.server.name:443"}'
Header always set Content-Type application/json
Header always set Access-Control-Allow-Origin *
</Files>
SRV DNS record delegation is also possible.
Setting up a systemd service
Now we'll set up a systemd service for Conduit, so it's easy to start/stop Conduit and set it to autostart when your
server reboots. Simply paste the default systemd service you can find below into
/etc/systemd/system/conduit.service.
[Unit]
Description=Conduit Matrix Server
After=network.target
[Service]
Environment="CONDUIT_CONFIG=/etc/matrix-conduit/conduit.toml"
User=conduit
Group=conduit
Restart=always
ExecStart=/usr/local/bin/matrix-conduit
[Install]
WantedBy=multi-user.target
Finally, run
$ sudo systemctl daemon-reload
Creating the Conduit configuration file
Now we need to create the Conduit's config file in
/etc/matrix-conduit/conduit.toml. Paste in the contents of
conduit-example.toml and take a moment to read it.
You need to change at least the server name.
You can also choose to use a different database backend, but right now only rocksdb and sqlite are recommended.
Setting the correct file permissions
As we are using a Conduit specific user we need to allow it to read the config. To do that you can run this command on Debian or RHEL:
sudo chown -R root:root /etc/matrix-conduit
sudo chmod 755 /etc/matrix-conduit
If you use the default database path you also need to run this:
sudo mkdir -p /var/lib/matrix-conduit/
sudo chown -R conduit:conduit /var/lib/matrix-conduit/
sudo chmod 700 /var/lib/matrix-conduit/
Setting up the Reverse Proxy
This depends on whether you use Apache, Caddy, Nginx or another web server.
Apache
Create /etc/apache2/sites-enabled/050-conduit.conf and copy-and-paste this:
# Requires mod_proxy and mod_proxy_http
#
# On Apache instance compiled from source,
# paste into httpd-ssl.conf or httpd.conf
Listen 8448
<VirtualHost *:443 *:8448>
ServerName your.server.name # EDIT THIS
AllowEncodedSlashes NoDecode
ProxyPass /_matrix/ http://127.0.0.1:6167/_matrix/ timeout=300 nocanon
ProxyPassReverse /_matrix/ http://127.0.0.1:6167/_matrix/
</VirtualHost>
You need to make some edits again. When you are done, run
# Debian
$ sudo systemctl reload apache2
# Installed from source
$ sudo apachectl -k graceful
Caddy
Create /etc/caddy/conf.d/conduit_caddyfile and enter this (substitute for your server name).
your.server.name, your.server.name:8448 {
reverse_proxy /_matrix/* 127.0.0.1:6167
}
That's it! Just start or enable the service and you're set.
$ sudo systemctl enable caddy
Nginx
If you use Nginx and not Apache, add the following server section inside the http section of /etc/nginx/nginx.conf
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen 8448 ssl http2;
listen [::]:8448 ssl http2;
server_name your.server.name; # EDIT THIS
merge_slashes off;
# Nginx defaults to only allow 1MB uploads
# Increase this to allow posting large files such as videos
client_max_body_size 20M;
location /_matrix/ {
proxy_pass http://127.0.0.1:6167;
proxy_set_header Host $host;
proxy_buffering off;
proxy_read_timeout 5m;
}
ssl_certificate /etc/letsencrypt/live/your.server.name/fullchain.pem; # EDIT THIS
ssl_certificate_key /etc/letsencrypt/live/your.server.name/privkey.pem; # EDIT THIS
ssl_trusted_certificate /etc/letsencrypt/live/your.server.name/chain.pem; # EDIT THIS
include /etc/letsencrypt/options-ssl-nginx.conf;
}
You need to make some edits again. When you are done, run
$ sudo systemctl reload nginx
SSL Certificate
If you chose Caddy as your web proxy SSL certificates are handled automatically and you can skip this step.
The easiest way to get an SSL certificate, if you don't have one already, is to install certbot and run this:
# To use ECC for the private key,
# paste into /etc/letsencrypt/cli.ini:
# key-type = ecdsa
# elliptic-curve = secp384r1
$ sudo certbot -d your.server.name
Automated renewal is usually preconfigured.
If using Cloudflare, configure instead the edge and origin certificates in dashboard. In case you’re already running a website on the same Apache server, you can just copy-and-paste the SSL configuration from your main virtual host on port 443 into the above-mentioned vhost.
You're done!
Now you can start Conduit with:
$ sudo systemctl start conduit
Set it to start automatically when your system boots with:
$ sudo systemctl enable conduit
How do I know it works?
You can open a Matrix client, enter your homeserver and try to register. If you are using a registration token, use Element web, Nheko or SchildiChat web, as they support this feature.
You can also use these commands as a quick health check.
$ curl https://your.server.name/_matrix/client/versions
# If using port 8448
$ curl https://your.server.name:8448/_matrix/client/versions
- To check if your server can talk with other homeservers, you can use the Matrix Federation Tester. If you can register but cannot join federated rooms check your config again and also check if the port 8448 is open and forwarded correctly.
What's next?
Audio/Video calls
For Audio/Video call functionality see the TURN Guide.
Appservices
If you want to set up an appservice, take a look at the Appservice Guide.
Conduit for Debian
Installation
Information about downloading, building and deploying the Debian package, see the "Installing Conduit" section in the Deploying docs. All following sections until "Setting up the Reverse Proxy" be ignored because this is handled automatically by the packaging.
Configuration
When installed, Debconf generates the configuration of the homeserver
(host)name, the address and port it listens on. This configuration ends up in
/etc/matrix-conduit/conduit.toml.
You can tweak more detailed settings by uncommenting and setting the variables
in /etc/matrix-conduit/conduit.toml. This involves settings such as the maximum
file size for download/upload, enabling federation, etc.
Running
The package uses the matrix-conduit.service systemd unit file to start and
stop Conduit. It loads the configuration file mentioned above to set up the
environment before running the server.
This package assumes by default that Conduit will be placed behind a reverse
proxy such as Apache or nginx. This default deployment entails just listening
on 127.0.0.1 and the free port 6167 and is reachable via a client using the URL
http://localhost:6167.
At a later stage this packaging may support also setting up TLS and running stand-alone. In this case, however, you need to set up some certificates and renewal, for it to work properly.
Conduit for Docker
Note: To run and use Conduit you should probably use it with a Domain or Subdomain behind a reverse proxy (like Nginx, Traefik, Apache, ...) with a Lets Encrypt certificate.
Docker
To run Conduit with Docker you can either build the image yourself or pull it from a registry.
Use a registry
OCI images for Conduit are available in the registries listed below. We recommend using the image tagged as latest from GitLab's own registry.
| Registry | Image | Size | Notes |
|---|---|---|---|
| GitLab Registry | registry.gitlab.com/famedly/conduit/matrix-conduit:latest | Stable image. | |
| Docker Hub | docker.io/matrixconduit/matrix-conduit:latest | Stable image. | |
| GitLab Registry | registry.gitlab.com/famedly/conduit/matrix-conduit:next | Development version. | |
| Docker Hub | docker.io/matrixconduit/matrix-conduit:next | Development version. |
Use
docker image pull <link>
to pull it to your machine.
Build using a dockerfile
The Dockerfile provided by Conduit has two stages, each of which creates an image.
- Builder: Builds the binary from local context or by cloning a git revision from the official repository.
- Runner: Copies the built binary from Builder and sets up the runtime environment, like creating a volume to persist the database and applying the correct permissions.
To build the image you can use the following command
docker build --tag matrixconduit/matrix-conduit:latest .
which also will tag the resulting image as matrixconduit/matrix-conduit:latest.
Run
When you have the image you can simply run it with
docker run -d -p 8448:6167 \
-v db:/var/lib/matrix-conduit/ \
-e CONDUIT_SERVER_NAME="your.server.name" \
-e CONDUIT_DATABASE_BACKEND="rocksdb" \
-e CONDUIT_ALLOW_REGISTRATION=true \
-e CONDUIT_ALLOW_FEDERATION=true \
-e CONDUIT_MAX_REQUEST_SIZE="20000000" \
-e CONDUIT_TRUSTED_SERVERS="[\"matrix.org\"]" \
-e CONDUIT_MAX_CONCURRENT_REQUESTS="100" \
-e CONDUIT_PORT="6167" \
--name conduit <link>
or you can use docker compose.
The -d flag lets the container run in detached mode. You now need to supply a conduit.toml config file, an example can be found here.
You can pass in different env vars to change config values on the fly. You can even configure Conduit completely by using env vars, but for that you need
to pass -e CONDUIT_CONFIG="" into your container. For an overview of possible values, please take a look at the docker-compose.yml file.
If you just want to test Conduit for a short time, you can use the --rm flag, which will clean up everything related to your container after you stop it.
Docker compose
If the docker run command is not for you or your setup, you can also use one of the provided docker compose files.
Depending on your proxy setup, you can use one of the following files;
- If you already have a
traefikinstance set up, usedocker-compose.for-traefik.yml - If you don't have a
traefikinstance set up (or any other reverse proxy), usedocker-compose.with-traefik.yml - For any other reverse proxy, use
docker-compose.yml
When picking the traefik-related compose file, rename it so it matches docker-compose.yml, and
rename the override file to docker-compose.override.yml. Edit the latter with the values you want
for your server.
Additional info about deploying Conduit can be found here.
Build
To build the Conduit image with docker compose, you first need to open and modify the docker-compose.yml file. There you need to comment the image: option and uncomment the build: option. Then call docker compose with:
docker compose up
This will also start the container right afterwards, so if want it to run in detached mode, you also should use the -d flag.
Run
If you already have built the image or want to use one from the registries, you can just start the container and everything else in the compose file in detached mode with:
docker compose up -d
Note: Don't forget to modify and adjust the compose file to your needs.
Use Traefik as Proxy
As a container user, you probably know about Traefik. It is a easy to use reverse proxy for making
containerized app and services available through the web. With the two provided files,
docker-compose.for-traefik.yml (or
docker-compose.with-traefik.yml) and
docker-compose.override.yml, it is equally easy to deploy
and use Conduit, with a little caveat. If you already took a look at the files, then you should have
seen the well-known service, and that is the little caveat. Traefik is simply a proxy and
loadbalancer and is not able to serve any kind of content, but for Conduit to federate, we need to
either expose ports 443 and 8448 or serve two endpoints .well-known/matrix/client and
.well-known/matrix/server.
With the service well-known we use a single nginx container that will serve those two files.
So...step by step:
-
Copy
docker-compose.for-traefik.yml(ordocker-compose.with-traefik.yml) anddocker-compose.override.ymlfrom the repository and remove.for-traefik(or.with-traefik) from the filename. -
Open both files and modify/adjust them to your needs. Meaning, change the
CONDUIT_SERVER_NAMEand the volume host mappings according to your needs. -
Create the
conduit.tomlconfig file, an example can be found here, or setCONDUIT_CONFIG=""and configure Conduit per env vars. -
Uncomment the
element-webservice if you want to host your own Element Web Client and create aelement_config.json. -
Create the files needed by the
well-knownservice.-
./nginx/matrix.conf(relative to the compose file, you can change this, but then also need to change the volume mapping)server { server_name <SUBDOMAIN>.<DOMAIN>; listen 80 default_server; location /.well-known/matrix/server { return 200 '{"m.server": "<SUBDOMAIN>.<DOMAIN>:443"}'; types { } default_type "application/json; charset=utf-8"; } location /.well-known/matrix/client { return 200 '{"m.homeserver": {"base_url": "https://<SUBDOMAIN>.<DOMAIN>"}}'; types { } default_type "application/json; charset=utf-8"; add_header "Access-Control-Allow-Origin" *; } location / { return 404; } }
-
-
Run
docker compose up -d -
Connect to your homeserver with your preferred client and create a user. You should do this immediately after starting Conduit, because the first created user is the admin.
Voice communication
In order to make or receive calls, a TURN server is required. Conduit suggests using Coturn for this purpose, which is also available as a Docker image. Before proceeding with the software installation, it is essential to have the necessary configurations in place.
Configuration
Create a configuration file called coturn.conf containing:
use-auth-secret
static-auth-secret=<a secret key>
realm=<your server domain>
A common way to generate a suitable alphanumeric secret key is by using pwgen -s 64 1.
These same values need to be set in conduit. You can either modify conduit.toml to include these lines:
turn_uris = ["turn:<your server domain>?transport=udp", "turn:<your server domain>?transport=tcp"]
turn_secret = "<secret key from coturn configuration>"
or append the following to the docker environment variables depending on which configuration method you used earlier:
CONDUIT_TURN_URIS: '["turn:<your server domain>?transport=udp", "turn:<your server domain>?transport=tcp"]'
CONDUIT_TURN_SECRET: "<secret key from coturn configuration>"
Restart Conduit to apply these changes.
Run
Run the Coturn image using
docker run -d --network=host -v $(pwd)/coturn.conf:/etc/coturn/turnserver.conf coturn/coturn
or docker compose. For the latter, paste the following section into a file called docker-compose.yml
and run docker compose up -d in the same directory.
version: 3
services:
turn:
container_name: coturn-server
image: docker.io/coturn/coturn
restart: unless-stopped
network_mode: "host"
volumes:
- ./coturn.conf:/etc/coturn/turnserver.conf
To understand why the host networking mode is used and explore alternative configuration options, please visit the following link: https://github.com/coturn/coturn/blob/master/docker/coturn/README.md. For security recommendations see Synapse's Coturn documentation.
Conduit for NixOS
Conduit 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 Nixpkgs
The flake.nix and default.nix do not (currently) provide a NixOS module, so
(for now) services.matrix-conduit from Nixpkgs should be used to
configure Conduit.
If you want to run the latest code, you should get Conduit from the flake.nix
or default.nix and set services.matrix-conduit.package
appropriately.
Administration
This chapter describes how to perform tasks you may want to do while running Conduit
Media
While running Conduit, you may encounter undesirable media, either from other servers, or from local users.
From other servers
If the media originated from a different server, which itself is not malicious, it should be enough
to use the purge-media-from-server command to delete the media from the media backend, and then
contact the remote server so that they can deal with the offending user(s).
If you do not need to media deleted as soon as possible, you can use retention policies to only store remote media for a short period of time, meaning that the media will be automatically deleted after some time. As new media can only be accessed over authenticated endpoints, only local users will be able to access the media via your server, so if you're running a single-user server, you don't need to worry about the media being distributed via your server.
If you know the media IDs, (which you can find with the list-media command), you can use the
block-media to prevent any of those media IDs (or other media with the same SHA256 hash) from
being stored in the media backend in the future.
If the server itself if malicious, then it should probably be ACLed in rooms it particpates in. In the future, you'll be able to block the remote server from interacting with your server completely.
From local users
If the undesirable media originates from your own server, you can purge media uploaded by them
using the purge-media-from-users command. If you also plan to deactivate the user, you can do so
with the --purge-media flag on either the deactivate-user or deactivate-all commands. If
they keep making new accounts, you can use the block-media-from-users command to prevent media
with the same SHA256 hash from being uploaded again, as well as using the allow-registration
command to temporarily prevent users from creating new accounts.
Setting up TURN/STUN
General instructions
- It is assumed you have a Coturn server up and running. See Synapse reference implementation.
Edit/Add a few settings to your existing conduit.toml
[global.turn]
# Refer to your Coturn settings.
# `your.turn.url` has to match the REALM setting of your Coturn as well as `transport`.
uris = ["turn:your.turn.url?transport=udp", "turn:your.turn.url?transport=tcp"]
# static-auth-secret of your turnserver
secret = "ADD SECRET HERE"
# If you have your TURN server configured to use a username and password
# you can provide these information too. In this case comment out `turn_secret above`!
#username = ""
#password = ""
Apply settings
Restart Conduit.
Setting up Appservices
Getting help
If you run into any problems while setting up an Appservice, write an email to timo@koesters.xyz, ask us in #conduit:ahimsa.chat or open an issue on GitLab.
Set up the appservice - general instructions
Follow whatever instructions are given by the appservice. This usually includes downloading, changing its config (setting domain, homeserver url, port etc.) and later starting it.
At some point the appservice guide should ask you to add a registration yaml file to the homeserver. In Synapse you would do this by adding the path to the homeserver.yaml, but in Conduit you can do this from within Matrix:
First, go into the #admins room of your homeserver. The first person that registered on the homeserver automatically joins it. Then send a message into the room like this:
@conduit:your.server.name: register-appservice
```
paste
the
contents
of
the
yaml
registration
here
```
You can confirm it worked by sending a message like this:
@conduit:your.server.name: list-appservices
The @conduit bot should answer with Appservices (1): your-bridge
Then you are done. Conduit will send messages to the appservices and the appservice can send requests to the homeserver. You don't need to restart Conduit, but if it doesn't work, restarting while the appservice is running could help.
Appservice-specific instructions
Remove an appservice
To remove an appservice go to your admin room and execute
@conduit:your.server.name: unregister-appservice <name>
where <name> one of the output of list-appservices.
Tested appservices
These appservices have been tested and work with Conduit without any extra steps:
- matrix-appservice-discord
- mautrix-hangouts
- mautrix-telegram
- mautrix-signal from version
0.2.2forward. - heisenbridge
FAQ
Here are some of the most frequently asked questions about Conduit, and their answers.
Why do I get a M_INCOMPATIBLE_ROOM_VERSION error when trying to join some rooms?
Conduit doesn't support room versions 1 and 2 at all, and doesn't properly support versions 3-5 currently. You can track the progress of adding support here.
How do I backup my server?
To backup your Conduit server, it's very easy. You can simply stop Conduit, make a copy or file system snapshot of the database directory, then start Conduit again.
Note: When using a file system snapshot, it is not required that you stop the server, but it is still recommended as it is the safest option and should ensure your database is not left in an inconsistent state.
How do I setup simplified sliding sync?
You don't need to! If your Conduit instance is reachable, simplified sliding sync should work right out of the box, no delegation required
Can I migrate from Synapse to Conduit?
Not really. You can reuse the domain of your current server with Conduit, but you will not be able to migrate accounts automatically. Rooms that were federated can be re-joined via the other participating servers, however media and the like may be deleted from remote servers after some time, and hence might not be recoverable.
How do I make someone an admin?
Simply invite them to the admin room. Once joined, they can administer the server by interacting with the @conduit:<server_name> user.