Run Snikket on your NAS

Some weeks ago at FOSDEM Matthew Wild announced Snikket. You can find the introduction here in his post.

Many admins are still struggling when they want to run their own XMPP server. One of the strength of XMPP is the extensibility. But this can be also a weakness. It can add a lot of complexity, and a variaty of options you need to choose from for your server install. Many extensions and modules you can choose from during the setup, often dependent on each other. Another burden is often getting your TLS certificate setup fully automated. ALl those pain points are addressed in Skicket.

Snikket is:

  • dockerized
  • certificates are automated by default using Let’s Encrypt
  • all modules to run a modern XMPP server are enabled and perfectly configured out of the box

One specific module to mention is shared roster module. This is what many people expect from a modern instant messaging system by default.
When you run your own family or company team chat server you want all your users being able to communicate with each other out of the box. Without asking them to build the contact list on their own, and request authorization before starting a conversation.

Now I will show how easy it is to install Snikket on a Synology NAS. This tutorial assumes that your Synology NAS has the Docker package already installed.

Step 1: DNS

XMPP is a decentralized system. Similar to Email, where many individual servers communicate to each other. There is no single point of failure. No single company which controls the network and own the users.

This means you need a domain for your Snikket server. And its important that you have access to control the DNS setup. In this sample I am choosing the domain gnauck.name. If you websites and other services on your domain its always suggested to use a subdomain for the XMPP services. This is why I decided to use chat.gnauck.name as the Snikket domain.

We need to add the following 3 DNS records. I am pointing chat.gnauck.name to the external IP address of my network.
The other 2 sub domains for groups (group chat service) and share (file share) need to point to the same address or domain. This is why I just use a CNAME records for all of them.

# Domain           TTL  Class  Type  Target
chat.gnauck.name.  600  IN     CNAME my-nas.dyndns.org.
groups.chat.gnauck.name  600  IN     CNAME  my-nas.dyndns.org
share.chat.gnauck.name   600  IN     CNAME  my-nas.dyndns.org

Step 2: Firewall routes

On the firewall the relevant ports get forwarded from the public internet to Snikket which will be running on the Synology NAS. The following 4 ports needs to get forwarded. I redirect ports on the firewall. YOu could to those port redirects also in the docker port setup later.

TCP 80 => TCP 5280 on NAS
TCP 443 => TCP 5281 on NAS
TCP 5222 => TCP 5222 on NAS
TCP 5269 => TCP 5269 on NAS

Step 3: Configure Snikket docker image

Now we switch to our Synology NAS and go to the Docker UI. First we go to the registry tab and search for Snikket docker images. We download the image from the alpha channel.

Once the image is downloaded we press the Launch button. We are getting asked to provide a container name. Lets choose snikket as the name and continue with the advanced settings.
We Enable auto-restart there, to make sure Snikket it running 24/7.

Under volume we mount a local directory from our NAS into the docker image. This is where Snikket will store all persistent data (user data, files, message history etc…)
I create a new directory /docker/snikket_data and mount it as /snikket to our container.

Under port settings we just expose all the required ports we need. In this section you could also redirect the 5280/5281 ports to 80/443. I kept them as is, because we already did the port mapping above on the firewall as described in step 2.

Under environment add the 2 environment variables for the Snikket domain and admin email address.

SNIKKET_ADMIN_EMAIL = yourmail@yourdomain.com
SNIKKET_DOMAIN = chat.gnauck.name

Now we can save our configuration and start the container. On the first startup Snikket is writing all the configuration files to the volume mount we created above. It also will request the TLS certificates for our subdomains. Lets give Snikket some time for the initial startup. You can look at the logs, or just wait 2-3 minutes.

Now we can just got to the container terminal on the Synology and open a new Bash console. In the console we just type the command which gives us an onboarding link to create the admin user.

create-invite --admin
Copy the link, paste it to a browser on your Desktop or Android device. You should get to a webpage which is hosted on your newly created Snikket server. Just follow the instructions to download the Snikket Android app and create your new admin user.
At any time you can create invites for additional users with the create-invite command. Of course you create your regular users without the --admin option.

That was easy! Now we have our own self hosted secure and federated WhatApp like instant messaging service. Or our company team chat service.

Simpler code in handlers using pattern matching

The pattern matching feature which came with c# 7 can be very useful when writing XMPP stanza handlers with MatriX.

The MatriX vNext handlers are using predicates to filter and match stanzas. Sometimes the predicates can get very complex and would require a lot of type casts without pattern matching. So pattern matching makes you code much more readable, but also faster at runtime because we can save some casts of objects.

Here is a small code snippet of a stanza handler which is responsible for XMPP roster pushes.

Code without pattern matching

public class RosterHandler : XmppStanzaHandler
{
    public RosterHandler()
    {
        // handle roster pushed
        Handle(
            el =>
                el.OfType<Iq>()
                && el.Cast<Iq>().Query.OfType<Roster>()
                && (el.Cast<Iq>().Type == IqType.Result || el.Cast<Iq>().Type == IqType.Set),

            async (context, xmppXElement) =>
            {
                // do something with the stanza
            });
    }
}

