Local Jabber/XMPP server with ejabberd and Debian

Jabber, the XMPP instant messenging protocol, is now the standard for IM communications. Slowly kicking out monstrosities from the 90's (msn, aol and such). The enormous advantage of Jabber is its decentralized architecture. Thus, you can setup you own server at home, with your own domain name, and communicate with any other xmpp user over the world (jabber.org, gtalk, …).

Right. That's the big commercial picture. Now, to build that, you need a little bit of a setup. Say:

  • a jabber server, such as ejabberd
  • a DNS server (bind)
  • a LDAP server (optionnal, but fancy)
  • a xmpp client (psi, mcabber, …)

XMPP Basis

, formely called jabber (but don't get confused, it's the same thing) is a network protocol standardized in RFCs 3920 and 3921. It is absolutely open and free (as in freedom).

In the XMPP world, users are identified by their JID. It's form is identical to the email: [username]@[location]. That means that you can have a JID that is identical to your email address: jean-kevin@mydomain.net.

Each XMPP server controls (or participate to) a domain and is responsible for contacting other domains. The XMPP server will send and receive messages from and to its users, but will also exchange presence datas to keep the list of connected users up to date (actually, this represents more than 60% of the XMPP traffic). It will also manage conference rooms, store profiles, queue connection requests, and so on…

ejabberd

Erlang Jabber Daemon, ejabberd, is probably the most popular xmpp server on Linux systems. The Debian version is very well packaged, so on Debian Lenny, a simple apt-get is enough to install it:

# apt-get install ejabberd

The configuration is located at /etc/ejabberd/. The main configuration file is ejabberd.cfg. The file itself is pretty well documented and almost ready for use. We just need to specify our domain name and provide a SSL certificate for STARTTLS communications between clients and the server (c2s) and server to server (s2s).

Some servers, such as the ones from Gtalk, impose the use of STARTTLS in s2s communications.

Domain configuration

To configure your domain name in ejabberd.cfg, change the hosts directive:

%% Hostnames
{hosts, ["mydomain.net"]}.

ejabberd configuration file is written in erlang syntax, where the % % signs represent a comment, and each directive must end with a dot.

If you want to manage several domains with the same server, list them in the same hosts directive: {hosts, [“mydomain.net”, “mydomain.org”]}. But keep in mind that each domain, or subdomain, has its set of independent users.

TLS Listener

ejabberd has typically two listener: one for c2s communications listening on port 5222, and one for s2s communication listening on port 5269. Each listener can furnish a STARTTLS support to enable TLS communications over the wire. But, for that, ejabberd needs a SSL certificate. Debian packages a self-signed certificate that's deposed in /etc/ejabberd/ejabberd.pem. Let's change that.

Generate your own certificate and private key and create a folder called certs in ejabberd folder. There, deposit you signed certificate (a PEM file) and the private key, as follow:

root@server:/etc/ejabberd/certs #  ls -l
total 20
-rw-r--r-- 1 root root 1675 aoû 13 12:58 jabber.mydomain.net.key
-rw-r--r-- 1 root root 7077 aoû 13 12:58 jabber.mydomain.net.pem

and back in ejabberd.cfg, change the c2s listener and s2s certfile:

