How to Moderate your Synpase Matrix Server with Draupnir

Introduction

Moderating a Matrix Synapse server can quickly become a challenging task, especially as a community grows. While Synapse provides some basic moderation tools — like kicking, banning, or deactivating user accounts — these actions are mostly manual and reactive. There’s no built-in automation, and trying to handle spam or abuse across multiple rooms or federated instances can quickly become overwhelming.

That’s why I turned to Draupnir, a powerful and flexible Matrix moderation bot. As a more advanced fork of Mjolnir, Draupnir enhances what’s possible with Synapse moderation. It automates repetitive tasks and introduces smarter tools for managing abuse. One of its most useful features is support for policy rooms (also called policy lists) — shared spaces where trusted communities maintain ban lists. By subscribing to these, Draupnir lets my server benefit from the moderation efforts of others, which makes a big difference when dealing with coordinated spam or abusive behavior.

In this blog post, I’ll walk you through how to set up and use Draupnir in a practical, hands-on way. I’ll start by going over the prerequisites you’ll need to meet before you can run Draupnir — things like preparing a dedicated Matrix user for the bot and ensuring Docker is set up on your system. From there, I’ll explain how to install Draupnir using Docker, including how to configure the container and persist its settings.

After the installation, I’ll show you how to connect Draupnir to your Synapse server. This involves inviting the bot to rooms, assigning it the necessary permissions, and managing it effectively as a server admin. Once that’s in place, I’ll go into more detail about Draupnir’s features — especially how to use policy lists to subscribe to existing ban regimes and automatically apply them to your own server.

Finally, I’ll show you how to unlock even more moderation power by integrating Synapse modules like synapse-http-antispam. I’ll cover how to install and configure it, and how to make use of Synapse’s spam checker callbacks to create custom moderation logic that works alongside Draupnir. By the end, you’ll have a modern, automated moderation setup that makes it much easier to keep your Matrix space clean and safe.

Whether you’re running a private community or a public instance, I hope this guide will help you take moderation to the next level with Draupnir and the Matrix ecosystem.

Prerequisits

To use Draupnir effectively, there are several prerequisites you need to fulfill before jumping into the installation process. Most importantly, you need to be running your own Synapse Matrix server. Draupnir is a powerful moderation bot, but many of its core features depend on Synapse-specific capabilities, such as the ability to install and configure server modules. If you’re using a hosted Matrix service without admin access to the Synapse backend, your options will be much more limited.

In this tutorial, I’ll be deploying Draupnir using Docker, so you’ll need to have Docker installed and running on your server. This could be a standalone Linux server, or something more user-friendly like a Synology NAS which is capable of running container manager. In any case the following setup assumes you’re comfortable working in the terminal and managing containers.

Next, you must technically be able to install Synapse modules (terminal access), as Synapse doesn’t come with moderation-related modules enabled by default. Later in the guide, I’ll show how to install and integrate modules like synapse-http-antispam, which are key to unlocking advanced spam and abuse filtering. Without admin-level access to the Synapse configuration files and restart control, you won’t be able to fully integrate Draupnir’s capabilities.

