Skip to content

# Basic Configuration

## XMPP Domains

### Host Names

ejabberd supports managing several independent XMPP domains on a single ejabberd instance, using a feature called virtual hosting.

The option `hosts` defines a list containing one or more domains that ejabberd will serve.

Of course, the `hosts` list can contain just one domain if you do not want to host multiple XMPP domains on the same instance.

Examples:

- Serving one domain:

      hosts: [example.org]

- Serving three domains:

      hosts:
        - example.net
        - example.com
        - jabber.somesite.org

Notice that Unicode is used natively by XMPP, Erlang/OTP, YAML... and ejabberd. You can setup non-latin host names using Unicode/UTF8. Since ejabberd 25.08 the host can be expressed in IDNA/punycode. For example:

    hosts:
      - localhost1
      - locälhost2
      - 日本語
      - xn--loclhost4-x2a

### Virtual Hosting

When managing several XMPP domains in a single instance, those domains are truly independent. It means they can even have different configuration parameters.

Options can be defined separately for every virtual host using the `host_config` option.

Examples:

- Domain `example.net` is using the internal authentication method while domain `example.com` is using the LDAP server running on the domain `localhost` to perform authentication:

      host_config:
        example.net:
          auth_method: internal
        example.com:
          auth_method: ldap
          ldap_servers:
            - localhost
          ldap_uids:
            - uid
          ldap_rootdn: "dc=localdomain"
          ldap_password: ""

- Domain `example.net` is using SQL to perform authentication while domain `example.com` is using the LDAP servers running on the domains `localhost` and `otherhost`:

      host_config:
        example.net:
          auth_method: sql
          sql_type: odbc
          sql_server: "DSN=ejabberd;UID=ejabberd;PWD=ejabberd"
        example.com:
          auth_method: ldap
          ldap_servers:
            - localhost
            - otherhost
          ldap_uids:
            - uid
          ldap_rootdn: "dc=example,dc=com"
          ldap_password: ""

To define specific ejabberd modules in a virtual host, you can define the global `modules` option with the common modules, and later add specific modules to certain virtual hosts. To accomplish that, instead of defining each option in `host_config` use `append_host_config` with the same syntax.

In this example three virtual hosts have some similar modules, but there are also other different modules for some specific virtual hosts:

    ## This ejabberd server has three vhosts:
    hosts:
      - one.example.org
      - two.example.org
      - three.example.org

    ## Configuration of modules that are common to all vhosts
    modules:
      mod_roster:    {}
      mod_configure: {}
      mod_disco:     {}
      mod_private:   {}
      mod_time:      {}
      mod_last:      {}
      mod_version:   {}

    append_host_config:
      ## Add some modules to vhost one:
      one.example.org:
        modules:
          mod_muc:
            host: conference.one.example.org
          mod_ping: {}
      ## Add a module just to vhost two:
      two.example.org:
        modules:
          mod_muc:
            host: conference.two.example.org

## Logging

ejabberd configuration can help a lot by having the right amount of logging set up.

There are several toplevel options to configure logging:

- `loglevel`: Verbosity of log files generated by ejabberd.
- `hide_sensitive_log_data`: Privacy option to disable logging of IP address or sensitive data.
- `log_modules_fully`: Modules that will log everything independently from the general `loglevel` option.
- `log_rotate_size`
- `log_rotate_count`: Setting count to N keeps N rotated logs. Setting count to 0 does not disable rotation, it instead rotates the file and keeps no previous versions around. Setting size to X rotate log when it reaches X bytes.
- `log_burst_limit_count`
- `log_burst_limit_window_time`

The values in default configuration file are:

    log_rotate_size: 10485760
    log_rotate_count: 1

For example, log warning and higher messages, but all c2s messages, and hide sensitive data:

    loglevel: warning
    hide_sensitive_log_data: true
    log_modules_fully: [ejabberd_c2s]

## Default Language

The `language` option defines the default language of server strings that can be seen by XMPP clients. If a XMPP client does not support `xml:lang`, ejabberd uses the language specified in this option.

The option syntax is:

`language: Language`: The default value is `en`. In order to take effect there must be a translation file `Language.msg` in ejabberd’s `msgs` directory.

For example, to set Russian as default language:

    language: ru

The page Internationalization and Localization provides more details.

## CAPTCHA

Some ejabberd modules can be configured to require a CAPTCHA challenge on certain actions, for instance mod_block_strangers, mod_muc, mod_register, and mod_register_web. If the client does not support CAPTCHA Forms (`XEP-0158`), a web link is provided so the user can fill the challenge in a web browser.

