Modern ejabberd configuration

ejabberd is one of the most widely used XMPP servers. It is easy to get it running for text-based messaging with a few configuration changes. However, to obtain a smoothly running modern feature set is harder. The configuration documentation is detailed, but even for a seasoned systems administrator or XMPP guru, a lot of questions remain. Here is an attempt at a simple how-to.

Single-host configuration

Configuration for a single virtual host for ejabberd 17.11.


Replace the modules: section and other variables with the following:

  - "no_sslv3"
  # generated with: openssl dhparam -out dhparams.pem 2048
  'DHFILE': "/etc/ejabberd/dhparams.pem" 

  - "/etc/letsencrypt/live/*/fullchain.pem"
  - "/etc/letsencrypt/live/*/privkey.pem"
s2s_use_starttls: required
s2s_protocol_options: 'TLSOPTS'
s2s_ciphers: 'CIPHERS'
s2s_dhfile: 'DHFILE'
c2s_dhfile: 'DHFILE'

# Will be used for @HOST@ substitution as well
  - ""

modules: # See manual
  # Ad-Hoc Commands (XEP-0050)
  mod_adhoc: {}
  # Additional ejabberdctl commands
  mod_admin_extra: {}
  # Send global announcements
  mod_announce: # recommends mod_adhoc
    access: announce
  # Transparently convert between vcard and pubsub avatars
  mod_avatar: {} # Requires ejabberd >= 17.09, mod_vcard, mod_vcard_xupdate, mod_pusub
  # Simple Communications Blocking (XEP-0191)
  mod_blocking: {} # requires mod_privacy
  # Exchange entity (client) capabilities, e.g. Jingle (XEP-0115)
  mod_caps: {}
  # Send messages to all clients of a user (XEP-0280)
  mod_carboncopy: {}
  # Queue and filter stanzas for inactive clients (improves mobile client battery life, XEP-0352)
  mod_client_state: {}
  # Server configuration with Ad-Hoc commands
  mod_configure: {} # requires mod_adhoc
  # Service discovery, e.g. for MUC, Pub/Sub, HTTP Upload (XEP-0030)
  mod_disco: {}
  # (XMPP over) BOSH: HTTP tunneling for web clients such as JSXC (XEP-0124, XEP-0206)
  mod_bosh: {}
  # Last activity (XEP-0012)
  mod_last: {}
  # Message Archive Management (XEP-0313): Allows clients to catch up
    default: roster
  # Queue messages for offline users (XEP-0160)
    access_max_user_messages: max_user_offline_messages
  # XMPP Ping and periodic keepalives (XEP-0199)
  mod_ping: {}
  # Limit status spam (a full presence authorization requires 4 messages)
  # See also Anti-Spam Workshop
    count: 50
    interval: 600
  # Block some senders (XEP-0016)
  mod_privacy: {}
  # Private XML storage (XEP-0049)
  mod_private: {}
  # Allows clients to request push notifications
  mod_push: {} # Requires ejabberd >= 17.08
  # The roster. You want this.
  mod_roster: {}
  # If you want to pre-configure rosters for workgroups
  mod_shared_roster: {}
  # Allow users to create a vcard, visible to authorized peers (XEP-0054)
    search: false # Privacy
  # vcard-based Avatars (XEP-0153)
  mod_vcard_xupdate: {}
  # Stream management (XEP-0198): Continuity after network interruptions
  mod_stream_mgmt: {}
  # Ask for a dialback, if the certificate does not match (XEP-0220)
  mod_s2s_dialback: {}

  # Additional services

  # Publish/subscribe, e.g. for Movim
    host: "pubsub.@HOST@" # "hosts:" for multiple pubsub services
    access_createnode: local
    ignore_pep_from_offline: false
    last_item_cache: false
    max_items_node: 1000
      max_items: 1000
      - "flat"
      - "pep" # Requires mod_caps.
  # Multi-User (group) Chat
    host: "conference.@HOST@"
      - allow
      - allow: admin
    access_create: muc_create
    access_persistent: muc_create
  # File transfer via HTTP Upload
    host: "userdata.@HOST@"
    docroot: "/srv/userdata/" # Or wherever you would like to have them stored
    put_url: "https://userdata.@HOST@/ud"
      "Access-Control-Allow-Origin": "*"
      "Access-Control-Allow-Methods": "OPTIONS, HEAD, GET, PUT"
      "Access-Control-Allow-Headers": "Content-Type"
  # Expire files on server after specified period
    max_days: 30

    port: 5222
    ip: "::"
    module: ejabberd_c2s
    starttls_required: true
    protocol_options: 'TLSOPTS'
    dhfile: 'DHFILE'
    ciphers: 'CIPHERS'
    max_stanza_size: 65536
    shaper: c2s_shaper
    access: c2s
    port: 5269
    ip: "::"
    module: ejabberd_s2s_in
    max_stanza_size: 131072
    shaper: s2s_shaper
    port: 443
    ip: "::"
    module: ejabberd_http
    tls: true
      "/websocket": ejabberd_http_ws
      "/ud": mod_http_upload
    http_bind: true # Will map to "/http-bind"
    port: 3478
    transport: udp
    module: ejabberd_stun
    auth_type: user
    auth_realm: ""
    use_turn: true
    turn_ip: "" # Your IP address
    port: 3478
    transport: tcp
    module: ejabberd_stun
    auth_type: user
    auth_realm: ""
    use_turn: true
    turn_ip: "" # Your IP address

DNS configuration

You will also require the following entries in the Domain Name System. can be any name you like.                         A                         AAAA  2001:db8::1                     CNAME                         CNAME            SRV   10 1 5222            SRV   10 1 5269 SRV   10 1 5269     SRV   10 1 5269

Certificate requirements

Your certificate should cover,,, and (and

openssl dhparam -out /etc/ejabberd/dhparams.pem 2048
chown ejabberd /etc/ejabberd/dhparams.pem

Updated 2018-01-22: Added c2s_dhfile.

Updated 2018-02-23: Removed thumbnail (useless with modern encrypted uploads), switched to certfiles (available as of ejabberd 17.11), and included dhparam creation.


Let’s stay in touch!

Receive a mail whenever I publish a new post.

About 1-2 Mails per month, no Spam.

Follow me on the Fediverse

Web apps

Leave a Reply

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