Hey Nix-ers,
as per the subject, I’ve been browsing the Wiki and studying Matrix a bit, and I got curious: does anyone have a complete, realistic configuration that includes group audio/video calls with Matrix, from Element web to the various Synapse, Coturn, Livekit services, etc.? Is anyone hosting a full stack or something else with near features parity like XMPP?
I would be interested as well ![]()
I’ve stopped maintaining the calls feature (no longer need it due to… let’s call it changes in social sphere), so that might be defunct, but I have been maintaining a full matrix homeserver for about 6 years.
The stack has moved on a bit, nowadays you’re supposed to self-host livekit for group calls (which used to be unusable IMO, but I’ve seen convincing demonstrations of group calls via livekit), but my config is still running: tlaternet-server/configuration/services/conduit/default.nix at master - tlaternet/tlaternet-server - Forgejo: Beyond coding. We Forge.
The recommended self-host webserver has changed over the years, but at this point I’m very happy with continuwuity (there’s a real module for it too these days, I haven’t migrated yet).
I don’t own apple devices, and have nobody with apple devices to call anymore, so I haven’t been able to verify that TURN with letsencrypt certs works; it used to be that the element phone app refused letsencrypt certs on both iOS and android, so I had a separate certificate for TURN - at least until 2024.
AIUI you want both TURN for element calls (for 1:1) as well as livekit (for group calls) for maximum client/feature/firewall dodging support, but this may be dated knowledge at this point.
Thanks for the super-fast response and the example configuration, I’ve milked much from it!
In the end, I managed to get a usable service (tested for chat and 1:1 calls, they work at least between Element Desktop and Element Classix) with this configuration Paste2.org - Viewing Paste Y3Ocw3vj
TLS Coturn settings no-tlsv1 and no-tlsv1_1 seems (from it’s log) no longer valid, package = pkgs.matrix-continuwuity;hacks does not work for me as well since Conduit look for a /nix/store/.../bin/conduit which is obviously not there, but Tuwunel works.
I still have to try adding Livekit and eventually (to support ElementX client) element-call, both are in Nixpkgs, but without documentation so I have to play a bit. Overall the Matrix experience for me it’s not much nice, but audio/video quality is good enough at least from the limited 1:1 tests I’ve done.
I’ll add the relevant Livekit/element-call configs as soon as I have them working… So far Continuwuity does not works for me, from the log I get Error: There was a problem with your configuration file: duplicate field allow_announcements_check and it’s false, since there is only one entry in the config created by the module and outside user control except setting true or false… Coturn fails to read SSL cert and key because they are readable only by NGINX and I still have to figure a way to show them to both, however it works anyway. I also still have to figure out how to support push notifications for Android/iOS…
Nice to hear it’s somewhat functional, but yeah, setup takes some effort. There are a lot of services involved.
Bridges are yet another step of work, at some point I need to sit down and start scripting full provisioning.
That’d be a bug to report to nixpkgs. I’ll try migrating one of these days, thanks for blazing the trail ![]()
That’ll be because it falls back to unencrypted session creation. Not the end of the world, the actual call is still encrypted, but this does permit seeing who talks to who.
You can see in my config that I deliberately add group permissions to the service to let coturn read keys.
Those are supported out of the box, that’s all app configuration on the target devices. ntfy helps, but it’s been a while since I configured it on iOS.
I guess you’re on unstable? Tuwunel works, but it’s explicitly not intended for production use yet, so I’ve stayed away.
I have been running synapse for a decade but I have never managed to even get normal 1:1 calls to work reliably. If the homeserver and coturn are behind a NAT, apparently no one knows how to do this.
From synapse docs:
Hosting TURN behind NAT requires port forwarding and for the NAT gateway to have a public IP. However, even with appropriate configuration, NAT is known to cause issues and to often not work.
What happened in my case is that either calls randomly didn’t connect, or audio worked one way only. If both peers have IPv6 addresses, then VoIP works fine, but that doesn’t have a snowball’s chance in hell.
I mean, yeah, the point of TURN is kind of to be a bridge between two NATed endpoints by proxying a public IP when needed, if your server itself is behind NAT (and forwarding is unclean) it can’t realistically do its job.
Hopefully one day we all get IPv6. Even my home connection still lacks that, though.
So far with the linked config for me, tested only with one remote, other network, both IPv4 and v6, seems to work flawlessly. The homeserver is behind NAT but in DMZ.
Well… So far I’ve no plan for bridging any other service because my use case it’s not really “Matrix” but more “just a shared space where family could type a snippet of text with something they accept” (because I’m the sole with IT knowledge unfortunately), and “something to makes call”, normally audio only and 1:1, casually videos like “ok mom, show me the coffe machines and I’ll tell you what to do for making hot water for tea”.
I’ve choose Matrix over XMPP only because it seems more supported out-of-the-box, but I have little knowledge of it and my interest is limited to communications (I still have to find a use of federation concept, I prefer Nostr approach in that regard).
I’ll try to find out how to report with some useful infos, so far I simply see just a single entry in config, and running the service manually without this like the rest of the config works as expected, I also see no other “configs included” so I do not really know from where it came from as an error…
I think with my limited Nix knowledge I fails to understand that part: my vhost is just a CNAME pointing to my home.subdomain.tld, like matrix.mydomain.tld > home.mydomain.tld, and in that case I do not know how to “split” the certificates since there is only one including all CNAMES entries.
I’ll dig this today/tomorrow, so far I’ve just see that a services.ntfy-sh do exists…
No, stable 25.11, the error message is from server logs, while coturn instance works normally anyway (meaning journalctl -u coturn.service), for my usecase even if it’s not production-ready it doesn’t really matter as long as it works, I have no value in history so it’s just having the service, if a day I lost chats etc it’s not at all an issue
Same for me, maybe the NAT wasn’t the problem then.
Anyway, my experiment is largely disappointing… I’m trying XMPP and so far it’s going even worse; I reckon these kinds of FLOSS projects just lack a proper vision to be successful…
They seem more like experiments started without a clear idea of where they’re going, with developers setting something up and then abandoning it, and others proposing something else only to abandon that too, in an ecosystem that just can’t manage to take shape.
PS: as for Coturn, I finally figured out how to get it to read the SSL certificates: users.users.turnserver.extraGroups = [ “nginx” ]; so that the process could read the nginx group readable cert and key.
If it can be of help, this was my configuration before I rage quitted coturn:
{
networking.firewall.allowedTCPPorts = [
3478 # turn server
5349 # turn server
];
firewall.allowedUDPPorts = [
3478 # turn server
];
firewall.allowedUDPPortRanges = [
{ from=49152; to=49999; } # turn relay
];
# Allow read access to ACME certificate
# to specific (service) users.
users.groups."hostname-with-dots-replaced-by-dashes".members = [ "murmur" "turnserver" "nginx" ];
services.matrix-synapse.settings = {
# Tell users about our TURN server
turn_uris = with config.services.coturn; [
"turns:${realm}:${toString tls-listening-port}?transport=udp"
"turns:${realm}:${toString tls-listening-port}?transport=tcp"
"turn:${realm}:${toString listening-port}?transport=udp"
"turn:${realm}:${toString listening-port}?transport=tcp"
];
turn_user_lifetime = "1d";
};
services.matrix-synapse.extraConfigFiles =
[
# Needed to restrict access to the TURN
# server to only our matrix users.
#
# Should contain `turn_shared_secret: "yoursecrethere"`
"/path/to/turn.yaml"
];
# Handles users behind a NAT,
# needed for reliable VoIP.
services.coturn = {
enable = true;
no-cli = true;
# Only allow users vouched for
# by the Matrix server.
lt-cred-mech = true;
use-auth-secret = true;
static-auth-secret-file = "yoursecrethere";
# Use maxwell certificate for TLS
realm = config.var.hostname;
cert = "/var/lib/acme/${config.var.hostname}/fullchain.pem";
pkey = "/var/lib/acme/${config.var.hostname}/key.pem";
# Port range for TURN relaying
min-port = 49152;
max-port = 49999;
# Enable TLS
secure-stun = true;
no-tcp-relay = true;
listening-ips = [ "0.0.0.0" ];
extraConfig = ''
external-ip=${config.var.ipv4WanAddress}
cipher-list=HIGH
no-multicast-peers
no-tlsv1
no-tlsv1_1
mobility
user-quota=12
total-quota=1200
verbose=true
'';
};
};
They seem more like experiments started without a clear idea of where they’re going, with developers setting something up and then abandoning it,
I can’t say for XMPP, but for Matrix I think the problem is not lack of vision but that they run out of money, a couple of years ago. This is why the stopped developing the next gen homeserver and P2P protocol.
This is definitely true, but I don’t see it impacting anything personally. Normal mortals shouldn’t run synapse anyway, the P2P protocol isn’t essential, and everything else is still either developed by other parties or perfectly fine.
Even Element X - their new and improved app - works really well in my experience. Sliding sync finally works without a hitch and is just as fast as commercial clients, despite me having a ~200ms ping to my server.
Matrix in general works well for me, and I don’t really understand the complaint of it seeming abandoned. The service is a ton of effort to set up, sure, but that’s kinda to be expected for a complex platform like this.
My main issue is the complexity of E2E encryption; it’s kinda hard to make laypeople understand what’s going on. But with a bit of handholding around that I’ve not had significant issues with non-tech people using my matrix instance.
The E2EE aspect of things is also actively being worked on by a bunch of companies, so I can see that improving significantly still.
Well, maybe I’m a (relatively) old Unix head, but… personally, I think a FLOSS project should be run on our own iron rather than using someone else’s ones, as far as possible. I don’t see why it shouldn’t be normal to have my own Matrix instance to talk to family and friends, complete with audio and video, instead of clogging up the project’s servers, which are an unnecessary extra cost for the project anyway, provided self-hosting is easy enough.
Mere mortals could self-host much more easily if it were a single package that didn’t require various separate services to be configured individually, often with poor documentation to start with them; making this possible would help the project spread.
It’s true that most people don’t have a domain name or a home server, but it’s also true that those who do don’t necessarily know much about Matrix, yet would still be interested in using it if it were simple. Pip isn’t exactly beyond reproach for many reasons, but it’s one of the reasons Python has been so successful: it makes hyper easy to pull in what you need into a venv. go get/go install do the same. Whether it’s pip, uv, or conda doesn’t matter much; the point is the barrier to entry, the amount of stuff you have to study, and how easy or difficult that is regardless of the documentation.
Time ago I was looking for a home video streaming service without knowing much about it; I did a quick search and Jellyfin popped up. A few lines in my config and there it was, up and running perfectly. YARR? The same. If Matrix were alike, it would have a much larger audience.
That’s not what I’m saying.
Synapse is the reference implementation of the server-side of the matrix protocol. It specifically was never intended to be the server people actually use; it’s written in python, horribly slow and takes tens of gigabytes of memory.
You can still self-host any other matrix homeserver, and I agree that this should be possible. In fact, I think that’s what’s neat about matrix over any other protocol; the federation feature makes it actually a viable replacement for all the commercial clients.
The company which wrote the initial matrix protocol spec is the one struggling with income, and the one that develops synapse. My point is, you don’t need synapse at all, so them struggling with income has little impact on the matrix ecosystem.
Sadly, decentralized messaging and especially VOIP is much more complicated than hosting a few mp4s, especially in a world in which IPv6 is still not reasonably usable.
Just adding another datapoint: We’ve running an unfederated Synapse server on the company VPN for a years time or so. For AV we went with element call only, which means no support for Element Classic calls, but on Element Web and Element X they work well.
A central feature we needed was bridging to other services and while there isn’t exactly an amazing nixpkgs module for that, most bridge solutions are packaged and there’s a decent amount of examples out there for stringing together something workable.
I would assume that the fact that we run unfederated is a primary reason for not experiencing the resource hunger and performance bottlenecks of Synapse quite so painfully. We are always on the lookout for tweaks to the setup, but for now this works for our needs.
I would assume that the fact that we run unfederated is a primary reason for not experiencing the resource hunger and performance bottlenecks of Synapse quite so painfully.
I run a small federated instance of Synapse but with a small number of users and strictly no large rooms. It’s not that bad RAM-wise.
And to be fair for a Tuwunel instance I also avoid large rooms…
Well… I quite agree that VoIP is more complex, but here’s a simple example: if push notifications require a tiny dedicated service, why not just integrate it? Why force the user to find out about it and figure out how to integrate it themselves instead of making it part of a single package?
I’ve read all sorts of things about Matrix, including Matrix? No, thanks. — Hackea documentació , which makes me think they aren’t exactly short of funds, maybe that’s not the case, but still, having either top-tier documentation or a lower barrier to entry would really help a project to spread.
If it took me this much time, a newbie student will most likely just give up and go to Discord, and it’s exactly this demographic that will be choosing which digital tools to use in the future and recommending them to their companies…
Because, if you know anything about what “push notifications” means, you’ll understand that this is a silly idea. That’d be the opposite of “push notifications”, we’d call that “polling” (and this is in fact how the non-app web client does it).
The idea of “push notifications” is that you have one centralized service which basically gets sent a message that says “hey, I have a new notification for this phone” by every app running on the phone.
The phone can then poll that single service every once in a while to check if there are new notifications.
If each app’s notification service has to be polled independently, then your phone has to wake up all the time to query the notification services of like 200 apps, and it needs to engage its networking, which is one of the most expensive things to wake for a phone (since it needs to do the whole 5G rigamaroll and send high-frequency radiation to and fro a cell tower; even worse if you have LTE+5G shenanigans going, so it needs to potentially call out to multiple towers).
So, fundamentally, matrix has to offload this to a different service (which can be shared between more than one app), or users will moan about your matrix client eating 30% of your battery life just to stay on top of notifications.
Actually, this is entirely unrelated to the matrix protocol; it’s simply an optimization matrix clients that run on phones might (or might not) implement. I know at least Element/X and fluffychat implement it, I don’t know about other clients.
Of course, ntfy isn’t the only push notification server either; it’s not like whatsapp uses it. You also don’t need ntfy for matrix clients that have Firebase/APS keys, and send your message notifications over Google/Apple servers. If you install Element/X from Google Play/Apple’s App Store, by default you should not need a separate push notification server, since by default Element/X has firebase/APS keys and is configured to use the respective push notification service.
That said, you can also configure Element/X to independently poll, at which point it eats 30% of your battery life a day, but push notifications will work without something like ntfy, and it will also work without sending notifications over firebase/APS.
At least for me, I’ve never had issues with push notifications, even for non-tech-savvy users, and I didn’t instruct them to configure ntfy. If you’re having issues, you’re probably using a matrix client that doesn’t support push notifications, installing a client in a way that makes it not have APS/firebase keys, or I suppose maybe there’s a way tuwunel might be causing issues here, though AFAIK the homeserver isn’t involved in push messages.
I’d suggest keeping an open mind. Reading too many opinionated blog posts shuts you out of actually understanding things for yourself. The internet loves to moan about anything that isn’t IRC (and while I agree IRC has its charms, no sane person actually uses IRC willingly).
I’ll agree that Matrix isn’t perfect, especially if you want to do federation, or manage large servers. Moderation tools in the ecosystem were an afterthought, and this has caused a lot of problems. Room versioning is painful. But for simple use cases I don’t think it’s far off the mark; it’s a perfectly cromulent messaging platform that normal people can actually use.
self-hosting is naturally always more complex than having someone else do that work for you, as unfortunate as that is. You end up having to understand the little trade-offs of what you’re hosting, and also need to understand the details of networking and - for something like Matrix - the limitations and interactions with various client hardware.
If you’re not up to the task, there are various public home servers which do the job just fine, and you can get yourself a managed instance pretty easily.
Sure, a random student will probably just choose Discord because it has the marketing and existing network advantage, but they can also choose matrix.org as a public homeserver without spending any more effort on using matrix than Discord. I don’t see why the only alternative to using Discord is self-hosting matrix; you can use federated matrix messaging for free without hosting it today.
In fact, using a public matrix server still gives you more privacy than Discord, since Discord has no E2EE features whatsoever, so I would still recommend that over Discord.
FWIW, Schildichat on Android seemed to work out of the box with push notifs, while Element X did not.