Example scripts are provided that generate the image using ImageMagick’s Convert program and Ghostscript fonts. Remember to install those dependencies: in Debian install the `imagemagick` and `gsfonts` packages; in container images check their documentation for details.

The relevant top-level options are:

- `captcha_cmd``: Path | Module`: Full path to a script that generates the image, or name of a module that supports generating CAPTCHA images (mod_ecaptcha, mod_captcha_rust). The default value disables the feature: `undefined`

- `captcha_url``: URL | auto`: An URL where CAPTCHA requests should be sent, or `auto` to determine the URL automatically. The default value is `auto`.

And finally, configure `request_handlers` for the `ejabberd_http` listener with a path handled by `ejabberd_captcha`, where the CAPTCHA images will be served.

Example configuration:

    hosts: [example.org]

    captcha_cmd: /lib/ejabberd-24.12/priv/bin/captcha.sh # make install or install-rel
    # captcha_cmd: /opt/ejabberd-24.12/lib/captcha.sh # Binary installers and container images
    # captcha_cmd: tools/captcha.sh # if ejabberd started with: make relive
    # captcha_cmd: mod_ecaptcha # if installed: ejabberdctl module_install mod_ecaptcha

    captcha_url: auto
    ## captcha_url: http://example.org:5280/captcha
    ## captcha_url: https://example.org:443/captcha
    ## captcha_url: http://example.com/captcha

    listen:
      -
        port: 5280
        module: ejabberd_http
        request_handlers:
          /captcha: ejabberd_captcha

## ACME

ACME is used to automatically obtain SSL certificates for the domains served by ejabberd, which means that certificate requests and renewals are performed to some CA server (aka "ACME server") in a fully automated mode.

### Setting up ACME

In ejabberd, ACME is configured using the `acme` top-level option, check there the available options and example configuration.

The automated mode is enabled by default. However, some configuration of ejabberd is still required, because ACME requires HTTP challenges: an ACME remote server will connect to your ejabberd server on HTTP port 80 during certificate issuance.

For that reason you must have an `ejabberd_http` listener with TLS disabled handling an "ACME well known" path. For example:

    listen:
      -
        module: ejabberd_http
        port: 5280
        tls: false
        request_handlers:
          /.well-known/acme-challenge: ejabberd_acme

Note that the ACME protocol requires challenges to be sent on port 80. Since this is a privileged port, ejabberd cannot listen on it directly without root privileges. Thus you need some mechanism to forward port 80 to the port defined by the listener (port 5280 in the example above). There are several ways to do this: using NAT, setcap (Linux only), or HTTP front-ends (e.g. `sslh`, `nginx`, `haproxy` and so on). Pick one that fits your installation the best, but DON'T run ejabberd as root.

If you see errors in the logs with ACME server problem reports, it's highly recommended to change `ca_url` option in the `acme` top-level option to the URL pointing to some staging ACME environment, fix the problems until you obtain a certificate, and then change the URL back and retry using `request-certificate` ejabberdctl command (see below). This is needed because ACME servers typically have rate limits, preventing you from requesting certificates too rapidly and you can get stuck for several hours or even days. By default, ejabberd uses Let's Encrypt authority. Thus, the default value of `ca_url` option is `https://acme-v02.api.letsencrypt.org/directory` and the staging URL will be `https://acme-staging-v02.api.letsencrypt.org/directory`:

    acme:
      ## Staging environment
      ca_url: https://acme-staging-v02.api.letsencrypt.org/directory
      ## Production environment (the default):
      # ca_url: https://acme-v02.api.letsencrypt.org/directory

The automated mode can be disabled by setting `auto` option to `false` in the `acme` top-level option:

    acme:
      auto: false

In this case automated renewals are still enabled, however, in order to request a new certificate, you need to run request_certificate API command:

    ejabberdctl request-certificate all

If you only want to request certificates for a subset of the domains, run:

    ejabberdctl request-certificate domain.tld,pubsub.domain.tld,server.com,conference.server.com,...

You can view the certificates obtained using ACME and list_certificates:

    $ ejabberdctl list-certificates
    domain.tld /path/to/cert/file1 true
    server.com /path/to/cert/file2 false

The output is mostly self-explained: every line contains the domain, the corresponding certificate file, and whether this certificate file is used or not. A certificate might not be used for several reasons: mostly because ejabberd detects a better certificate (i.e. not expired, or having a longer lifetime). It's recommended to revoke unused certificates if they are not yet expired (see below).

At any point you can revoke a certificate using revoke_certificate: pick the certificate file from the listing above and run:

    ejabberdctl revoke-certificate /path/to/cert/file

If the commands return errors, consult the log files for details.

### ACME implementation details

