Enter the Matrix

When Element decided to change their cloud hosting pricing last year, I had a decision to make; pay more money1 per user on my account (€60 per user/year, paid annually), setup my own server using Synapse (the only Matrix software that was out at the time), or go with some third‑party. Synapse was hella complicated to deal with so I decided to go with the latter.

Long story short, this third‑party (Federated Computer) is not good. Just this past weekend, they performed an unannounced server upgrade which broke my instance and I was gaslit by someone on their support team until I mentioned I only experienced issues over the weekend.

They refused to answer my very direct question ("how can I export my data?") three times before pointing me to the room chat export feature of Element, which was not what I asked for. EMS (Element Matrix Services) provided everyone on their platform with a dashboard where they could export the database and other files necessary to import to a new host. When I approached FC (who were listed as hosts recommended by EMS), they instructed me to upload to SwissTransfer2 so they could concierge the process.

You'd think the folks at Federated Computer would remember/understand that, no?

They've also got quite the lackluster dashboard UI. I've designed better when I got my start coding in 2008. Anyhoo, YMMV but FC is not for me. This experience was enough impetus to explore if the Matrix self‑host landscape changed and luckily, it has!

After some quick research, I decided to go with Conduit3 as my Matrix server. It's written in Rust, is in beta at the time of this post, and its instructions are slightly wrong so I'm writing this post for future me and friends.

Before I get into it, a few things:

Sliding Sync4 is not implemented yet. The fancy Element X client uses it for quick syncing of Matrix rooms and I wanna use it.

I asked about SS in Conduit's Matrix room:

The current sliding sync implementation is not working as we need simple sliding sync now. And that is not ready in conduit yet.

The developer leading this feature has said it is high on his list of priorities.

Also, when I invited my friends to my new server I wasn't able to see their messages decrypted, even after verifying my sessions. I still can't see those initial messages but the syncing has been fine for the past few days so maybe that was just some setup weirdness.

Installing Conduit

I'll assume you're installing Conduit on Linux. I prefer Ubuntu LTS for my servers. The Conduit install tutorial gives you three types of binaries to install: statically linked Debian package, statically linked binary, and OCI image.

I didn't realize the Debian package didn't work for me until much later. The statically linked binary worked though. Unless you are on an ARM platform, you should choose one of the x86_64 options. I used x86_64-unknown-linux-musl:

# download binary to your system
wget -O /usr/local/bin/matrix-conduit https://gitlab.com/api/v4/projects/famedly%2Fconduit/jobs/artifacts/master/raw/x86_64-unknown-linux-musl?job=artifacts

# make binary executable
chmod +x /usr/local/bin/matrix-conduit

# add a user that will handle the Conduit process
adduser --system conduit --group --disabled-login --no-create-home

Next, we'll set up the systemd service:

nano /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

Reload systemd so it knows about Conduit:

systemctl daemon-reload

Now it's the fun part, creating the Conduit configuration file so you can customize (like increasing the file upload limit past the default 20MB)!

# create directory
mkdir -p /etc/matrix-conduit

nano /etc/matrix-conduit/conduit.toml

The only things I've changed are max_request_size (so I can share gaming clips with my friends, 20MB is NOT enough), enable_lightning_bolt, registration_token, and server_name. I thought I needed to give my friends the token but I just sent invites to their Matrix addresses instead. I wonder if I can set allow_registration to false and still invite people to my server…

[global]
# This makes sure Conduit can only be reached using the reverse proxy
address = "127.0.0.1"

allow_check_for_updates = true
allow_federation = true

# Enables registration. If set to false, no users can register on this server.
allow_registration = true

database_backend = "rocksdb"

# This is the only directory where Conduit will save its data
database_path = "/var/lib/matrix-conduit/"

# Enable the display name lightning bolt on registration.
enable_lightning_bolt = false

# Max size for uploads in bytes (100MB)
max_request_size = 100_000_000

# 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
port = 6167

# 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 = "your-generated-token"

server_name = "matrix.webb.page"

# Servers listed here will be used to gather public keys of other servers.
trusted_servers = ["matrix.org"]

Now we've gotta set file permissions. Almost done!

chown -R root:root /etc/matrix-conduit

chmod 755 /etc/matrix-conduit

# gotta make more directories
mkdir -p /var/lib/matrix-conduit/

chown -R conduit:conduit /var/lib/matrix-conduit/

chmod 700 /var/lib/matrix-conduit/

I already had Caddy setup from my new server install script6, but here's the relevant portion:

apt install debian-keyring debian-archive-keyring apt-transport-https curl -y

curl -1sLf "https://dl.cloudsmith.io/public/caddy/stable/gpg.key" | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

curl -1sLf "https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt" | tee /etc/apt/sources.list.d/caddy-stable.list

apt update -y

apt install caddy -y

The Conduit tutorial mentions making a particular directory for the Caddy config but that didn't work for me. Instead, do this:

nano /etc/caddy/Caddyfile

Obviously you'll swap my domains for yours.

matrix.webb.page, matrix.webb.page:8448 {
reverse_proxy /_matrix/* 127.0.0.1:6167
}

Reload Caddy and enable Conduit!

service caddy reload

systemctl start conduit

systemctl enable conduit

To ensure your Matrix server works, run these locally (not on your server). Oh, and if you don't have jq 7 installed…why not? Just remove "| jq" to get raw JSON (jq is a pretty formatter).

curl https://matrix.webb.page/_matrix/client/versions | jq

# if using port 8448
curl https://matrix.webb.page:8448/_matrix/client/versions | jq

Your response should look like this:

{
"versions": [
"r0.5.0",
"r0.6.0",
"v1.1",
"v1.2",
"v1.3",
"v1.4",
"v1.5"
],
"unstable_features": {
"org.matrix.e2e_cross_signing": true,
"org.matrix.msc3916.stable": true
}
}

Install Element

Getting Elememt installed8 is quite simple.

apt install -y wget apt-transport-https

wget -O /usr/share/keyrings/element-io-archive-keyring.gpg https://packages.element.io/debian/element-io-archive-keyring.gpg

echo "deb [signed-by=/usr/share/keyrings/element-io-archive-keyring.gpg] https://packages.element.io/debian/ default main" | sudo tee /etc/apt/sources.list.d/element-io.list

apt update -y

apt install -y element-web

nano /etc/element-web/config.json

Here is the relevant portion that I changed in my Element config:

"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix.webb.page",
"server_name": "webb.page"
},
"m.identity_server": {
"base_url": "https://vector.im"
}
},

You're gonna add something new to your Caddyfile as well:

nano /etc/caddy/Caddyfile

# again, swap my domain for yours

element.webb.page {
file_server
root * /usr/share/element-web
}

You made another change so refresh Caddy.

service caddy reload

FIN

That should be it! I hope I didn't leave anything out and if I did, you know where to find and correct me. Hope this helps!

🕸️

EDIT: Made my file upload limit 200MB because 100MB wasn't enough. Also learned that you need to close and re‑open your Element client so it syncs the new limit. You'd think service conduit restart would actually restart but it seems to hang for me…or maybe I'm just impatient so I end up rebooting my server.