How to configure ejabberd to get 100% in XMPP compliance test

Your ejabberd XMPP server is a powerful piece of software. But configuring everything requires several steps. Your best place to start is this hands-on ejabberd installation tutorial and this ejabberd STUN/TURN tutorial. If you have specific questions, first be sure to consult the official ejabberd documentation.

Testing your ejabberd configuration can be a tricky task. Luckily, Daniel Gultsch and Rishi Raj created an XMPP compliance test that will assist you in this process.

ejabberd XMPP server passes most of the XMPP compliance test checks out-of-the box, in default configuration. My fresh installation started at 94%. To get a 100% result, you need to configure a few things to pass the remaining 3 tests.

I’m assuming the configuration from my previous two tutorials on setting up your ejabberd real time IM server and configuring ejabberd video & voice calling.

How to configure ejabberd to get 100% in XMPP compliance test

XEP-0363: HTTP File Upload (CORS Headers)

You need to configure ejabberd to add custom headers to pass this XMPP compliance test. I also recommend creating a dedicated directory at /var/www/upload. For HTTP file upload to work, you don’t need anything else except ejabberd XMPP server. No PHP scripts or web servers. Remember that file upload operates on port 5443. Make sure it’s allowed by your server’s firewall.

  mod_http_upload:
    put_url: https://@HOST@:5443/upload
    docroot: /var/www/upload
    custom_headers:
      "Access-Control-Allow-Origin": "https://@HOST@"
      "Access-Control-Allow-Methods": "GET,HEAD,PUT,OPTIONS"
      "Access-Control-Allow-Headers": "Content-Type"

Make sure /var/www/upload directory is owned by ejabberd. Execute the following command:

chown ejabberd:ejabberd /var/www/upload

Once you configure ejabberd XMPP server with custom_headers, it will pass this XMPP compliance test.

XEP-0156: Discovering Alternative XMPP Connection Methods (HTTP)

To pass this test you need a web daemon on your ejabberd XMPP server. It could be Nginx or Apache. One way or another, it should allow http and https access to two files:

  • https://example.com/.well-known/host-meta
  • https://example.com/.well-known/host-meta.json.

The first file is an XML document without any extension defined in its name. Fill it with the following code:

<?xml version='1.0' encoding='utf-8'?>
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
  <Link rel="urn:xmpp:alt-connections:xbosh"
        href="https://example.com:5443/bosh" />
  <Link rel="urn:xmpp:alt-connections:websocket"
        href="wss://example.com:5443/ws" />
</XRD>

Substitute example.com with the domain name of your ejabberd XMPP server. The code above announces addresses for clients to connect using BOSH and WebSockets. Both services are available in the default ejabberd installation.

The second file is the same data encoded in JSON:

{
  "links": [
    {
      "rel": "urn:xmpp:alt-connections:xbosh",
      "href": "https://example.com:5443/bosh"
    },
    {
      "rel": "urn:xmpp:alt-connections:websocket",
      "href": "wss://example.com:5443/ws"
    }
  ]
}

You can test the accessibility of these files using your regular web browser. Once reachable, your ejabberd server will pass this XMPP compliance test.

XEP-0368: SRV records for XMPP over TLS

To pass this test you need to add four SRV records to your ejabberd XMPP server domain DNS. You already should have STUN/TURN records there, so what you need are these:

_xmpp-client._tcp IN example.com 5 0 5222 example.com 3600
_xmpp-server._tcp IN example.com 5 0 5269 example.com 3600
_xmpps-client._tcp IN example.com 5 0 5223 example.com 3600
_xmpps-server._tcp IN example.com 5 0 5270 example.com 3600

Depending on your domain provider, the form to create these SRV records will vary. Most often the items are as follows:

  • Service: xmpp-client, xmpp-server, xmpps-client, xmpps-server
  • Protocol: tcp
  • Priority: 5
  • Weight: 0
  • Port: 5222, 5269, 5223, 5270
  • Target: example.com
  • TTL: 3600 or Default

Remember to open the 4 ports listed above in your ejabberd XMPP server’s firewall. Allow up to 24 hours for the changes in the DNS to propagate. Then re-run the XMPP compliance test.

Conclusion

XMPP compliance test is a great way to know if your ejabberd is well configured and accessible. It will also give you an option to embed a nice badge certifying you passed all the tests. My personal XMPP server report used during these several tutorials looks like this.

In this ejabberd tutorial series:

Photo by Ali Yahya on Unsplash


Let us know what you think 💬