In nutshell, certification requests are performed in two phases. Firstly, ejabberd creates an account at the ACME server. That is an EC private key. Secondly, a certificate is requested. In the case of a revocation, no account is used - only a certificate in question is needed. All information is stored under `acme` directory inside spool directory of ejabberd (typically `/var/lib/ejabberd`). An example content of the directory is the following:

    $ tree /var/lib/ejabberd
    /var/lib/ejabberd
    ├── acme
    │   ├── account.key
    │   └── live
    │       ├── 251ce180d964e98a2f18b65504df2ab7c55943e2
    │       └── 93816a8429ebbaa75574eb3f59d4a806b67d6917
    ...

Here, `account.key` is the EC private key used to identify the ACME account. You can inspect its content using `openssl` command:

    openssl ec -text -noout -in /var/lib/ejabberd/acme/account.key

Obtained certificates are stored under `acme/live` directory. You can inspect any of the certificates using `openssl` command as well:

    openssl x509 -text -noout -in /var/lib/ejabberd/acme/live/251ce180d964e98a2f18b65504df2ab7c55943e2

In the case of errors, you can delete the whole `acme` directory - ejabberd will recreate its content on next certification request. However, don't delete it too frequently - usually there is a rate limit on the number of accounts and certificates an ACME server creates. In particular, for Let's Encrypt the limits are described here.

## Access Rights

This section describes new ACL syntax introduced in ejabberd 16.06. For old access rule and ACL syntax documentation, please refer to configuration document archive

### ACL

Access control in ejabberd is performed via Access Control Lists (ACLs), using the `acl` option. The declarations of ACLs in the configuration file have the following syntax:

    acl:
      ACLName:
        ACLType: ACLValue

`ACLName` is any name you may want to give, and later can use it in other options to reference that ACL. The following `ACLName` are pre-defined:

- `all`: Matches any JID.

- `none`: Matches no JID.

`ACLType: ACLValue` can be one of the following:

- `all`: Matches all JIDs. Example:

      acl:
        world: all

- `user: Username`: Matches the user with the name `Username` on any of the local virtual host. Example:

      acl:
        admin:
          user: yozhik

- `user: {Username: Server} | Jid`: Matches the user with the JID `Username@Server` and any resource. Example:

      acl:
        admin:
          - user: peter@example.org
          - user:
              yozhik@example.org
          - user: {susan: example.org}
          - user:
              jan: example.org

- `server: Server`: Matches any JID from server `Server`. Example:

      acl:
        exampleorg:
          server: example.org

- `resource: Resource`: Matches any JID with a resource `Resource`. Example:

      acl:
        mucklres:
          resource: muckl

- `shared_group: Groupname`: Matches any member of a Shared Roster Group with name `Groupname` in the virtual host. Example:

      acl:
        techgroupmembers:
          shared_group: techteam

- `shared_group: {Groupname: Server}`: Matches any member of a Shared Roster Group with name `Groupname` in the virtual host `Server`. Example:

      acl:
        techgroupmembers:
          - shared_group: {techteam: example.org}
          - shared_group:
              secteam: example.org

- `ip: Network`: Matches any IP address from the `Network`. Example:

      acl:
        loopback:
          ip:
            - 127.0.0.0/8
            - "::1"

- `user_regexp: Regexp`: Matches any local user with a name that matches `Regexp` on local virtual hosts. Example:

      acl:
        tests:
          user_regexp: "^test[0-9]*$"

- `user_regexp: {Regexp: Server} | JidRegexp`: Matches any user with a name that matches `Regexp` at server `Server`. Example:

      acl:
        tests:
          user_regexp:
            - "^test1": example.org
            - "^test2@example.org"

- `server_regexp: Regexp`: Matches any JID from the server that matches `Regexp`. Example:

      acl:
        icq:
          server_regexp: "^icq\\."

- `resource_regexp: Regexp`: Matches any JID with a resource that matches `Regexp`. Example:

      acl:
        icq:
          resource_regexp: "^laptop\\."

- `node_regexp: {UserRegexp: ServerRegexp}`: Matches any user with a name that matches `UserRegexp` at any server that matches `ServerRegexp`. Example:

      acl:
        yozhik:
          node_regexp:
            "^yozhik$": "^example.(com|org)$"

- `user_glob: Glob`:

- `user_glob: {Glob: Server}`:

- `server_glob: Glob`:

- `resource_glob: Glob`:

- `node_glob: {UserGlob: ServerGlob}`: This is the same as above. However, it uses shell glob patterns instead of regexp. These patterns can have the following special characters:

  - `*`: matches any string including the null string.

  - `?`: matches any single character.

  - `[...]`: matches any of the enclosed characters. Character ranges are specified by a pair of characters separated by a `-`. If the first character after `[` is a `!`, any character not enclosed is matched.

