Document: WM-067 P. Webb
Category: Self Hosting 2025.04.25
Enter the Matrix
Abstract
When all else fails, DIY!
Body
When Element decided to change their cloud hosting pricing last year,
I had a decision to make; pay more money[1] 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 SwissTransfer[2]
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 Conduit[3] 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 Sync[4] 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.
1. 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 script[6],
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
}
}
2. Install Element
Getting Elememt installed[8] 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.