You’ll also need to create a dedicated Matrix room that will act as Draupnir’s command and control center (control room). This room (e.g. “#bot:example.com”) must be private (invite-only) and unencrypted, as Draupnir can’t operate properly in encrypted rooms. If your Synapse server is configured to prevent the creation of non-encrypted rooms, you’ll need to temporarily change that setting to allow one to be created. You can revert this restriction after the room has been successfully set up. This control room is where you’ll interact with the bot, issue commands, and manage policy lists and get feedback from the bot (which is really verbose). It’s important to understand that any user with access to this room has full control over Draupnir, and by extension, moderation control over your entire server — depending on the bot’s power level in each room.

In addition to the room, you’ll need to create a separate Matrix user account specifically for Draupnir. This account acts as the identity the bot uses to moderate rooms, send messages, redact content, and enforce bans. You’ll need to generate an admin access token for this user, which will be added to the Draupnir configuration later on. Don’t worry — I’ll explain exactly how to get this token when we get to that step. For now, just make sure the account exists, and invite it to the command and control room you created earlier.

You don’t need to invite the bot to all the rooms you want it to moderate right away. Once Draupnir is running, you’ll be able to issue a command that automatically invites it to additional rooms. For now, just make sure it’s in the moderation room so you can interact with it after setup.

With all of that in place — a working Synapse server, Docker access, the ability to install modules, a command and control room, and a dedicated Matrix user for the bot — you’re ready to move on to the next step: installing Draupnir.

Draupnir Installation

To deploy Draupnir in a clean and maintainable way, we’ll be using Docker with a docker-compose.yaml configuration. This makes it easy to manage Draupnir alongside other services, ensures it restarts automatically if needed, and keeps the configuration and runtime data separated for easier maintenance and backups.

Here’s an example of a docker-compose.yaml file that we can use to run Draupnir:

draupnir:
  image: gnuxie/draupnir:latest
  container_name: Draupnir
  hostname: draupnir
  restart: unless-stopped
  volumes:
    - /volume1/docker/draupnir/config:/data/config:ro
    - /volume1/docker/draupnir/data:/data/storage
  command: bot --draupnir-config /data/config/production.yaml
  networks:
    - frontend
  depends_on:
    synapse:
      condition: service_started

This configuration tells Docker to pull the latest Draupnir image and run it with a stable container name (Draupnir) and custom hostname (draupnir). The setting restart: unless-stopped makes sure Draupnir stays online and automatically restarts if the container crashes or the host reboots.

The depends_on option is useful if our Synapse server is running in a Docker container as well. It ensures that Draupnir only starts after Synapse has started, avoiding race conditions during boot. To make this work, we need to replace synapse with the actual name of the Synapse container in our Compose setup.

Two volume mounts are defined in this setup:

/volume1/docker/draupnir/config:/data/config:ro

This is where we store Draupnir’s configuration files. The :ro flag marks the config directory as read-only from inside the container.

/volume1/docker/draupnir/data:/data/storage

This path is used by Draupnir to store its persistent data, logs, and anything it needs to keep across restarts.

The critical file inside the config directory is called production.yaml, and this serves as Draupnir’s main configuration. We need to create this file ourselves before starting the container. A helpful starting point is the default configuration provided by the Draupnir project, which is available here.

We can copy this default file into our configuration directory and rename it to production.yaml. Before starting the Draupnir container, we must edit this file to define how Draupnir connects to our Synapse server. Specifically, we’ll need to set the homeserver URL, the user ID of the moderation account, and provide an access token.

In the next section, we’ll go through the details of how to configure production.yaml so Draupnir can authenticate correctly with our homeserver and begin managing rooms.

Connect Draupnir to Synpase

Now that we have our Draupnir container prepared and the basic production.yaml file in place, we need to configure it so the bot can connect to our Synapse server and start functioning as our moderation tool. This is a crucial step, as Draupnir relies on API access to interact with rooms, fetch events, issue redactions, and apply bans.

The production.yaml file contains many settings, but there are a few core parameters we need to focus on for the initial connection:

homeserverUrl: This is the base URL of our Synapse server, usually something like https://matrix.example.org. It must point to the public-facing endpoint that clients use to connect—not the internal Docker hostname.

accessToken: This is the admin token we need to generate for the Draupnir bot account, giving it the ability to access and moderate rooms.

managementRoom: This is our command and control room we defined beforehand. Just use the full room name such as “#bot:example.com”

Note: There is also an option to provide a username and password. However as long as you have an access token, you don’t need to provide this information since both options are mutually exclusive whereby username and password are for when you want to run draupnir in an encrypted environment (which is not recommended) and the access token is for non-encrypted setups (prefered).

To obtain an access token for the bot account, we can use one of two methods.

The first and easiest method works directly through Element or any other Matrix client. After logging into the client as the Draupnir user, we can access the access token either via the browser developer tools or more conveniently from the client settings:

In Element Web or Desktop, go to the user menu in the top-left corner, select “Settings”, then scroll all the way down to the “Help & About” section. At the very bottom of this menu, we’ll find a “Access Token” button or display area that allows us to reveal and copy the access token for the current session.

Alternatively, if we prefer the more technical route, we can open the Developer Tools (Ctrl+Shift+I or Cmd+Opt+I), go to the Application tab, and under Local Storage, select the entry for https://app.element.io (or the respective domain). There, we can search for the key mx_access_token and copy its value. This token gives Draupnir the ability to authenticate as that user.

The second method involves using the Synapse Admin API. This approach is especially helpful when we’re managing things server-side or want to script setup steps. To use this method, we’ll need the username and password of the Draupnir bot account (here: “draupnir”). Then, we issue the following POST request:

curl -X POST "https://matrix.example.org/_matrix/client/r0/login" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "m.login.password",
    "user": "draupnir",
    "password": "your-bot-password"
  }'

