Install and Integrate Rspamd on Ubuntu 26.04

By 

Updated on

8 min read

Rspamd mail filtering and DKIM signing illustration

This is the third part of our Setting up and configuring a mail server . In this tutorial, we will install and configure Rspamd, connect it to Postfix, and create DKIM and DMARC DNS records.

You may ask why we choose to go with Rspamd and not with Spamassassin. Rspamd is more actively maintained and written in C, so it is much faster than Spamassassin which is written in Perl. Another reason is that Rspamd ships a DKIM signing module, so we will not have to use another piece of software to sign our outgoing emails.

If you are not familiar with Rspamd, you can check the official documentation here .

Prerequisites

Before continuing with this tutorial, make sure you are logged in as a user with sudo privileges and that you have completed the first and second parts of the series, where we set up PostfixAdmin, Postfix, and Dovecot.

Install Redis

Redis is used as the storage and caching backend for Rspamd. Install it with:

Terminal
sudo apt update
sudo apt install -y redis-server
sudo systemctl enable --now redis-server
Info
A local DNS resolver such as Unbound can reduce DNS RBL lookup latency on busy servers, but configuring it correctly on Ubuntu 26.04 (where systemd-resolved already binds port 53) is out of scope for this tutorial.

Install Rspamd

Ubuntu 26.04 universe ships a recent stable Rspamd, so we can install it directly from the default repositories:

Terminal
sudo apt install -y rspamd

Confirm the installed version and that the service started:

Terminal
rspamd --version
systemctl status rspamd --no-pager
Info
If you want a newer release than the one in Ubuntu universe, you can use the official Rspamd APT repository when it adds support for the Ubuntu 26.04 resolute suite. Use the modern keyring layout under /etc/apt/keyrings/ rather than the deprecated apt-key.

Configure Rspamd

Instead of modifying the stock configuration files, we will create new files under /etc/rspamd/local.d/ which override the default settings.

By default Rspamd’s normal worker (the worker that scans email messages) listens on all interfaces on port 11333. Restrict it to localhost:

/etc/rspamd/local.d/worker-normal.inccfg
bind_socket = "127.0.0.1:11333";

The proxy worker listens on port 11332 and supports the milter protocol. Postfix talks to Rspamd through this worker, so we enable milter mode and configure it to scan messages locally:

/etc/rspamd/local.d/worker-proxy.inccfg
bind_socket = "127.0.0.1:11332";
milter = yes;
timeout = 120s;
upstream "local" {
  default = yes;
  self_scan = yes;
}

Generate an encrypted password for the controller worker, which provides access to the Rspamd web interface:

Terminal
rspamadm pw --encrypt -p rspamd_controller_password

The output should look something like this:

output
$2$khz7u8nxgggsfay3qta7ousbnmi1skew$zdat4nsm7nd3ctmiigx9kjyo837hcjodn1bob5jaxt7xpkieoctb
Info
Replace rspamd_controller_password with a long random password before running the command.

Copy the password from your terminal and paste it into the controller configuration file:

/etc/rspamd/local.d/worker-controller.inccfg
password = "$2$khz7u8nxgggsfay3qta7ousbnmi1skew$zdat4nsm7nd3ctmiigx9kjyo837hcjodn1bob5jaxt7xpkieoctb";
bind_socket = "127.0.0.1:11334";

Point Rspamd at the local Redis instance:

/etc/rspamd/local.d/redis.confcfg
servers = "127.0.0.1";

Set Redis as the backend for the Bayesian classifier:

/etc/rspamd/local.d/classifier-bayes.confcfg
servers = "127.0.0.1";
backend = "redis";

Open the milter_headers.conf file and set the headers Rspamd writes to scanned messages:

/etc/rspamd/local.d/milter_headers.confcfg
use = ["x-spamd-bar", "x-spam-level", "authentication-results"];

You can find more information about the milter headers in the Rspamd documentation .

