Draupnir

Moderation bot for Matrix servers

This project is funded by NLnet through these subgrants:

Try the service in a VM

  1. Install Nix
    Arch Linux
    Bash
    $ pacman --sync --refresh --noconfirm curl git jq nix
    Debian
    Bash
    $ apt install --yes curl git jq nix
    Ubuntu
    Bash
    $ apt install --yes curl git jq nix
  2. Download a configuration file
    # default.nix
    {
      ngipkgs ? import (fetchTarball "https://github.com/ngi-nix/ngipkgs/tarball/main") { },
    }:
    ngipkgs.demo-vm (
      # https://github.com/NixOS/nixpkgs/blob/c7661dfc33f947d81443ec911549e2d0f6414085/nixos/tests/matrix/draupnir.nix
      { ... }:
    
      let
        port = 8008;
      in
      {
        # We want a server for demos.
        services.matrix-synapse = {
          enable = true;
          log.root.level = "WARNING";
          settings = {
            database.name = "sqlite3";
            # Do *NOT* do this in production!
            registration_shared_secret = "supersecret-registration";
    
            listeners = [
              {
                bind_addresses = [
                  "::"
                ];
                inherit port;
                resources = [
                  {
                    compress = true;
                    names = [ "client" ];
                  }
                  {
                    compress = false;
                    names = [ "federation" ];
                  }
                ];
                tls = false;
                type = "http";
                x_forwarded = false;
              }
            ];
          };
        };
    
        services.draupnir = {
          enable = true;
          settings = {
            homeserverUrl = "http://localhost:${toString port}";
            managementRoom = "#moderators:homeserver";
          };
          secrets = {
            # This needs be set up before the service is started.
            accessToken = "/tmp/draupnir-access-token";
          };
        };
    
        # demo-vm
        networking.firewall.allowedTCPPorts = [ port ];
      }
    
    )
    
  3. Enable binary substituters
    Bash
    $ export NIX_CONFIG='substituters = https://cache.nixos.org/ https://ngi.cachix.org/
    trusted-public-keys = cache.nixos.org-1:6nchdd59x431o0gwypbmraurkbj16zpmqfgspcdshjy= ngi.cachix.org-1:n+cal72roc3qqulxihpv+tw5t42whxmmhpragkrsrow='
  4. Build and run a virtual machine
    Arch Linux, Debian Sid and Ubuntu 25.04
    Bash
    $ nix-build ./default.nix && ./result
    Debian 12 and Ubuntu 24.04/24.10
    Bash
    $ rev=$(nix-instantiate --eval --attr sources.nixpkgs.rev https://github.com/ngi-nix/ngipkgs/archive/master.tar.gz | jq --raw-output)
    $ nix-shell -I nixpkgs=https://github.com/NixOS/nixpkgs/archive/$rev.tar.gz --packages nix --run "nix-build ./default.nix && ./result"
  5. Access the service
    Open a web browser at http://localhost:8008 .

Options

services.draupnir
services.draupnir.enable

Whether to enable Draupnir, a moderations bot for Matrix.

Type:
boolean
Default:
false
services.draupnir.package

The draupnir package to use.

Type:
package
Default:
pkgs.draupnir
services.draupnir.secrets.accessToken

File containing the access token for Draupnir's Matrix account to be used in place of {option}services.draupnir.settings.accessToken.

Type:
null or absolute path
Default:
null
services.draupnir.secrets.pantalaimon.password

File containing the password for Draupnir's Matrix account when used in conjunction with Pantalaimon to be used in place of {option}services.draupnir.settings.pantalaimon.password.

::: {.warning} Take note that upstream has limited Pantalaimon and E2EE support: https://the-draupnir-project.github.io/draupnir-documentation/bot/encryption and https://the-draupnir-project.github.io/draupnir-documentation/shared/dogfood#e2ee-support. :::

Type:
null or absolute path
Default:
null
services.draupnir.secrets.web.synapseHTTPAntispam.authorization

File containing the secret token when using the Synapse HTTP Antispam module to be used in place of {option}services.draupnir.settings.web.synapseHTTPAntispam.authorization.

See https://the-draupnir-project.github.io/draupnir-documentation/bot/synapse-http-antispam for details.

Type:
null or absolute path
Default:
null
services.draupnir.settings

Free-form settings written to Draupnir's configuration file. See Draupnir's default configuration for available settings.

Type:
YAML 1.1 value
Default:
{ }
services.draupnir.settings.dataPath Read-only

The path Draupnir will store its state/data in.

::: {.warning} This option is read-only. :::

::: {.note} If you want to customize where this data is stored, use a bind mount. :::

Type:
absolute path
Default:
"/var/lib/draupnir"
services.draupnir.settings.homeserverUrl

Base URL of the Matrix homeserver that provides the Client-Server API.

::: {.note} When using Pantalaimon, set this to the Pantalaimon URL and {option}services.draupnir.settings.rawHomeserverUrl to the public URL. :::

Type:
string
services.draupnir.settings.managementRoom

The room ID or alias where moderators can use the bot's functionality.

The bot has no access controls, so anyone in this room can use the bot - secure this room! Do not enable end-to-end encryption for this room, unless set up with Pantalaimon.

::: {.warning} When using a room alias, make sure the alias used is on the local homeserver! This prevents an issue where the control room becomes undefined when the alias can't be resolved. :::

Type:
string
services.draupnir.settings.rawHomeserverUrl

Public base URL of the Matrix homeserver that provides the Client-Server API when using the Draupnir's Report forwarding feature.

::: {.warning} When using Pantalaimon, do not set this to the Pantalaimon URL! :::

Type:
string
Default:
config.services.draupnir.settings.homeserverUrl

Examples

# https://github.com/NixOS/nixpkgs/blob/c7661dfc33f947d81443ec911549e2d0f6414085/nixos/tests/matrix/draupnir.nix
{ ... }:

let
  port = 8008;
in
{
  # We want a server for demos.
  services.matrix-synapse = {
    enable = true;
    log.root.level = "WARNING";
    settings = {
      database.name = "sqlite3";
      # Do *NOT* do this in production!
      registration_shared_secret = "supersecret-registration";

      listeners = [
        {
          bind_addresses = [
            "::"
          ];
          inherit port;
          resources = [
            {
              compress = true;
              names = [ "client" ];
            }
            {
              compress = false;
              names = [ "federation" ];
            }
          ];
          tls = false;
          type = "http";
          x_forwarded = false;
        }
      ];
    };
  };

  services.draupnir = {
    enable = true;
    settings = {
      homeserverUrl = "http://localhost:${toString port}";
      managementRoom = "#moderators:homeserver";
    };
    secrets = {
      # This needs be set up before the service is started.
      accessToken = "/tmp/draupnir-access-token";
    };
  };

  # demo-vm
  networking.firewall.allowedTCPPorts = [ port ];
}