This command will return a JSON response containing the access_token. We can copy this token and place it in the access_token field of our production.yaml.

With these essential fields set—homeserver, server_name, user_id, and access_token—Draupnir is ready to authenticate with our Synapse server. Once this connection is in place, the bot will be able to join rooms, respond to moderation commands, and enforce policies as configured.

At this point, we won’t touch any of the advanced features or Synapse module integrations just yet. It’s important to make sure the core setup is working correctly before we move forward. Once we’ve verified that Draupnir is operational and responsive, we’ll come back to those enhancements later in the guide.

Next, we’ll walk through how to use Draupnir for actual moderation—inviting it to rooms, issuing commands, and working with policy lists to streamline our server management.

Moderation with Draupnir

Once Draupnir has successfully connected to our Synapse homeserver, we should start seeing activity in our #bot:example.com room, where the bot will notify us of its status and activity. This verbosity helps us ensure that Draupnir is running smoothly and interacting with our server.

Draupnir’s moderation capabilities revolve around three core concepts: protected rooms, policy lists, and user management. These concepts work together to provide an automated, scalable way of managing users across multiple rooms with minimal manual intervention.

Protected Rooms

Protected rooms are rooms where Draupnir has been granted permission to moderate and enforce policies. By designating rooms as protected, Draupnir can apply actions like bans, kicks, and user-specific policies across all protected rooms simultaneously, rather than having to manage them individually.

For example, if we have a #general room and a #support room that should be moderated under the same set of rules, we can mark them both as protected rooms. This means that any ban or kick action applied in one room can be enforced across all protected rooms. Draupnir ensures that the rules we define are applied consistently.

If you are unsure whether Draupnir is protecting a room, you can issue the “!draupnir rooms list” command to view a list of rooms that Draupnir is currently protecting.

You can manage which rooms Draupnir is protecting by using the following commands to add or remove a protected room:

!draupnir rooms add #room:example.com #To add a protected room
!draupnir rooms remove #room:example.com #To remove a protected room

You can also just invite your Draupnir bot to rooms, Draupnir will ask you within the management room whether you wish to protect the room.

Once Draupnir is protecting a room, Draupnir may start to complain about missing permissions. You will want to first take note of which permissions Draupnir has described as missing. Then you will go to the protected room’s settings in your client and give Draupnir the “Admin” power level.

Policy Lists

Policy lists are a key feature in Draupnir. They allow us to define a set of rules (such as ban lists or user restrictions) and apply them universally across multiple rooms. Instead of manually banning a user in each room, we can define a policy that applies the same ban to all rooms in the policy list.

To set up our own policy list, we first need to create a new list, which will be used to define specific policies (like user bans, rate-limiting, etc.). Draupnir allows us to manage and customize these policy lists according to our needs. For instance, we can create a policy list for a specific server or a group of rooms and apply a user ban across all those rooms, ensuring that the banned user cannot rejoin any of the protected rooms under that policy.

To create a policy list for your server you can use the command “!draupnir list create”. So for example, if you want to create a policy list for your banned users, then you can  use the command as follows:

!draupnir list create my-bans my-bans

This will create a policy room with the shortcode my-bans and an alias #my-bans:example.com, which can be used to share the list with other communities.

After watching or unwatching policy rooms, you may wish to confirm what policy lists Draupnir is watching. This can be done by issuing the !draupnir status command whereby you will be able to see a list of policy rooms and their associated “shortcodes”.