Code with pattern matching

The sample below used also the **IsAnyOf** extension method which was added to MatriX recently
// With pattern matching
public class RosterHandler : XmppStanzaHandler
{
    public RosterHandler()
    {
        // handle roster pushes
        Handle(
            el =>
                el is Iq iq                
                && iq.Query is Roster
                && iq.Type.IsAnyOf(IqType.Result, IqType.Set),
            async (context, xmppXElement) =>
            {
                // do something with the stanza
            });
    }
}
of course you can use XPath or other technologies fore more complex stanza filtering in MatriX. I personally just prefer predicates becuase they are strongly typed and also fast.

Palaver XMPP client

It’s more than 20 years since I got involved with chat technologies. In the late 90’s I got hired by company for developing a chat client. We did this by reverse engineering the ICQ and AIM protocols and created a compatible client. Then Jabber was announced, we switched to it immediately, using the gateway feature to talk to the proprietary systems.

Later I worked for SLTS Communications on the myJabber client, which was very popular on the Windows platform. Also one of the first clients which bridged Jabber and SIP for VOIP integration.

Then I became self employed and focused mostly on libraries which helped many companies to bring their Jabber/XMPP products faster to market. I also did lots of consulting and custom development on clients, servers and other Jabber/XMPP related products.
Also many products which were not IM related, but using the realtime capabilities and other modern XMPP features.

Working on chat clients was always one of the tasks I enjoyed most. I missed the client work over the last 10+ years. So I thought its time to get back to it ;-)

Over the last 12+ month I did lots research on clients and their UIs. This includes XMPP, other open IM protocols and proprietary chat systems.
I worked on several prototypes with different toolsets and technologies. The aim was to evaluate languages and their frameworks. As well as available XMPP libraries for creating a modern cross platform client using the latest compliance suites.

The focus was on desktop clients only. While we have pretty good mobile clients, we are lacking on good desktop clients these days. Especially on Windows. Many people still spend most of their time on the desktop.

I created prototypes with:

  • various Javascript SPA frameworks, as PWA and Electron application
  • Different cross platform native UI-kits and programming languages
  • WASM
  • Java
  • .NET

I got the best results with technologies that have good implementations of the MVVM pattern. This narrowed it down to some web frameworks and the .NET platform for me.

With netCore the .NET platform became finally open source and cross platform. What’s still missing is an official cross platform GUI from Microsoft. But there is the open source XAML framework Avalonia, supporting all major platforms. And my own MatriX library is available for netCore for a while now, also open source, licensed under the GPL.

Because of the great Avalonia UI framework I decided on the netCore stack using for the new Palaver XMPP client.

Its still in very early stages. Once I can stabilize the prototype into a working client for daily usage all code will be published under the GPL license on GitHub. If anyone is already interested to contribute to this project then feel free to contact me.

Here you can see some early screenshots



XMPP websocket connection manager

For a new project I am working on (more to be announced) I was looking for a standalone websocket connection manager. Because still many public and private XMPP servers offer only the TCP transport or BOSH.

There are already existing projects websocket connection managers. But I ran into some issues with them for my current use case. Usually I am not trying to re-invent the wheels ;-)

After WebSocket support came to DotNetty which one of the latest releases, and MatriX vNext of course having full support for XMPP XML streams and clients I was considering creating my own proxy.

So it took only a 90 minute flight to come up with a working solution. I would not consider this solution as production ready yet. But the current design using DotNetty and MatriX vNext can support this at high scale.

When you are interested you can checkout the project on GitHub here:
https://github.com/matrix-xmpp/xmpp-websocket-proxy

MatriX vNext 2.0 released

we are thrilled to announce MatriX vNext 2.0

main changes in 2.0 are:

  • minor API changes which force major version bump (semver)
  • Direct TLS support (XEP-0368)
  • netstandard 2.0 support
  • new NameResolver wich allows to specify IP addresses of the XMPP server manual
  • new Matrix.Extensions package with extensions and helper functions
  • myget feed for latest dev builds

There is a new website for MatriX vNext and the documentation at:
https://matrix-xmpp.io/

All source code is available on Github now at:
https://github.com/matrix-xmpp/matrix-vnext

There is a WPF example client based on MatriX vNext available on Github here: https://github.com/matrix-xmpp/matrix-client

Introducing MatriX vNext

We are thrilled to announce the next generation of the MatriX XMPP libraries.
15 years elapsed already since we started our first .NET/c# XMPP library agsXMPP with .NET 1.0. Our XMPP libraries and the .NET technologies had many major evolutions over the years.

With the switch to .Net Core we also took the opportunity for a major rewrite and redesign of the codebase. The API for clients, servers and components is not backwards compatible, but all XMPP protocol classes remain the same. Updating existing code bases to MatriX vNext should be pretty straightforward.

Some highlights

  • new software design and more modern API
  • target .Net Core
  • high performance sockets using Azure DotNetty
  • Completly Task based using the TAP pattern (async/await)
  • more Linq extensions
  • Rx (Reactive Extensions)
  • will be open source and available under a dual license (Open Source and commercial)

