Using XMPP for our internal chat network

As a company that supports free software and an open, decentralized Internet, we often find ourselves at odds with dominant Internet paradigms. While cloud services might have lower startup costs and less technological or usability barriers, we often compromise our ideals and our needs. For example, to fill a need for company-wide communication, we've had to augment our project management software with a combination of personal Google Talk accounts and text messaging to share our work status with each other. We wanted to figure out how to enhance our communication, and ended up with our own XMPP server.



We decided to host our own XMPP service not only to decrease our Google usage, but also to gain access control and privacy. We wanted to use special features like cross-device audio/video, eventual multi-user video, and temporal status messages. We spent a bit of time learning about other group messaging and status update systems, but weren't impressed by any of them.

After talking as a group about what we wanted out of a messaging platform, I researched different services and software, and finally decided to experiment with ejabberd, an XMPP server written in Erlang. Running our own XMPP server provides all of what we wanted, and will provide more as time goes on and the code improves.


We were all familiar with the way XMPP chat works through Google's services, so using our own server wasn't a huge leap — we all knew how status messages and offline messaging worked. Some of us hadn't used a desktop chat client since high school (in my case, I hadn't used one since Pidgin was called gAIM!), so we had to do some experimenting with different clients for Linux and OS X. We settled on using Empathy on Linux and a mix of iChat and Adium on OS X.

We've found one-to-one Jingle audio/video chat using our own server to be much smoother than using Skype or Google. Unfortunately, we can't do iChat-to-Empathy audio/video... but we can do Empathy-to-GoogleTalk! We're looking forward to being able to have audio/video conferencing using Muji because going back to Google Hangout after being spoiled by our setup is hard to do!

Server side

Overall, it wasn't too complicated to install and configure the server. The following is a loosely-organized HOWTO based on what I did:

Install ejabberd and configure both the server and DNS records. Follow

Get an SSL certificate, and configure as described in

Make sure your firewall is allowing inbound TCP ports 3478, 5222, 5269, 5280, 5282, and 5349 as well as UDP port 3478. You might not need all of these if you aren't using all of the features configured in this guide.

Follow to set up dialback to federate with Google Talk and other servers. Add something like to /etc/hosts.

Federation will only work with accounts, unless domain owner adds special DNS records. I set this up for our client Allied Media Projects and it worked swimmingly:

_xmpp-server._tcp 10800 IN SRV 20 0 5269
_xmpp-server._tcp 10800 IN SRV 20 0 5269
_xmpp-server._tcp 10800 IN SRV 20 0 5269
_xmpp-server._tcp 10800 IN SRV 20 0 5269
_xmpp-server._tcp 10800 IN SRV 5 0 5269

To enable HTTPS on the ejabberd admin interface, edit /etc/ejabberd/ejabberd.cfg:

# ...removed web_admin from normal http server
{5282, ejabberd_http, [
                       tls, {certfile, "/etc/ejabberd/"}

For fun, try installing some modules, like mod_webpresence. See for a list.

apt-get install subversion erlang-dev erlang-tools
svn co
cd ejabberd-modules/mod_webpresence/trunk
cp ebin/mod_webpresence.beam /usr/lib/ejabberd/ebin/
cp -R data/pixmaps/ /usr/share/ejabberd/mod_webpresence_pixmaps
vim /etc/ejabberd/ejabberd.cfg # per README
service ejabberd restart

In the case of mod_webpresence, if you use a fancy jabber client like Psi (or Psi+) you can run a service discovery and try it out.

For Jingle audio/video chat to be useful, you need to punch some holes through NATs and firewalls using STUN. See and for reference.

In /etc/ejabberd/ejabberd.cfg, add at bottom of {listen ...}:
{ {3478, udp}, ejabberd_stun, []},
{3478, ejabberd_stun, []},
{5349, ejabberd_stun, [{certfile, "/etc/ejabberd/"}]}

and restart ejabberd.

Add DNS records like:

_stun._tcp 900 IN SRV 0 0 3478
_stun._udp 900 IN SRV 0 0 3478
_stuns._tcp 900 IN SRV 0 0 5349

That's all it takes!