Subscribing to External Policy Lists

In addition to creating our own policy lists, Draupnir allows us to subscribe to external policy lists maintained by trusted community members or Matrix.org directly. This is useful if we want to integrate with other established moderation efforts without having to set up our own from scratch.

For example, there are several well-maintained policy lists that can be used across different Matrix servers, providing global consistency when it comes to banning known spammers, bots, or other bad actors. Here are some trusted policy lists that we can subscribe to:

#community-moderation-effort-bl:neko.dev — A community-driven effort to create a global ban list, offering a comprehensive set of policies to reduce spam across servers.

#tchncs-ban-list:tchncs.de — A well-known ban list that is maintained by the Tchncs team. It includes bans for known spammers and other malicious users.

#matrix-org-hs-tos-bl:matrix.org — This list is maintained by Matrix.org and enforces the Terms of Service (ToS) for the Matrix protocol. It includes users who have violated Matrix’s terms and ensures compliance with the platform’s rules.

#asragrbanlist_general:asra.gr — A general ban list maintained by the Asra community, designed to protect rooms from disruptive users.

To subscribe to these policy lists, we simply need to add them to Draupnir’s configuration or use specific commands to subscribe directly from the bot. For example, to subscribe to the #matrix-org-hs-tos-bl policy list, we can use the command:

!draupnir watch #matrix-org-hs-tos-bl:matrix.org

Once subscribed, Draupnir will automatically apply the policies from that list to any protected rooms under our moderation.

You can check the current protection status of your rooms as well as subscription status of your policy lists with the following command:

!draupnir status

By leveraging both our own policy lists and the external lists available, we can streamline moderation across our entire server or federation, ensuring consistent enforcement of rules while minimizing manual oversight.

Advanced Features and Module usage

Once Draupnir is up and running and managing our rooms effectively, we can unlock even more powerful moderation capabilities by integrating it with Synapse’s extensible module system — specifically, the synapse-http-antispam module. This allows Draupnir to intervene much earlier in the message pipeline, catching spam or abusive behavior before messages are even accepted by the server.

To get started, we first need to understand how Synapse handles external modules. These are Python packages that extend the functionality of the server. We install them using pip, typically within the environment where Synapse runs. For example:

First ensure you are using the latest pip version by issue the following command:

pip install --upgrade pip

If your synpase installation is running in a docker environment you can use the following command instead:

docker exec -u 0 Matrix pip install --upgrade pip

Afterwards install the module by using the following command:

pip install synapse-http-antispam

If your synpase installation is running in a docker environment you can use the following command instead:

docker exec -u 0 synapse-container-name pip install synapse-http-antispam

To check is you installed the module correctly you can enter your synpse docker container with the following command:

docker exec -it synpase-container-name /bin/sh

Now that you inside your container you can just use this command to check the module version:

pip show synapse-http-antispam

However, if we’re running Synapse as a Docker container, it’s important to be aware that any pip install operation will be lost when the container is rebuilt or restarted — unless we’ve modified the Docker image or set up a persistent overlay. This tutorial will not go into those details, but it’s critical to ensure that the module is available and running whenever Draupnir’s HTTP spam check feature is enabled in its configuration. For testing or evaluation purposes, installing the module manually after re initiating the container is usually sufficient.

The synapse-http-antispam module allows Synapse to delegate spam-checking logic to an external HTTP service — in our case, Draupnir. It hooks into Synapse’s spam checker callbacks, which are well-defined points in the message flow where custom logic can decide whether to allow or reject user behavior.

Here are the key callbacks it supports:

check_event_for_spam: Triggered when a user sends a message or performs an action. Draupnir can inspect the event and decide if it should be rejected.

user_may_invite: Determines whether a user is allowed to send an invitation to another user.

user_may_join_room: Checks if a user should be permitted to join a specific room.

By enabling these hooks, Draupnir can perform proactive moderation, preventing spam before it even enters our rooms.