114 {listen,
115  [
116   {5222, ejabberd_c2s, [
117                         {access, c2s},
118                         {shaper, c2s_shaper},
119                         {max_stanza_size, 65536},
120                         starttls, {certfile, "/etc/ejabberd/certs/jabber.mydomain.net.pem"}
121                        ]},

[...]

206 {s2s_certfile, "/etc/ejabberd/certs/jabber.mydomain.net.pem"}.

Basic configuration of the server is done, you can restart it and verify that port 5222 and 5269 are listening to incoming TCP connections.

# /etc/init.d/ejabberd restart
Restarting jabber server: ejabberd.

# netstat -taupen |grep -E "5222|5269"
tcp        0      0 0.0.0.0:5222            0.0.0.0:*               LISTEN      119        21657632    10743/beam
tcp        0      0 0.0.0.0:5269            0.0.0.0:*               LISTEN      119        21657634    10743/beam

Register a user

ejabberdctl is a program furnished with the ejabberd package to provide realtime control over the server while it's running. ejabberctl provides a large set of functions, so feel free to browse the documentation (or simply run ejabberdctl -h and play with the commands). To register a new user to the server, use the following command: ejabberdctl register <username> <domain> <userpassword>.

Exemple with jean-kevin:

# ejabberdctl register jean-kevin mydomain.net 'm3g4password'

jean-kevin can now log in. But that's pretty much all jean-kevin can do, because we have to let the outside world know about our xmpp server, and this is going to be done with DNS SRV records.

Configure the DNS to provide XMPP information

A XMPP server connected to the internet will be able to contact other XMPP servers almost right away. But for another server to contact us, we need to publish some information through the DNS master of the domain.

Imagine that michel@toto.com wants to talk to jean-kevin@mydomain.net. The cinematic is as follow:

  1. michel's client connect to its own xmpp server (called SRVMICHEL) and sends a message destinated to jean-kevin (MESSAGE1)
  2. SRVMICHEL receives MESSAGE1 and look more closely at the receiver's address: jean-kevin@mydomain.net. SRVMICHEL needs to determine what server is in charge of XMPP messages for mydomain.net. So, SRVMICHEL performs a DNS query similar to the following one:
$ dig SRV _xmpp-server._tcp.mydomain.net

[...]

;; QUESTION SECTION:
;_xmpp-server._tcp.mydomain.net. IN   SRV

;; ANSWER SECTION:
_xmpp-server._tcp.mydomain.net. 259200 IN SRV 5 0 5269 jabber.mydomain.net.

;; ADDITIONAL SECTION:
jabber.mydomain.net.     259200  IN      A       11.22.33.44

;; Query time: 109 msec
;; SERVER: 212.27.40.241#53(212.27.40.241)
;; WHEN: Sat Aug 14 14:14:22 2010
;; MSG SIZE  rcvd: 111

The query ask for the xmpp-server in charge of the domain mydomain.net. The DNS of mydomain.net replies that this xmpp is handled by jabber.mydomain.net on tcp port 5269, and that jabber.mydomain.net is located at the IP address 11.22.33.44.

  1. SRVMICHEL then connects to ip address 11.22.33.44 on TCP port 5269
  2. SRVJEANKEVIN accepts the connection. Then follow an exchange of XMPP messages (signaling, data and so on) and SRVMICHEL sends MESSAGE1 to SRVJEANKEVIN.
  3. SRVJEANKEVIN forward the MESSAGE1 to the client software used by Jean-kevin.

So, what we need in our DNS master is a SRV records that publishes the XMPP information of mydomain.net to the Internet. In your DNS zone file, we add the following information:

jabber          IN      A       11.22.33.44
conference      IN      CNAME   jabber

;srvce.prot.name                      class   rr  pri weight   port    target
_jabber._tcp.mydomain.net.              IN   SRV  5    0       5269    jabber.mydomain.net.
_xmpp-server._tcp.mydomain.net.         IN   SRV  5    0       5269    jabber.mydomain.net.
_xmpp-client._tcp.mydomain.net.         IN   SRV  5    0       5222    jabber.mydomain.net.

Some explanations:

  • conference points to our jabber server and will be used for public chatrooms.
  • All SRV records have a priority of 5, a weight of 0 and point to jabber.mydomain.net.
  • _jabber._tcp.mydomain.net. is the legacy SRV record for jabber servers
  • _xmpp-server._tcp.mydomain.net. is the record that will be queried by other xmpp servers to know where to send xmpp messages
  • _xmpp-client._tcp.mydomain.net. is used by xmpp clients softwares to know to which server to connect to when adding a user account
  • As said before, server requests are sent to TCP port 5269 and client request to TCP port 5222

With these information, the DNS master can be restarted and you can test your configuration with a dig query similar to the one used previously.

Test first configuration

Now, if your server configuration, dns configuration, and eventually firewall rules and NAT are set properly, you should be able to connect to your XMPP server with any xmpp client and contact other XMPP users.

For basic test, I recommend mcabber, a console xmpp client, locally on the ejabberd server. Install it with a quick apt-get and create a ~/.mcabber/mcabberrc basic configuration file as follow:

set username = jean-kevin@mydomain.net
set server = localhost
set port = 5222
set resource = mcabber
set ignore_self_presence = 1
set ssl = 0
set cmdhistory_lines = 250
set message_autoaway = Auto-away (idle)
set escdelay = 50
alias me = say /me
alias online   = status online
alias away     = status away
alias dnd      = status dnd
alias notavail = status notavail
bind 17 = roster unread_next
bind 24 = roster alternate
bind 269 = roster toggle_offline
bind 276 = roster toggle
bind 521 = buffer up
bind 514 = buffer down

Launch mcabber and type your password, you should see the following screen. try the command /add michel@toto.com to add a new user to your friend list:

$ mcabber
MCabber 0.9.7 -- Email: mcabber [at] lilotux [dot] net
[14:43:14] MCabber 0.9.7 -- Email: mcabber [at] lilotux [dot] net

[14:43:14] Reading /home/jeankevin/.mcabber/mcabberrc
Server: localhost
Username: jean-kevin@mydomain.net
Please enter Jabber password:

LDAP configuration

On my own configuration, users are stored in a LDAP directory. The tree is pretty basic and described in this article. Users are stored in ou=people,dc=mydomain,dc=net. ejabberd can easily query the LDAP directory to check user's passwords. To do so, you need to change the authentication backend in ejabberd.cfg configuration file.

Comment the basic authentication backend and uncomment the lines concerning LDAP, as follow:

237 %%{auth_method, internal}.

[...]
258 %%
259 %% Authentication using LDAP
260 %%
261 {auth_method, ldap}.
262 %%
263 %% List of LDAP servers:
264 {ldap_servers, ["localhost"]}.
265 %%
266 %% Encryption of connection to LDAP servers (LDAPS):
267 %%{ldap_encrypt, tls}.
268 %%
269 %% Port connect to LDAP server:
270 {ldap_port, 389}.
271 %%
272 %% LDAP manager:
273 %%{ldap_rootdn, "dc=example,dc=com"}.
274 %%
275 %% Password to LDAP manager:
276 %%{ldap_password, "******"}.
277 %%
278 %% Search base of LDAP directory:
279 {ldap_base, "ou=people,dc=mydomain,dc=net"}.
280 %%
281 %% LDAP attribute that holds user ID:
282 {ldap_uids, [{"mail", "%u@mydomain.net"}]}.
283 %%
284 %% LDAP filter:
285 {ldap_filter, "(objectClass=inetOrgPerson)"}.
286

Some explanations here:

  • we deactivate the basic internal authentication method by commenting the line.
  • we activate the ldap method (line 261)
  • a ldap slave is present locally on the server, so ldap calls are done on localhost:389 without TLS
  • the ldap search base is ou=people,dc=mydomain,dc=net, where users are located in the LDAP tree
  • JIDs are identical to user's email addresses, so we look for the mail attribute to find usernames. This is done with the directive {ldap_uids, [{“mail”, ”%u@mydomain.net”}]}.
  • and, finally, we restrict the search filter to inetOrgPerson object class. no need to look for other types of objects, we only want to match users (and not printers, for examples).

In my configuration, there is no need for a LDAP manager. User's credentials can be used to bind to the ldap server and verify the user password. So I left the LDAP MANAGER directives commented out.

With these directives, ejabberd should be able to verify the user credentials against the ldap directory. Simply restart your ejabberd server and try to log in again with, this time, the password stored in LDAP, and you should be all set.

This configuration does not require that user are registered against the ejabberd server using ejabberdctl command before they can actually log in. ejabberd will rely on the ldap objects directly.

MSN transport

Using pymsnt as a gateway with ejabberd, it is possible to contact MSN users through a XMPP account.

# aptitude install pymsnt

The configuration file is /etc/pymsnt.conf.xml. pymsnt needs a DNS records, such as msn.mydomain.net that points to the pymsnt gateway. The sample configuration file connect to ejabberd on localhost:5557 and share a random secret token for basic security:

<pymsnt>
<jid>msn</jid>
<host>msn.mydomain.net</host>
<mainServer>127.0.0.1</mainServer>
<port>5557</port>
<secret>totodanslecaniveau</secret>
<lang>en</lang>
<website>http://jabber.mydomain.net</website>
<mailNotifications/>
<allowRegister/>
<getAllAvatars/>
<ftSizeLimit>524288</ftSizeLimit>
<ftRateLimit>2048</ftRateLimit>
<ftJabberPort>8010</ftJabberPort>
<debugLevel>2</debugLevel>
</pymsnt>

Some explanations from the doc:

  • The 'jid' setting should be the ID you want PyMSNt to take on the network. Example: 'msn.host.com'.
  • The 'host' setting should be a public DNS or IP address of the server the transport is running on. This is needed for file transfer!
  • The 'mainServer' setting should be the IP address or DNS of the main Jabber server. Default: '127.0.0.1'.
  • The 'port' setting is the port that PyMSNt and the Jabber server agree to use to connect between them (more details on this below). Default: '5347'.
  • The 'secret' setting should match the secret specified for component connections in your main Jabber server. It's a password that only the Jabber server and the transport must know.
  • The 'website' setting should be a website to refer users to.
  • There are other options in this file that are documented by comments. It is safe to leave them at the default values.
  • Ensure that the transport can make outgoing connections on port 443 (HTTPS), 1863, as well as incoming connections on 8010 (for Jabber file transfers).

In /etc/ejabberd/ejabberd.cfg, we need to configure the MSN transport as follow:

  %% MSN Transport
  {5557, ejabberd_service, [
                            {ip, {127, 0, 0, 1}},
                            {access, all},
                            {shaper_rule, fast},
                            {host, "msn.mydomain.net", [{password, "totodanslecaniveau"}]}
                            ]},

Open TCP/8010
PyMSNt will listens on port TCP/8010 by default for incoming connections. Make sure you open that one in your firewall ;)

Restart both daemons, on your local xmpp client (such as PSI), your should see “msn.mydomain.net” in the service discovery section.

If you run Lenny. There is a bug between twistd and pymsnt

If you have an error message on the removePID function, apply the followingpath to main.py as follow:

# cd /usr/share/pymsnt/src

# patch -p1 < pymsn.patch
can t find file to patch at input line 4
Perhaps you used the wrong -p or --strip option?
The text leading up to this was:
--------------------------
|diff -a -u -d -r pymsnt.a/src/main.py pymsnt.b/src/main.py
|--- pymsnt.a/src/main.py       2008-04-04 17:45:43.000000000 +0400
|+++ pymsnt.b/src/main.py       2008-08-05 17:44:17.000000000 +0400
--------------------------
File to patch: main.py
patching file main.py

# /etc/init.d/pymsnt restart
Stopping MSN transport for Jabber: No python found running; none killed.
Starting MSN transport for Jabber: Removing stale pidfile /var/run/pymsnt/pymsnt.pid
pymsnt.

Configure File Transfert

ejabberd can act as a proxy between two clients to allow file transfert between those clients. There is a module called mod_proxy65 for this purpose. The documentation is available here, a basic configuration works as follow, in ejabberd.cfg:

  {mod_proxy65,  [
                  {name, "File transfert service"},
                  {host, "jabber.mydomain.net"},
                  {hostname, "jabber.mydomain.net"},
                  {ip, {0, 0, 0, 0}},
                  {port, 5270},
                  {access, local},
                  {shaper, c2s_shaper}
                 ]},

With:

  • {host, HostName}: This option defines the Jabber ID of the service. If the host option is not specified, the Jabber ID will be the hostname of the virtual host with the prefix ‘proxy.’. The keyword ”@HOST@” is replaced at start time with the real virtual host name.
  • {name, Text}: Defines Service Discovery name of the service. Default is “SOCKS5 Bytestreams”.
  • {ip, IPTuple}: This option specifies which network interface to listen for. Default is an IP address of the service’s DNS name, or, if fails, {127,0,0,1}.
  • {port, Number}: This option defines port to listen for incoming connections. Default is 7777.
  • {hostname, HostName}: Defines a hostname advertised by the service when establishing a session with clients. This is useful when you run the service behind a NAT. The default is the value of ip option. Examples: “proxy.mydomain.org”, “200.150.100.50”. Note that not all clients understand domain names in stream negotiation, so you should think twice before setting domain name in this option.

FIXME → USE SPECTRUM ! http://spectrum.im/projects/spectrum/wiki

en/ressources/articles/ejabberd.txt · Last modified: 2011/04/06 14:06 by julien
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0