19 thoughts on “How to configure ejabberd to get 100% in XMPP compliance test

  1. Thank you very much for your guides, I now have my own xmpp server at 95% compliance.
    However I cannot figure out at all how to get XEP-0368 working.

    I’ve added the SRV records, but it still will not pass, do I need to do something with port 443 or direct it to 5223 or 5270 (via nginx)? As I think is the purpose of XEP-0368?

    Reading around the web it seems like there are more steps than just adding the SRV records, but I can’t actually find what it is. Any advice on what else was necessary would be appreciated.

    (On ejabberd 20.07)

    • There should be no issue. OMEMO is mostly a client-side protocol, so try first debugging there. For example, start a chat between two Conversations clients on Android and see if OMEMO works there with your server.

  2. Hi,
    I have followed what is indicated in this tutorial (thank you), but can’t go over 95%. Two tests fail, while checking manually, the dns and http(s) records are there.

  3. Same for me on ejabberd 21.01.

    Clean setup, SQL back-end, followed the first two tutorials up to voice and video calling.

    Stuck at 95% due to XEP-0368 failing.

    I notice the article talks of port 5270 but ejabberd 21.01 does NOT listen on port 5270 out of the box. There is no reference to it in ejabberd.yml and I can see nothing listening on 5270 so there must be an additional step or redirect required.

    netstat -tulpen
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name
    tcp 0 0 43.63.88.100:7777 0.0.0.0:* LISTEN 998 31015 1404/beam.smp
    tcp 0 0 0.0.0.0:42693 0.0.0.0:* LISTEN 998 26091 1404/beam.smp
    tcp 0 0 127.0.0.1:3306 0.0.0.0:* LISTEN 116 26988 1492/mysqld
    tcp 0 0 0.0.0.0:4369 0.0.0.0:* LISTEN 998 25807 1433/epmd
    tcp 0 0 127.0.0.53:53 0.0.0.0:* LISTEN 101 23741 1100/systemd-resolv
    tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 0 25782 1392/sshd: /usr/sbi
    tcp 0 0 0.0.0.0:28888 0.0.0.0:* LISTEN 0 32065 2250/lfd Cluster Se
    tcp6 0 0 :::1883 :::* LISTEN 998 30955 1404/beam.smp
    tcp6 0 0 :::8443 :::* LISTEN 998 30953 1404/beam.smp
    tcp6 0 0 :::5280 :::* LISTEN 998 30954 1404/beam.smp
    tcp6 0 0 :::5443 :::* LISTEN 998 30952 1404/beam.smp
    tcp6 0 0 :::5349 :::* LISTEN 998 30957 1404/beam.smp
    tcp6 0 0 :::5222 :::* LISTEN 998 30950 1404/beam.smp
    tcp6 0 0 :::4369 :::* LISTEN 998 25808 1433/epmd
    tcp6 0 0 :::5269 :::* LISTEN 998 30951 1404/beam.smp
    tcp6 0 0 :::22 :::* LISTEN 0 25793 1392/sshd: /usr/sbi
    udp 0 0 127.0.0.53:53 0.0.0.0:* 101 23740 1100/systemd-resolv
    udp 0 0 0.0.0.0:68 0.0.0.0:* 0 22348 1029/dhclient
    udp 0 0 127.0.0.1:323 0.0.0.0:* 0 24885 1345/chronyd
    udp 0 0 0.0.0.0:3478 0.0.0.0:* 998 30956 1404/beam.smp
    udp6 0 0 ::1:323 :::* 0 24886 1345/chronyd

    FWIW on prosody I can get 100% compliance and pass XEP-0368 without having any reference to port 5270 in DNS or otherwise.

      • Yes Marek, I got 100% now on the compliance check. I perused the XEP-0368 and compared to how I had it working to 100% pass rate on another XMPP server product before. There was indeed no need for legacy s2s. What WAS needed however was a legacy 5223 c2s.

        So my listen is:

        listen:

        port: 5222
        ip: “::”
        module: ejabberd_c2s
        max_stanza_size: 524288
        shaper: c2s_shaper
        access: c2s
        starttls_required: true

        port: 5223
        ip: “::”
        module: ejabberd_c2s
        max_stanza_size: 524288
        shaper: c2s_shaper
        access: c2s
        tls: true

        port: 5269
        ip: “::”
        module: ejabberd_s2s_in
        max_stanza_size: 524288

        The 5223 port config being the pertinent part.

        For the SRV records I am indeed only showing 5222, 5223 and 5269 for this XEP plus the STUN and TURN stuff from your Voice / Video calling tutorial. Example SRV records:

        ;; SRV Records
        _stuns._tcp.example.com. 1 IN SRV 10 10 5349 x.example.com.
        _stun._tcp.example.com. 1 IN SRV 10 10 3478 x.example.com.
        _stun._udp.example.com. 1 IN SRV 10 10 3478 x.example.com.
        _turns._tcp.example.com. 1 IN SRV 10 10 5349 x.example.com.
        _turn._tcp.example.com. 1 IN SRV 10 10 3478 x.example.com.
        _turn._udp.example.com. 1 IN SRV 10 10 3478 x.example.com.
        _xmpp-client._tcp.example.com. 1 IN SRV 10 10 5222 x.example.com.
        _xmpps-client._tcp.example.com. 1 IN SRV 10 10 5223 x.example.com.
        _xmpp-server._tcp.example.com. 1 IN SRV 10 10 5269 x.example.com.

        This combo of SRV records and listeners gets me 100%. Obviously need to open on firewall as well. Compliance checker tries to connect on port 5223. Now I am good. Smooth move over to ejabberd!

        • Glad you figured it out! Indeed it’s the _xmpps_client that is required, not the _server :)

          • Hello Marek,
            sorry for asking again – but I can’t get “100%” due to the XEP-0368 issue.
            I reproduced accurate the steps, which Michael F. pointed out
            Here are the relevant DNS records (for domain “example.com” host “xmpp.example.com”):
            ————————————-88——————————-
            …and listeners in “ejabberd.yml”
            ——————————————88—————————————-
            I don’t see any mistake, do you?
            Thank you for reading!
            F.

  4. sorry – something went wrong with formatting the code block:
    _stun._tcp.example.com. SRV 0 0 3478 xmpp.example.com.
    _stun._udp.example.com. SRV 0 0 3478 xmpp.example.com.
    _stuns._tcp.example.com. SRV 0 0 5349 xmpp.example.com.
    _turn._udp.example.com. SRV 0 0 3478 xmpp.example.com.
    _turns._tcp.example.com. SRV 0 0 5349 xmpp.example.com.
    _xmpp-client._tcp.example.com. SRV 1 1 5222 xmpp.example.com.
    _xmpp-server._tcp.example.com. SRV 1 1 5269 xmpp.example.com.
    _xmpps-client._tcp.example.com. SRV 1 1 5223 xmpp.example.com.
    _xmpps-server._tcp.example.com. SRV 1 1 5270 xmpp.example.com.

    port: 5222
    ip: “::”
    module: ejabberd_c2s
    max_stanza_size: 524288
    shaper: c2s_shaper
    access: c2s
    starttls_required: true


    port: 5223
    ip: “::”
    module: ejabberd_c2s
    max_stanza_size: 524288
    shaper: c2s_shaper
    access: c2s
    tls: true


    port: 5269
    ip: “::”
    module: ejabberd_s2s_in
    max_stanza_size: 524288


    port: 5270
    ip: “::”
    tls: true
    module: ejabberd_s2s_in
    max_stanza_size: 524288


    port: 3478
    ip: “::”
    transport: udp
    module: ejabberd_stun
    use_turn: true
    turn_min_port: 49152
    turn_max_port: 65535
    turn_ipv4_address: “aaa.bbb.ccc.ddd”
    turn_ipv6_address: “aaaa:bbbb:cccc:ddd::e”

    port: 5349
    transport: tcp
    module: ejabberd_stun
    use_turn: true
    tls: true
    turn_min_port: 49152
    turn_max_port: 65535
    ip: 0.0.0.0
    turn_ipv4_address: “aaa.bbb.ccc.ddd”
    turn_ipv6_address: “aaaa:bbbb:cccc:ddd::e”

    • Please check the SRV records code block again, I think you are missing the TCP turn line:
      _turn._tcp IN SRV 0 0 3478 example.com.

  5. Thank you.
    I’m wondering if I got something completely wrong here – from my perspective, the SRV DNS records are missing the actual ‘SRV’ parameter – why is that?

  6. Hello, I have an even more serious problem, I cannot establish a connection via websocket, it gives me the following error:
    WebSocket connection to ‘wss://midominio.com:5443/ws’ failed: _connect @ websocket.js:156
    error websocket error {“istrusted”:true}
    error websocket closed unexcectedly

  7. Thank you so much for this howto
    It is possible to comply with “XEP-0368: SRV records for XMPP over TLS”, having DDNS (like duckdns for example)?

    Best regards!

Leave a Comment


This site uses Akismet to reduce spam. Learn how your comment data is processed.