> ## Content Index
> Fetch the complete content index at: https://www.process-one.net/llms.txt
> Use this file to discover other available public pages before exploring further.

# Matrix gateway setup with ejabberd
- URL: https://www.process-one.net/blog/matrix-gateway-setup-with-ejabberd/
- Published: 2024-03-07T11:00:00.000Z
- Updated: 2025-06-05T20:45:47.000Z
- Description: As of version 24.02, ejabberd is shipped with a Matrix gateway and can participate in the Matrix federation. This means that an XMPP client can exchange messages with Matrix users or rooms. Let’s see how to configure your ejabberd to enable this gateway.
- Author: Jérôme Sautret

## Configuration in ejabberd

### HTTPS listener

First, add an [HTTP handler](https://docs.ejabberd.im/admin/configuration/listen/?ref=process-one.net#ejabberd-http), as Matrix uses HTTPS for Server-Server API.

In the [listen section](https://docs.ejabberd.im/admin/configuration/toplevel/?ref=process-one.net#listen) of your `ejabberd.yml` configuration file, add a handler on Matrix port `8448` for path `/_matrix` that calls the `mod_matrix_gw` module. You must enable TLS on this port to accept HTTPS connections (unless a proxy already handles HTTPS in front of ejabberd) and provide a valid certificate for your Matrix domain (see `matrix_domain` below). You can set this certificate using the [certfile option](https://docs.ejabberd.im/admin/configuration/listen-options/?ref=process-one.net#certfile) of the listener, like in the example below, or listing it in the [certfiles top level option](https://docs.ejabberd.im/admin/configuration/toplevel/?ref=process-one.net#certfiles).

*Example*:

```yaml
listen:
  -
    port: 5222
    module: ejabberd_c2s
  -
    port: 8448 # Matrix federation
    module: ejabberd_http
    tls: true
    certfile: "/opt/ejabberd/conf/matrix.pem"
    request_handlers:
      "/_matrix": mod_matrix_gw

```

If you want to use a non-standard port instead of `8448`, you must serve a `/.well-known/matrix/server` on your Matrix domain (see below).

### Server-to-Server

You must enable s2s (Server-to-Server federation) by setting an [access rule](https://docs.ejabberd.im/admin/configuration/basic/?ref=process-one.net#access-rules) `all` or `allow` on [s2s\_access](https://docs.ejabberd.im/admin/configuration/toplevel/?ref=process-one.net#s2s-access) top level option:

*Example*:

```yaml
s2s_access: s2s

access_rules:
  local:
    - allow: local
  c2s:
    - deny: blocked
    - allow
  s2s:
    - allow # to allow Matrix federation

```

### Matrix gateway module

Finally, add [mod\_matrix\_gw](https://docs.ejabberd.im/admin/configuration/modules/?ref=process-one.net#mod-matrix%5Fgw) module in the [modules](https://docs.ejabberd.im/admin/configuration/toplevel/?ref=process-one.net#modules) list.

*Example*:

```yaml
modules:
  mod_matrix_gw:
    matrix_domain: "matrixdomain.com"
    key_name: "key1"
    key: "SU4mu/j8b8A1i1EdyxIcKlFlrp+eSRBIlZwGyHP7Mfo="

```

#### `matrix_domain`

Replace `matrixdomain.com` with your Matrix domain. That domain must resolve to your ejabberd server or [serve a file](https://www.process-one.net/blog/matrix-gateway-setup-with-ejabberd/%60https://matrix-org.github.io/matrix-authentication-service/setup/well-known.html%60) https://matrixdomain.com/.well-known/matrix/server that contains a JSON file with the address and Matrix port (as defined by the Matrix HTTPS handler, see above) of your ejabberd server:

**Example:**

```json
{
   "m.server": "ejabberddomain.com:8448"
}

```

#### `key_name` & `key`

The `key_name` is arbitrary. The `key` value is your base64-encoded ed25519 [Matrix signing key](https://matrix-org.github.io/dendrite/installation/manual/signingkeys?ref=process-one.net). It can be generated by Matrix tools or in an Erlang shell using the command `base64:encode(element(2, crypto:generate_key(eddsa, ed25519))).`:

**Example:**

```shell
$ erl
Erlang/OTP 24 [erts-12.3.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [dtrace]

Eshell V12.3.1 (abort with ^G)
1> base64:encode(element(2, crypto:generate_key(eddsa, ed25519))).
<<"SU4mu/j8b8A1i1EdyxIcKlFlrp+eSRBIlZwGyHP7Mfo=">>
2> q().
ok

```

Once your configuration is ready, you can restart ejabberd.

## Testing

To check if your setup is correct, go to the following page and enter your Matrix domain (as set by the `matrix_domain` option):  
[https://federationtester.matrix.org/](https://federationtester.matrix.org/?ref=process-one.net)

This page should list any problem related to Matrix on your ejabberd installation.

## Routing  

What messages are routed to an external Matrix server?

### Implicit routing

Let’s say an XMPP client connected to your ejabberd server sends a message to a JID `user1@domain1.com`. If `domain1.com` is defined by the [hosts](https://docs.ejabberd.im/admin/configuration/toplevel/?ref=process-one.net#hosts) parameter of your ejabberd server (i.e. it’s one of your XMPP domains), the message will be routed locally. If it’s not, ejabberd will try to establish an XMPP Server-to-Server connection to a remote `domain1.com` XMPP server.

If this fails (i.e. there is no such external XMPP domain), then ejabberd will try to route the message over the Matrix federation by transforming the JID `user1@domain1.com` into the Matrix ID `@user1:domain1.com` and attempt to open a connection to the remote Matrix domain.

This behavior is enabled when the `matrix_id_as_jid` option in the `mod_matrix_gw` module is set to `true`. 

### Explicit routing

It is also possible to route messages explicitly to the Matrix federation by setting the option `matrix_id_as_jid` in the `mod_matrix_gw` module to **`false`**:

Example:

```
modules:
  mod_matrix_gw:
    host: "matrix.@HOST@"
    matrix_domain: "matrixdomain.com"
    key_name: "key1"
    key: "SU4mu/j8b8A1i1EdyxIcKlFlrp+eSRBIlZwGyHP7Mfo="
    matrix_id_as_jid: false
```

In this case, the automatic fallback from XMPP to Matrix when XMPP Server-to-Server fails is **enabled**: if ejabberd cannot deliver a message to an XMPP domain, it will try to route it via Matrix by transforming the JID (e.g. `user@matrixdomain.tld`) into a Matrix ID (e.g. `@user:matrixdomain.tld`).

To send a message to the Matrix user `@user:remotedomain.com`, the XMPP client must send a message to the JID `user%remotedomain.com@matrix.xmppdomain.com`, where `matrix.xmppdomain.com` is the JID of the gateway service as set by the `host` option of the `mod_matrix_gw` module (the keyword `@HOST@` is replaced with the XMPP domain of the server). If `host` is not set, the Matrix gateway JID is your XMPP domain with the `matrix.` prefix added.

---

#### 🛠️ Update n°2 (2025/06/05 22:44)

Thanks to the feedback from the community, this post has been updated to reflect the [correct behavior](https://github.com/processone/docs.ejabberd.im/commit/57ae13bf40ed?ref=process-one.net) of the `matrix_id_as_jid` option in `mod_matrix_gw`.

- `matrix_id_as_jid: true` → enables implicit fallback to Matrix when XMPP s2s fails.
- `matrix_id_as_jid: false` (default) → disables fallback; messages must be explicitly routed to the Matrix gateway.