### Access Rules

The `access_rules` option is used to allow or deny access to different services. The syntax is:

    access_rules:
      AccessName:
        - allow|deny: ACLName|ACLDefinition

Each definition may contain arbitrary number of `- allow` or `- deny` sections, and each section can contain any number of acl rules (as defined in previous section, it recognizes one additional rule `acl: ACLName` that matches when the ACL named `ACLName` matches). If no ACL name or definition is defined, the ACL `all` is applied.

Definition's `- allow` and `- deny` sections are processed in top to bottom order, and first one for which all listed acl rules matches is returned as result of access rule. If no rule matches, `deny` is returned.

To simplify configuration two shortcut version are available: `- allow: acl` and `- allow`, example below shows equivalent definitions where short or long version are used:

    access_rules:
      a_short: admin
      a_long:
        - acl: admin
      b_short:
        - deny: banned
        - allow
      b_long:
        - deny:
          - acl: banned
        - allow:
          - all

If you define specific Access rights in a virtual host, remember that the globally defined Access rights have precedence over those. This means that, in case of conflict, the Access granted or denied in the global server is used and the Access of a virtual host doesn't have effect.

Example:

    access_rules:
      configure:
        - allow: admin
      something:
        - deny: someone
        - allow
      s2s_banned:
        - deny: problematic_hosts
        - deny:
          - acl: banned_forever
        - deny:
          - ip: 222.111.222.111/32
        - deny:
          - ip: 111.222.111.222/32
        - allow
      xmlrpc_access:
        - allow:
          - user: peter@example.com
        - allow:
          - user: ivone@example.com
        - allow:
          - user: bot@example.com
          - ip: 10.0.0.0/24

The following `AccessName` are pre-defined:

- `all`: Always returns the value ‘`allow`’.

- `none`: Always returns the value ‘`deny`’.

### Shaper Rules

The `shaper_rules` top-level option declares shapers to use for matching user/hosts. The syntax is:

    shaper_rules:
      ShaperRuleName:
        - Number|ShaperName: ACLName|ACLDefinition

Semantic is similar to that described in Access Rights section, only difference is that instead using `- allow` or `- deny`, name of shaper or number should be used.

Examples:

    shaper_rules:
      connections_limit:
        - 10:
          - user: peter@example.com
        - 100: admin
        - 5
      download_speed:
        - fast: admin
        - slow: anonymous_users
        - normal
      log_days: 30

### Limiting Opened Sessions

The special access `max_user_sessions` specifies the maximum number of sessions (authenticated connections) per user. If a user tries to open more sessions by using different resources, the first opened session will be disconnected. The error `session replaced` will be sent to the disconnected session. The value for this option can be either a number, or `infinity`. The default value is `infinity`.

The syntax is:

    shaper_rules:
      max_user_sessions:
        - Number: ACLName|ACLDefinition

This example limits the number of sessions per user to 5 for all users, and to 10 for admins:

    shaper_rules:
      max_user_sessions:
        - 10: admin
        - 5

### Connections to Remote Server

The special access `max_s2s_connections` specifies how many simultaneous S2S connections can be established to a specific remote XMPP server. The default value is `1`. There’s also available the access `max_s2s_connections_per_node`.

The syntax is:

    shaper_rules:
      max_s2s_connections: MaxNumber

For example, let's allow up to 3 connections with each remote server:

    shaper_rules:
      max_s2s_connections: 3

## Shapers

The `shaper` top-level option defines limitations in the connection traffic. The basic syntax is:

    shaper:
      ShaperName: Rate

where `Rate` stands for the maximum allowed incoming rate in bytes per second. When a connection exceeds this limit, ejabberd stops reading from the socket until the average rate is again below the allowed maximum.

This example defines a shaper with name `normal` that limits traffic speed to 1,000bytes/second, and another shaper with name `fast` that limits traffic speed to 50,000bytes/second:

    shaper:
      normal: 1000
      fast: 50000

You can use the full syntax to set the `BurstSize` too:

    shaper:
      ShaperName:
        rate: Rate
        burst_size: BurstSize

With `BurstSize` you can allow client to send more data, but its amount can be clamped reasonably. Each connection is allowed to send `BurstSize` of data before processing is delayed, and that amount is replenished by `Rate` each second, but never more than what `BurstSize` allows. This allows the client to send quite a bit of data at once, but still have limited amount of data to send on constant basis.

In this example, the `normal` shaper has `Rate` set to `1000` and the `BurstSize` takes that same value. The `not_normal` shaper has the same `Rate` that before, and sets a higher `BurstSize`:

    shaper:
      normal: 1000
      not_normal:
        rate: 1000
        burst_size: 20000