Running your own XMPP server on Debian or Ubuntu

In order to get closer to my goal of reducing my dependence on centralized services, I decided to setup my own XMPP / Jabber server on a server running Debian buster. I chose ejabberd since it was recommended by the RTC Quick Start website and here's how I put everything together.

DNS and SSL

My personal domain is fmarier.org and so I created the following DNS records:

jabber-gw            CNAME    fmarier.org.
_xmpp-client._tcp    SRV      5 0 5222 jabber-gw.fmarier.org.
_xmpp-server._tcp    SRV      5 0 5269 jabber-gw.fmarier.org.

Then I went to get a free TLS certificate for the above.

Let's Encrypt

The easiest way to get a certificate is to install certbot:

apt install certbot python3-certbot-apache

Then, shutdown your existing webserver if you have one running and request a cert like this:

certbot --duplicate certonly --apache -d jabber-gw.fmarier.org -d fmarier.org

Once you have the cert, you can merge the private and public keys into the file that ejabberd expects:

cat /etc/letsencrypt/live/jabber-gw.fmarier.org/privkey.pem /etc/letsencrypt/live/jabber-gw.fmarier.org/fullchain.pem > ejabberd.pem

and then restart the service:

systemctl restart ejabberd.service

I wrote a cronjob to renew this certificate automatically using certbot.

ejabberd installation

Installing ejabberd on Debian is pretty simple and I mostly followed the steps on the Ubuntu wiki with an additional customization to solve the Pidgin "Not authorized" connection problems.

  1. Install the package, using "admin" as the username for the administrative user:

    apt install ejabberd
    
  2. Set the following in /etc/ejabberd/ejabberd.yml:

    acl:
      admin:
         user:
             - "admin@fmarier.org"
    
    hosts:
      - "fmarier.org"
    
    auth_password_format: scram
    auth_scram_hash: sha512
    fqdn: "jabber-gw.fmarier.org"
    listen:
      -
        port: 3478
        ip: "::"
        transport: udp
        module: ejabberd_stun
        use_turn: false
    
  3. Copy the SSL certificate into the /etc/ejabberd/ directory and set the permissions correctly:

    chown root:ejabberd /etc/ejabberd/ejabberd.pem
    chmod 640 /etc/ejabberd/ejabberd.pem
    
  4. Improve the client-to-server and server-to-server TLS configuration:

    define_macro:
      # ...
      'DH_FILE': "/etc/ejabberd/dhparams.pem"
    
    c2s_dhfile: 'DH_FILE'
    s2s_dhfile: 'DH_FILE'
    
    listen:
      -
        port: 5222
        ip: "::"
        module: ejabberd_c2s
        starttls_required: true
    
    s2s_use_starttls: required
    
  5. Create the required dhparams.pem file:

    openssl dhparam -out /etc/ejabberd/dhparams.pem 2048
    
  6. Optionally disable non-essential modules by commenting them out under the modules: section of /etc/ejabberd/ejabberd.yml:

    ## mod_avatar
    ## mod_mam
    ## mod_muc
    ## mod_private
    ## mod_pubsub
    
  7. Restart the ejabberd daemon:

    systemctl restart ejabberd.service
    
  8. Create a new user account for yourself:

    ejabberdctl register me fmarier.org P@ssw0rd1!
    
  9. Open up the following ports on the server's firewall:

    iptables -A INPUT -p udp --dport 3478 -j ACCEPT
    iptables -A INPUT -p tcp --dport 5222 -j ACCEPT
    iptables -A INPUT -p tcp --dport 5269 -j ACCEPT
    
  10. Optionally create a cronjob in /etc/cron.d/restart-ejabberd to restart ejabberd once a day to ensure it doesn't stop responding to requests after running for a while:

    0 4 * * *      root    /bin/systemctl restart ejabberd.service
    

Note that if you'd like to be able to talk to contacts via the GMail XMPP server, you will unfortunately need to change the s2s_use_starttls setting in step 4 to the following:

  s2s_use_starttls: optional

Client setup

On the client side, if you use Pidgin, create a new account with the following settings in the "Basic" tab:

  • Protocol: XMPP
  • Username: me
  • Domain: fmarier.org
  • Password: P@ssw0rd1!

and the following setting in the "Advanced" tab:

  • Connection security: Require encryption

From this, I was able to connect to the server without clicking through any certificate warnings.

Testing

If you want to make sure that XMPP federation works, add your GMail address as a buddy to the account and send yourself a test message.

In this example, the XMPP address I give to my friends is me@fmarier.org.

Finally, to ensure that your TLS settings are reasonable, use this automated tool to test both the client-to-server (c2s) and the server-to-server (s2s) flows.

Spam protection

If you start having problems with spammers sending messages or subscription requests to your users, you can whitelist the servers that are allowed to federate with yours by putting the following in /etc/ejabberd/ejabberd.yml:

acl:
  trusted_servers:
    server:
      - "cheogram.com"
      - "conference.soprani.ca"
      - "jmp.chat"

access:
  s2s:
    allow: trusted_servers
    deny: all

s2s_access: s2s

The above was all I needed in order to be able to use the JMP SMS-to-XMPP service.