Run a configuration check and restart the Rspamd service for the changes to take effect:

Terminal
sudo rspamadm configtest
sudo systemctl restart rspamd

Configure Postfix

Configure Postfix to use the Rspamd milter on the proxy worker socket:

Terminal
sudo postconf -e "smtpd_milters = inet:127.0.0.1:11332"
sudo postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"
sudo postconf -e "milter_protocol = 6"
sudo postconf -e "milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}"
sudo postconf -e "milter_default_action = accept"

Restart the Postfix service for the changes to take effect:

Terminal
sudo systemctl restart postfix

Send a test message and confirm Rspamd scanned it:

Terminal
swaks --to user@linuxize.com --from admin@linuxize.com --server 127.0.0.1
sudo grep -i rspamd /var/log/mail.log | tail -n 10

Configure Nginx

In the first part of this series, we created an Nginx server block for the PostfixAdmin instance. Add a new location block to that server so we can reverse proxy the Rspamd controller through HTTPS:

/etc/nginx/sites-enabled/mail.linuxize.comnginx
...
location /rspamd/ {
    proxy_pass http://127.0.0.1:11334/;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...

Reload the Nginx service for the changes to take effect:

Terminal
sudo systemctl reload nginx

Open https://mail.linuxize.com/rspamd/ in your browser, enter the password you generated with rspamadm pw, and you will be presented with the Rspamd web interface.

Rspamd web interface on Ubuntu 26.04

Create DKIM keys

DomainKeys Identified Mail (DKIM) is an email authentication method which adds a cryptographic signature to outbound message headers. It allows the receiver to verify that an email claiming to originate from a specific domain was indeed authorized by the owner of that domain. The main purpose of this is to prevent forged email messages.

We can have different DKIM keys for each domain we host. The Rspamd DKIM signing module supports a per-domain layout out of the box, so we will use a key path that includes both the domain and the selector. That way you can add more domains later by generating a new key with the same selector.

Create a directory to store the DKIM keys and generate a new keypair using rspamadm:

Terminal
sudo mkdir -p /var/lib/rspamd/dkim
sudo rspamadm dkim_keygen -b 2048 -s mail -d linuxize.com -k /var/lib/rspamd/dkim/linuxize.com.mail.key > /tmp/linuxize.com.mail.txt

In the example above we are using mail as the DKIM selector. The private key is written to /var/lib/rspamd/dkim/linuxize.com.mail.key, and the public TXT record we will publish in DNS is captured in /tmp/linuxize.com.mail.txt.

Set the correct ownership and permissions so only the Rspamd user can read the private key:

Terminal
sudo chown -R _rspamd:_rspamd /var/lib/rspamd/dkim
sudo chmod 750 /var/lib/rspamd/dkim
sudo chmod 440 /var/lib/rspamd/dkim/linuxize.com.mail.key

Now tell Rspamd where to look for the DKIM key. The path uses the $domain and $selector variables so the same configuration file works for every domain you add later:

/etc/rspamd/local.d/dkim_signing.confcfg
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
selector = "mail";
allow_username_mismatch = true;

Run a configuration check and restart Rspamd:

Terminal
sudo rspamadm configtest
sudo systemctl restart rspamd

DNS settings

The DKIM public TXT record was written to /tmp/linuxize.com.mail.txt when we generated the key. The content should look similar to this:

output
mail._domainkey IN TXT ( "v=DKIM1; k=rsa;"
    "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqdBRCqYzshc4LmmkxUkCH/rcIpSe..."
    "...ZTRe1FlONOzO7ZkQFb7O6ogFepWLsM9tYJ38TFPteqyO3XBjxHzp1AT0UvsPcauDoeHUXgqbxU7udG1t05f6ab5h/Kih+jisgHHF4ZFK3qRtawhWlA9DtS35DlwIDAQAB" ) ;

If you are running your own Bind DNS server, copy and paste the record directly into your domain zone file. If you are using a DNS web interface, create a new TXT record with mail._domainkey as the name. For the value, remove the quotes and concatenate the lines together so the record contains a single string starting with v=DKIM1; and ending with the public key.

We will also publish a Domain-based Message Authentication, Reporting, and Conformance (DMARC) record. DMARC tells the receiving server how to treat email that fails SPF or DKIM checks, and it protects your domain against direct spoofing while improving its reputation.

If you followed the series from the beginning, you should already have an SPF record for your domain. To set up a DMARC record, the sending domain needs both an SPF and a DKIM record published. The DMARC policy itself is published as a TXT record:

cfg
_dmarc  IN  TXT  "v=DMARC1; p=none; adkim=r; aspf=r;"

Let us break down the record:

  • v=DMARC1 is the DMARC version identifier.
  • p=none tells the receiver to take no action on messages that fail DMARC. You can change this to quarantine or reject once you are confident the configuration is correct.
  • adkim=r and aspf=r set the DKIM and SPF alignment mode to relaxed. Use s for strict alignment.

As with the DKIM record, paste the line into your zone file or create a TXT record with _dmarc as the name and v=DMARC1; p=none; adkim=r; aspf=r; as the value.

It may take a while for the DNS changes to propagate. You can check whether the records have propagated using the dig command :

Terminal
dig mail._domainkey.linuxize.com TXT +short
dig _dmarc.linuxize.com TXT +short
output
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqdBRCqYzshc4LmmkxUkCH/rcIpSe..."
"v=DMARC1; p=none; adkim=r; aspf=r;"

You can also inspect your domain DMARC policy with the DMARC inspector .

Verify DKIM signing

Before you trust outbound mail to be signed, send an authenticated message through port 587 and confirm a DKIM-Signature header appears on the delivered copy:

Terminal
swaks --to user@linuxize.com --from user@linuxize.com --server mail.linuxize.com --port 587 --auth LOGIN --auth-user user@linuxize.com --auth-password 'MAILBOX_PASSWORD' --tls

Find the most recent message in the user Maildir and inspect its headers:

Terminal
LATEST=$(sudo find /var/mail/vmail -type f \( -path '*/new/*' -o -path '*/cur/*' \) -printf '%T@ %p\n' | sort -nr | head -1 | awk '{print $2}')
sudo grep -E '^(DKIM-Signature|Authentication-Results|ARC-)' "$LATEST"

You should see a DKIM-Signature: v=1; a=rsa-sha256; ... d=linuxize.com; s=mail; ... line. If the header is missing, check the path in dkim_signing.conf against the file name on disk and confirm the key is readable by _rspamd.

Troubleshooting

Rspamd web login fails
Confirm that the hash in /etc/rspamd/local.d/worker-controller.inc came from the same plain text password you are entering in the browser. Then restart Rspamd and reload Nginx:

Terminal
sudo rspamadm configtest
sudo systemctl restart rspamd
sudo systemctl reload nginx

Postfix messages are not scanned
Check that Postfix points to the proxy worker on port 11332, then send a local test message and inspect the mail log:

Terminal
postconf smtpd_milters non_smtpd_milters
swaks --to user@linuxize.com --from admin@linuxize.com --server 127.0.0.1
sudo grep -i rspamd /var/log/mail.log | tail -n 20

DKIM-Signature is missing
Verify that the private key name matches the $domain.$selector.key pattern from dkim_signing.conf, and that the _rspamd user can read it:

Terminal
sudo ls -l /var/lib/rspamd/dkim/
sudo -u _rspamd test -r /var/lib/rspamd/dkim/linuxize.com.mail.key

Conclusion

You have installed Rspamd, integrated it with Postfix as a milter, configured per-domain DKIM signing, and published the DKIM and DMARC TXT records. In the next part of this series, we will continue with Roundcube installation and configuration .

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page