Here is some demo client code using MatriX vNext:

var xmppClient = new XmppClient
{
    Username = "alex",
    Password = "secret",
    XmppDomain = "server.com",
};

xmppClient
	.XmppXElementStream
	.Where(el => el.OfType<Presence>())
	.Subscribe(el =>
	{
		// Handle incoming presence
		Debug.WriteLine(el.Cast<Presence>().From);
	});

xmppClient
	.XmppXElementStream
	.Where(el => el.OfType<Message>())
	.Subscribe(el =>
	{
		// Handle incoming messages	    
		Debug.WriteLine(el.Cast<Message>().Body);
	});

xmppClient
	.XmppXElementStream
		.Where(el => 
		el.OfType<Iq>
		&& el.Cast<T>().Type == IqType.Get
		&& el.Cast<T>().Query.OfType<Ping>()
	.Subscribe(el =>
	{
		// handle and reply to incoming pings
		var iq = xmppXElement.Cast<T>();

		var resIq = Factory.GetElement<T>();
		resIq.Id    = iq.Id;
		resIq.To    = iq.From;
		resIq.Type  = IqType.Result;

		await xmppClient.SendAsync(resIq);
	});

// connect, secure, authenticate and bind
await xmppClient.ConnectAsync();

// request roster (contact list)
var roster = await xmppClient.RequestRosterAsync();

// send own presence to the server
xmppClient.SendPresenceAsync(Show.Chat, "free for Chat");

Releases are available as a Nuget packages here: https://www.nuget.org/packages/Matrix.vNext

Firebase Cloud Messaging with MatriX XMPP SDK

We get a lot of requests on howto use the MatriX XMPP SDK with Google Firebase Cloud Messaging.

The following are the settings for your XmppClient object

  • The XMPP domain is: gcm.googleapis.com
  • The hostname is: fcm-xmpp.googleapis.com
  • It looks like there are no SRV records in place, this is why you need to set the hostname manual and disable SRV record lookups
  • Firebase does not support XMPP’s StartTls feature and requires to initiate a TLS connection. This is how we have done it in the old days when the protocol still was called Jabber. The OldStyleSsl property takes care of this in MatriX’s XmppClient.
  • Firebase is using a non standard XMPP port, because no SRV records are in place we have to set port 5236 manual in the code
  • the username is your Firebase Sender Id and the password is your server key. You find them in the Firebase portal under Settings => Cloud Messagging
  • the contact list and presence feature is not require. So we can disable it by setting AutoRoster and AutoPresence to false
XmppClient xmppClient = new XmppClient
{
    XmppDomain          = "gcm.googleapis.com",
    Hostname            = "fcm-xmpp.googleapis.com",
    Port                = 5236,
    ResolveSrvRecords   = false,
    OldStyleSsl         = true,
    Username            = "YOUR_FIREBASE_SENDER_ID",
    Password            = "YOUR_FIREBASE_SERVER_KEY",
    AutoRoster          = false,
    AutoPresence        = false
};

xmppClient.Open();

You can find a basic example also here in our GIT repository:
https://gitlab.com/matrix-xmpp/samples/tree/master/csharp/FirebaseClient

See also:
https://firebase.google.com/docs/cloud-messaging/server#implementing-the-xmpp-connection-server-protocol

MatriX XMPP SDK available for .NET Core

The MatriX XMPP SDK is also available for the .NET Core now.
You can get it from NuGet here: https://www.nuget.org/packages/MatriX.NetCore/

It passed all our internal tests and QA, but its still marked as a pre-release until we collected some more feedback from users.

Don’t hesitate to contact us directly, or use our forums for any questions related to the .NET Core version.

MatriX v2 released

We are pleased to announce the stable releases of MatriX 2. More about the changes in the v2 version can be found in this blog post

Instead of installers we will use NuGet only for all future MatriX releases. You can find all MatriX NuGet packages here

Sample codes can be found in the Git repository here

All our customers with active support & maintenance can of course upgrade to MatriX 2 for free. Updating existing code bases to MatriX 2 should only take a few minutes. We highly suggest the update because there are many improvements in the MatriX 2 core, and also many new features on our roadmap.

MatriX JS XMPP library in beta now

We are pleased to announce our new JavaScript XMPP library MatriX JS which is available for beta now.

MatriX JS is build with Microsoft’s TypeScript. The software design is very similar to our popular MatriX .NET XMPP SDK. TypeScript allowed us to port lots of existing source code, logic and patterns from our MatriX C# library to JavaScript. MatriX JS is also based on LinQ and LinQ to XML. This will make it very easy for our existing customers to port existing code bases to the web or cross platform HTML/JS applications.

Currently BOSH and websockets are supported as transport layers. Node.js and tcp sockets are coming later.

MatriX JS will be licensed under a Creative Commons Attribution-NonCommercial 4.0 International (CC BY-NC 4.0) license.

Contact us to join the MatriX JS beta