To enable this functionality, we first need to adjust Draupnir’s production.yaml. Specifically, we must enable the HTTP spam check integration, define a port for the callback server, and set an authorization token for secure communication between Synapse and Draupnir.

Here’s an example snippet from production.yaml:

# Options for exposing web APIs.
web:
  # Whether to enable web APIs.
  enabled: true

  # The port to expose the webserver on. Defaults to 8080.
  port: 8282

  # The address to listen for requests on. Defaults to only the current
  # computer.
  address: 0.0.0.0

  abuseReporting:
    # Whether to enable this feature.
    enabled: false

  synapseHTTPAntispam:
    enabled: true
    authorization: YOUR_SECRET_TOKEN

This tells Draupnir to start an HTTP server on port 8282 and use the specified secret to authenticate incoming requests from Synapse.

Next, we need to configure Synapse to use the synapse-http-antispam module and point it to Draupnir’s HTTP endpoint. This is done in our synpase homeserver.yaml config, where we define the module and its parameters:

modules:
  - module: synapse_http_antispam.HTTPAntispam
    config:
      base_url: http://draupnir:8282/api/1/spam_check
      authorization: YOUR_SECRET_TOKEN
      enabled_callbacks:
        - check_event_for_spam
        - user_may_invite
        - user_may_join_room
      fail_open:
        check_event_for_spam: true
        user_may_invite: true
        user_may_join_room: true
      async:
        check_event_for_spam: true

Let’s walk through this configuration:

base_url: This is the full URL Synapse uses to contact Draupnir. When both containers run inside the same Docker network, we can use the internal Docker hostname (in this case, “draupnir” as defined above) and the specified port (8282) to establish communication.

authorization: This must match the auth_secret from Draupnir’s configuration. It’s used to secure the requests between the server and the bot.

enabled_callbacks: Specifies which spam-checking functions should be enabled. Draupnir will only respond to these particular events.

fail_open: If Draupnir fails to respond, Synapse can be configured to allow the event to proceed. This prevents accidental lockouts if the bot is temporarily unavailable.

async: For check_event_for_spam, enabling asynchronous behavior can help improve performance by not blocking the entire Synapse process while waiting for the spam decision.

To ensure this all works smoothly, both Synapse and Draupnir must be part of the same Docker network. This allows Synapse to resolve the draupnir hostname correctly and connect over the specified port. In our Docker Compose setup, this can be achieved by adding both services to a common network (like frontend) and referencing each other by container name.

By integrating Draupnir with synapse-http-antispam, we allow it to perform dynamic, real-time spam detection across our rooms—greatly enhancing our ability to prevent abuse, unwanted messages, and toxic behavior before it even reaches users. This is especially useful on busy servers or in public communities where proactive filtering is essential.

Conclusion

Now that everything is set up and running, I hope you’re starting to see just how much easier and more effective moderation on a Matrix Synapse server can be with Draupnir in place. When I first started exploring ways to scale moderation without manually hunting down and banning problematic users across multiple rooms, I quickly realized the built-in tools weren’t going to cut it for anything beyond the most basic use cases. Draupnir changed that.

Through this tutorial, I’ve walked you through the full process of deploying Draupnir as a Docker container, connecting it to your Synapse server, and configuring it to work securely and efficiently. We explored how to manage protected rooms, create and subscribe to policy lists, and use Draupnir’s command-and-control room to centralize moderation tasks. With just a few well-placed commands, you can now apply bans or warnings across your entire network of protected rooms—something that used to take manual effort and too much time.

Once you’ve got the basics working, unlocking the full potential of Draupnir by integrating the synapse-http-antispam module really takes it to the next level. Being able to catch abuse before it reaches your users is a game-changer. Even though installing and running Synapse modules in Docker environments requires a bit of care, the added protection and flexibility make it more than worth it in my experience.

If you ever get stuck, have questions, or just want to connect with others using Draupnir, I highly recommend joining the official Draupnir support room on Matrix: #draupnir:matrix.org. The community there has been incredibly helpful and welcoming, and it’s a great place to stay updated on new features and best practices.

Good luck with your setup — and happy moderating!

Leave a Reply

Your email address will not be published. Required fields are marked *