Building your own Slack

The world is flooded with Chat & Video Conferencing apps. Apps like Slack, Microsoft Teams, Zoom, Google Meet, Facebook Rooms (the list goes on and on) are getting ever more popular. And there is a good reason for it. Since we all were and still are affected by the Isolation caused by the Covid-19 pandemic, the ability to work and collaborate online became a big necessity. By solving this problem and providing tools for effective remote team collaboration, these apps have seen a huge growth in their users and revenues.

Most of these apps, although providing free options, for preimum functionalities (larger chat groups, conferences participants or higher quality video/audio) they cost money (dah!).

What if you could build your own Slack app?

I’m not talking about simple chat demo app that you can find everywhere on the internet. No! I mean a bit more sofisticated than that.

Something like a fully blown Artillery app composed of:

  • multi-party calls & video conferences up to 50 people,
  • powerful rich-text chat packed with emoji’s, giphys, file sharing, mentions and reactions,
  • organized conversation channels using private, public, nested rooms supported by simple yet effective roles-based security model (moderators & members)?

And on top of that being able to deploy it either on-premise or in the cloud?

Well, that exactly what we are going to do here. And we are going to name our baby Roomler.

Ladies (… and Gentlemen), you can think of it as “Slack on Crack” or “Microsoft Teams on Wheels”, and all that fully free and open source.

So without any further ado, let’s get down to the core.

Show me the Money!

As they say, actions speak louder than words so let see it in action first. To get a glimpse of the final result, check out this intro video:

Building a Powerful Video Conferenceing & Team Collaboration Tool

Technology stack

We are going to do this by using the cutting edge open source technologies:

  • Janus GatewayMeetecho’s Awesome General purpose WebRTC server (SFU)
  • Coturn — Free open source implementation of TURN and STUN Server
  • Fastify — Fast and low overhead web framework, for Node.js
  • PM2 — Production Process Manger for Node.JS
  • MongoDB — document-based, distributed database built for modern application developers and for the cloud era
  • Redis — in-memory data structure store, used as a database, cache and message broker
  • VueJS — Progressive JavaScript Framework
  • NuxtJS — Meta-framework for universal applications
  • VuetifyJS — Material Design UI Component Framework
  • Nginx— High Performance Load Balancer, Web Server & Reverse Proxy with HTTP3/Quiche & Brtoli support
  • Docker — Platform for building, deploying, and managing containerized applications

Microservices based Architecture

The whole app is composed of the following micro-services (Docker containers), stitched together:

  • MongoDB — Official image (386MB)
  • Redis — Bitnami’s image (105MB)
  • Coturn — Alpine:edge based image (20MB)
  • Janus — Debian:buster-slim image (170MB)
  • Roomler — Debian:buster-slim NodeJS installed image (622MB)
  • Nginx — Debian:buster-slim image with HTTP3/Quic + Brotli support (107MB)
Image for post
Image for post

Stiching your Microservices together

Prerequisites

We need two docker networks:

MongoDB

As a data storage for storing:

  • users
  • rooms
  • messages
  • connections
  • calls
  • etc..

we will use MongoDB.

We will start a container of MongoDB via:

After starting your MongoDB container, you can log in into it:

and create a user for the Roomler app:

Then your MongoDB connection string passed as an environment variable into roomler (see below in Roomler secion) could look like this:

For the sake of simplicity, we are starting only one mongo instance. In real world production scenario, you would like to setup cluster of mongo instances.

I wrote about how to setup your mongo cluster in:

For now let’s move on with the simple approach.

Redis

Since we want to make roomler Chat scalable (support multiple replicated containers), in order for these containers to be able to communicate with each other, we will use Redis’s PUB/SUB mechanism to achieve this inter container communication.

E.g. chat messages received over Web Sockets in container C1 will be published to redis so that other containers Ci subscribed on redis will receive them too.

Image for post
Image for post

Even though, not recommended, we will start Redis without a Password, but this should not be an issue, because Redis will not be accessible from the internet (only from the backend docker bridge network).

Coturn

In order to support joining the video conferencing to users that are behind NAT (have private IP addresses), we need a TURN server.

It’s recommended that it’s runs on the dockershost network directly:

Janus

For video conferencing we will rely WebRTC connections via browsers. However, since WebRTC is p2p protocol, in the context of video conferences, the default MESHED topology is not very scalable, so we will implement a SFU (Selective Forwarding Unit) topology via the excellent Janus Gateway.

Image for post
Image for post

Just like coturn it is recommended that also janus is attached to the dockers host network, to avoid networking issues while joining to video conferences (ICE candidates gathering failures).

Roomler

Roomler supports OAuth authentication with your favorite accounts (Facebook, Gmail, LinkedIn, Github) as well as Local registration (using username, email and password). We need to wire up all OAuth IDs/Secrets, DB connection string, Coturn Auth as well as Giphy API key.

Since Roomler container needs to be in both backend and frontend docker networks, and by default while starting a container we can only attach it to only one network (backend), we need to attach the container to the second network after roomler is started:

Nginx

Before starting nginx we need to have nginx.conf:

as well as conf.d/roomler.live.conf:

By default we will start the nginx container attached to the default bridge network and apply port mapping. Note that on port 443 we are exposing both tcp and udp protocol mapping. This is because our nginx image supports the experimental http3 which is blazing fast and relies on both udp and tcp connections. ! Lovely :)

Like roomler we will also attach nginx to the frontend network.

That’s it!

If you’ve successfully followed the steps from above, your own Powerful Video Conferencing & Team Collaboration Tool S̶l̶a̶c̶k Roomler should be up and running.

You can also try it out here:

Of course all the above steps, could have been wired up in a single docker-compose.yml file, but that way, we wouldn’t learn anything :)

However, as a home work, you can try doing this via docker-compose .

In the meanwhile, you can find the source code here:

Wrapping up

By stitching few simple open source, yet very powerful micro-services, we have managed to setup and run our own Video Conferencing & Team Collaboration Tool, that compares (or even exceedes), the functionalities of the large-scale applications like Slack, Microsoft Teams, Zoom etc.

This opens up the opportunity to collaboration with your team, clients, familiy and friends on your own infrastructure (on-premise or in the cloud) for only the fraction of cost, that your would otherwise need to pay for the mentioned premium services.

What’s next?

In next posts we will dive into implementation details of Roomler.

We will cover things like:

  • Authentication
  • Scalable Web Sockets
  • Rich-text editing (file share, mentiones, reactions)
  • GeoIP
  • Giphy
  • API testing
  • … and much more

Stay tuned!

If you liked what you have read and seen, then they say:

Give the devil his due!

Hence I would appreciate if:

  • Clap & share this post with your friends
  • Star it on github
  • Share your experience with Roomler (how it has benefited you)
  • Report any issue found on github

Talk to you soon!

Written by

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store