Matrix Chat

You're missing out on chat

Matrix is a good thing

Recently I spent some time with Matrix (link). It’s meant to be something of a be all for chat and video. What struck me most about it was end to end encryption as well as the ability to create ‘bridges’ to connect Maxtrix accounts to other networks.

I’ve been maintaining an XMPP server for years and the promise of Matrix was a bit too alluring to ignore. After some trials, tribulations and banging away on my keyboard I can say this: it’s a great system despite some quirks. I’ve been able to link it to all kinds of external accounts and I’m not even more visible on chat than I was in the past.

If you’re looking for a self-hosted, OSS chat solution. Definitely look at Matrix.

What I setup

I was able to get the following setup with Matrix. It’s so comprehensive I’m not looking at the alternatives anymore. I’m looking for Matrix bridges to connect my Matrix account to other networks. It really is impressive.

Main Matrix Service

I was able to install Matrix per their directions here (link) along with their identity service here (link). These form the core chat/video service(s) and it’s been surprisingly sound. I did set it up to use Postgresql instead of the default SQLite database. Their docs for the setup were top notch.

The docs on the identity provider were a bit lacking but I was able to watch the logs and sort out some of the odd errors I received along the way.

Web Access

The most commonly recommend web front end is and it’s a great OSS project you can self-host. I was able to pull the release from here (link) and get it deployed via nginx pretty easily. It’s got some rough edges but nothing worse than what I had with XMPP.

They also have an Android client that works well. No better or worse than the XMPP client I was using on Android.

XMPP Bridge (Pupped account config)

The first bridge I setup was an XMPP bridge that allows me to ‘Puppet’ my XMPP account from Matrix. The config allows me to use my Matrix account to interact with XMPP contacts/people as if I was using a native XMPP client. Perfect for migrating away from XMPP over time. It’s also helpful since a large portion of my contact list is on XMPP and not other networks.

You can find the bridge here (link)

Command Line Client

Once I had XMPP up and running I went digging for a good way to access Matrix from the command line. Normally I use Finch (part of Pidgin) for CLI chat purposes. I was able to find a libpurple plugin for Pidgin/Finch that works very well. I was able to build/install the plugin and it ‘just worked’ with Finch.

You can find the plugin here (link)


One other chat system I leveraged heavily in the past but haven’t used in a while is IRC. For the sheer fun of it I setup the official Matrix IRC bridge to connect my Matrix server to Freenode. I was surprised how quickly and easily it came together. I was able to setup transparent proxying of Matrix and IRC such that I can now use Matrix as my IRC client.

I was able to join rooms, DM people, authorize my nick with nickserv and a bunch of other neat stuff.

You can find the bridge here (link)


A project I’ve recently wanted to track uses Gitter for their chat presence. I was able to setup a basic Matrix to Gitter bridge. It doesn’t puppet accounts but works ‘well enough’ for my day to day needs. Pretty handy if you want to access a Gitter room here and there.

You can find the bridge here (link)

Going Forward

Going forward I plan on cleaning up the Gitter config a little but for now I’m happy. Along the way I found a node framework that helps build bridges to puppet accounts as well as bridges for discord, skype and signal puppeting. I’ve only taken a cursory look, but things seem very promising. If I can get discord, skype and signal bridged with Matrix I’ll have very little need for any other chat services.

Relevant puppet links (untested/non-verified) * * * *

matrix  chat  it 

(function(f, a, t, h, o, m){ a[h]=a[h]||function(){ (a[h].q=a[h].q||[]).push(arguments) }; o=f.createElement('script'), m=f.getElementsByTagName('script')[0]; o.async=1; o.src=t;'fathom-script'; m.parentNode.insertBefore(o,m) })(document, window, '//', 'fathom'); fathom('set', 'siteId', 'PUEYX'); fathom('trackPageview');