Files
blog/content/blog/2026-10-05-matrix-is-a-pain.md

9.2 KiB

title, date, draft, description
title date draft description
Matrix is a pain 2026-10-05T14:37:00 false you read the title

Matrix in general

Most chat platforms have one signing server, which if you think about it is like the internet having one dns server. If discord goes down, you're kinda fucked. Matrix solves this through communism.

Homeservers and awayservers

Homeservers are just servers. On servers you can host users and rooms, and through special properties, rooms can be voice chats or spaces. Pretty simple stuff. The biggest one is, obviously, matrix.org, because signing up is free. Matrix.org also allows free hosting for spaces, the equivalent of discord servers in this context. Spaces are just rooms with special parameters, but we can get to that in a minute. Finally, matrix.org manages federation with other servers. Federation can be oversimplified into lots of encrypted API calls that result in profile information and messages being validated and fetched from a remote homeserver.

Using the given certificate, there is a mutual understanding between different homeservers that as long as the cert is right, the enclosed information will be correct as well. Federation used to act over port 8448, resulting in some funky port forwarding, but in matrix 2 and 3, you can make it run in parallel with the http api, only on port 443. This also lets federation leverage ssl instead of dodgy round robin encryption, making man in the middle attacks nearly impossible unless someone manages to steal your private key, not to mention you can run the whole thing behind a reverse proxy.

Matrix as a protocol was initially built to be like IRC, with many public connectable rooms and no real worry about impersonation or chat history. Discord then started being shit, meaning there was a demand for an end to end encrypted decentralised chat network that somehow managed to maintain some level of identity. Hence, the whole protocol was rebuilt and iterated on to be what it is today

Running Matrix

As usual with apps, there is a server and a client. The officially maintained server is called synapse (who knows why), and is runnable as a docker container fairly easily. Of course, I have to jump through a bunch of nix shaped hoops to get it to work, but other than that I had a server "running" that I could log into almost immediately. However, when DNS is involved, nothing is ever easy.

First of all, federation requests don't work through cloudflare's esoteric proxy bullshit, so you have to be on DNS only. Its not as if anyone can hack me, but if you wanted to get a pretty accurate location of where I live, you can do that now I guess. Then there's the not-so-obvious server settings that are basically required if you want anything to work, dynamic_thumbnails = true being necessary if you have any icons ever.

WE HATE DNS

Beyond that, you have to set headers for the actual domain, and if you don't want to reserve your main url for matrix and matrix only, you have to include .well-known path nonsense. Here's the config for anyone interested:

location = /.well-known/matrix/server {
    default_type application/json;
    add_header Access-Control-Allow-Origin "*" always;
    return 200 '{"m.server":"matrix.voidarc.co.uk:443"}';
}
location = /.well-known/matrix/client {
    default_type application/json;
    add_header Access-Control-Allow-Origin "*" always;
    return 200 '{"m.homeserver":{"base_url":"https://matrix.voidarc.co.uk"}}';
}

BOTH paths are required for any modern client to be able to federate. In the docs they list the second path as unnecessary, but almost no modern client will accept federation unless the second path is present. At most, with only the server address, you can get private messaging, but you won't be able to join any rooms or let people join any rooms on your server.

Just for completeness, this is the header config for the actual matrix domain. This domain should proxy pass to whatever endpoint hosts the /_matrix/ path.

client_max_body_size 100M;

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_set_header Access-Control-Allow-Origin: *;

Important also to note that a generic cloudflare origin cert (like the default *.example.com, example.com cert with an origin CA) will NOT work for matrix. Most other homeservers will ping your server, and then refuse to accept the return packet with a 402 or something because it hasn't been signed against by the actual FQDN. This is simple enough to fix with letsencrypt, just make sure the cert has the same address as whatever you put as the public address in synapse's config file.

Clients and you

Matrix is a protocol, not a product. That means anyone can make a new way of interfacing with the protocol, ie a client, and use that to communicate with any other client. It's as simple as that.

Synapse is just the server, it provides the protocol endpoints needed to use matrix, but no actual user-facing interface. To actually message people, you need a client. Once again, the most popular is whatever matrix.org recommends, and that happens to be element. Element is shit, imo. It looks bad, it's bloated, and the desktop version is just a glorified webapp. It also requires either hosting a really heavy service yourself, or relying on someone else's server to stay up. Both pointless options if you want to be decentralised.

The best clients are fully local, and the most minimal is iamb. Vim bindings, fully tui, no mouse support whatsoever. It's what I choose to use in my config, so I have to glaze it. Then there are more esoteric options, like commet, which has a great mobile client, mirroring that of old school discord, but uses literally the same ui on desktop for some reason. It also does some funky shit when it comes to authentication and cross signing, and has very nearly deleted all my devices' authentication a few times. I should probably explain cross signing now, huh?

Cross signing is also a pain

I didn't know about cross signing when I first use matrix, because there was literally nothing saying you had to be careful about it. As I said, matrix supports end to end encryption (e2ee from here), which means that you need some way to encrypt the messages end to end. Take whatsapp as an example, your signing keys are held permanently on the mobile app, and when you link a device, that device gets access to your keys, so you can read your messages. These keys are also the reason that it's a pain in the ass to move whatsapp to a new device, no matter how many wizards they present you with, and also why you can't log into whatsapp on multiple phones at once. I'm safe in assuming that whatsapp rotates the keys regularly, on a local timer, and then presents whoever you're messaging with the public key, and, to prevent sending the pubkey with every message, gives the pubkey an expiry matching up with when the next key swap is. This is what's known in the DNS world as a TTL, or time to live. If another device logged in as the same user was using an old key, no messages sent from that device would be able to be decrypted by the recipient, and no sent messages would be able to be read either.

You can think of the primary logged in device as the "root device", acting as the source of truth for all other logged in devices. When you first log in, most clients will ask you to verify. You put in a passkey and out comes a shiny recovery key that you will almost certainly lose or forget about. If you've ever used a crypto wallet, it's the same concept. If you forget your password, you have an absolute way to get all your money back, just that instead of money it's messages. The difference here is that only the session that gave you the recovery key, or any sessions verified against it, will accept that recovery key. If you log out of your root session without verifying any other devices, all the encrypted messages sent from that client basically just vanish.

You verify all other devices through the root device, and if you log out of the root device, you can choose another root device by putting the recovery key into another device that was previously verified. Simple, right? This song and dance of root devices and ssl is how matrix manages to keep authenticity, unlike irc which was almost completely anonymous, while also not needing a user to hand over their email to some big company if they don't want to. Just don't log out of your root device, or at the very least, remember which device that even is. (I dont remember mine)

The only downside of this mutual verification nonsense is that the keys can't be rotated nearly as easily. Of course, modern SSL kind of removes the need for that, but if you wanted to rotate your keys, it would take far more effort than literally any other chat platform.

Decentralised Moral of the story

Matrix is a pain in the ass, but if you aren't hosting it yourself, it's a great way to talk to other people that also don't like big evil companies.

I don't like big evil companies!! Text me at @admin:voidarc.co.uk

Also join the voidarc official matrix server at #space:voidarc.co.uk. You know how it works, you deserve it. If you join through this, tell me so that I know people actually read this blog lol. Byee