Skip to content

RSpamD

Setting up Redis

We'll first create separate Redis instances specifically for Rspamd. We'll create one for the bayes engine, one for fuzzy storage, and one for caching.

Further information: https://rspamd.com/doc/tutorials/redis_replication.html

Enter a sudo shell and install Redis and a secure password generator:

sudo -s
apt update && apt install redis-server pwgen

We'll first make a few tweaks to the system for an optimal Redis setup.

Add the following line to sysctl.conf:

nano /etc/sysctl.conf
net.core.somaxconn = 1024
vm.overcommit_memory=1

Now install hugepages and configure as follows:

apt update && apt install libhugetlbfs-bin
hugeadm --thp-never

Make sure /etc/rc.local exists and, if not, then create it as follows:

nano /etc/rc.local
#!/bin/sh -e
#
# rc.local
#
# This script is executed at the end of each multiuser runlevel.
# Make sure that the script will "exit 0" on success or any other
# value on error.
#
# In order to enable or disable this script just change the execution
# bits.
#
# By default this script does nothing.

exit 0

Add the hugepages command to the file using the following line:

/bin/sed -i '$i /usr/bin/hugeadm --thp-never' /etc/rc.local

Make the file executable:

chmod +x /etc/rc.local

And now restart rc-local:

systemctl restart rc-local

First we'll create a common configuration file for all instances:

mv /etc/redis/redis.conf /etc/redis/common.conf

Open this file and comment out any unixsocket, bind, or port lines. We also change protected mode to 'no':

nano /etc/redis/common.conf
#bind 127.0.0.1 ::1
#port 6379
# unixsocket /var/run/redis/redis-server.sock
# unixsocketperm 700

protected-mode no

Generate a secure password:

pwgen -Bvsc 64 1

This results in something like the following:

rtVh7zMTFHWm7HWVFXfcgNLXXtjC9scTt4mHVwjnrvqwsJ9qv9CjdwcCWtpqNVbL

Create the master Rspamd configuration file:

nano /etc/redis/redis-rspamd.conf

Enter the following, using the password you generated above:

#
# Redis Master configuration
# for Rspamd Modules
#   Ratelimit, Greylisting, DMARC, Replies, IP score, Multimap, MX Check
#

include /etc/redis/common.conf
# Listen on localhost
bind 127.0.0.1 ::1
port 6380
unixsocket /var/run/redis-rspamd/redis-server.sock
unixsocketperm 700
daemonize yes
supervised systemd
pidfile /var/run/redis-rspamd/redis-server.pid
loglevel notice
logfile /var/log/redis/redis-rspamd.log
dbfilename dump-rspamd.rdb
requirepass rtVh7zMTFHWm7HWVFXfcgNLXXtjC9scTt4mHVwjnrvqwsJ9qv9CjdwcCWtpqNVbL
# maxmemory <bytes>
# maxmemory-policy noeviction
# maxmemory-samples 5

Create another password and use it with the Rspamd Bayesian configuration file:

nano /etc/redis/redis-rspamd-bayes.conf

Enter the following, using the new password:

#
# Redis Master configuration
# for Rspamd Bayesian statistic Module
#

include /etc/redis/common.conf
# Listen on localhost
bind 127.0.0.1 ::1
port 6381
unixsocket /var/run/redis-rspamd-bayes/redis-server.sock
unixsocketperm 700
daemonize yes
supervised systemd
pidfile /var/run/redis-rspamd-bayes/redis-server.pid
loglevel notice
logfile /var/log/redis/redis-rspamd-bayes.log
dbfilename dump-rspamd-bayes.rdb
requirepass rtVh7zMTFHWm7HWVFXfcgNLXXtjC9scTt4mHVwjnrvqwsJ9qv9CjdwcCWtpqNVbL
# maxmemory <bytes>
# maxmemory-policy noeviction
# maxmemory-samples 5

Create another password and use it with the Rspamd Bayesian configuration file:

nano /etc/redis/redis-rspamd-fuzzy.conf

Enter the following, using the new password:

#
# Redis Master configuration
# for Rspamd Fuzzy Module
#

include /etc/redis/common.conf
# Listen on localhost
bind 127.0.0.1 ::1
port 6382
unixsocket /var/run/redis-rspamd-fuzzy/redis-server.sock
unixsocketperm 700
daemonize yes
supervised systemd
pidfile /var/run/redis-rspamd-fuzzy/redis-server.pid
loglevel notice
logfile /var/log/redis/redis-rspamd-fuzzy.log
dbfilename dump-rspamd-fuzzy.rdb
requirepass rtVh7zMTFHWm7HWVFXfcgNLXXtjC9scTt4mHVwjnrvqwsJ9qv9CjdwcCWtpqNVbL
# maxmemory <bytes>
# maxmemory-policy noeviction
# maxmemory-samples 5

Make a copy of the pre-installed service file:

cp /lib/systemd/system/redis-server@.service /etc/systemd/system/

remove the existing unneeded service file:

mv /etc/systemd/system/redis.service ~/redis.service.bak

Edit the new service file:

nano /etc/systemd/system/redis-server@.service

Make sure it's set as follows:

# Templated service file for redis-server(1)
#
# Each instance of redis-server requires its own configuration file:
#
#   $ cp /etc/redis/redis.conf /etc/redis/redis-myname.conf
#   $ chown redis:redis /etc/redis/redis-myname.conf
#
# Ensure each instance is using their own database:
#
#   $ sed -i -e 's@^dbfilename .*@dbfilename dump-myname.rdb@' /etc/redis/redis-myname.conf
#
# We then listen exlusively on UNIX sockets to avoid TCP port collisions:
#
#   $ sed -i -e 's@^port .*@port 0@' /etc/redis/redis-myname.conf
#   $ sed -i -e 's@^\(# \)\{0,1\}unixsocket .*@unixsocket /var/run/redis-myname/redis-server.sock@' /etc/redis/redis-myname.conf
#
# ... and ensure we are logging, etc. in a unique location:
#
#   $ sed -i -e 's@^logfile .*@logfile /var/log/redis/redis-server-myname.log@' /etc/redis/redis-myname.conf
#   $ sed -i -e 's@^pidfile .*@pidfile /var/run/redis-myname/redis-server.pid@' /etc/redis/redis-myname.conf
#
# We can then start the service as follows, validating we are using our own
# configuration:
#
#   $ systemctl start redis-server@myname.service
#   $ redis-cli -s /var/run/redis-myname/redis-server.sock info | grep config_file
#
#  -- Chris Lamb <lamby@debian.org>  Mon, 09 Oct 2017 22:17:24 +0100
[Unit]
Description=Advanced key-value store (%I)
After=network.target
Documentation=http://redis.io/documentation, man:redis-server(1)

[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/redis-%i.conf
ExecStop=/bin/kill -s TERM $MAINPID
PIDFile=/var/run/redis-%i/redis-server.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=redis
RuntimeDirectory=redis-%i
RuntimeDirectoryMode=2755

UMask=007
PrivateTmp=yes
LimitNOFILE=65535
PrivateDevices=yes
ProtectHome=yes
ReadOnlyDirectories=/
ReadWriteDirectories=-/var/lib/redis
ReadWriteDirectories=-/var/log/redis
ReadWriteDirectories=-/var/run/redis-%i

NoNewPrivileges=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
MemoryDenyWriteExecute=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

# redis-server can write to its own config file when in cluster mode so we
# permit writing there by default. If you are not using this feature, it is
# recommended that you replace the following lines with "ProtectSystem=full".
ProtectSystem=full
ReadWriteDirectories=-/etc/redis

[Install]
WantedBy=multi-user.target

Change permissions on the configuration files and reload systemd:

chown -Rc redis:redis /etc/redis
systemctl daemon-reload

Enable and start the services

systemctl enable redis-server@rspamd redis-server@rspamd-bayes redis-server@rspamd-fuzzy
systemctl start redis-server@rspam*.service --all

Check that the service are running with:

ps aux | grep redis

or

service redis-server@rspam* status

RSpamd Installation and Initial Configuration

Install dependencies (if you haven't already installed them):

apt install software-properties-common lsb-release wget

And add the Rspamd repository:

wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -
echo "deb [arch=amd64] http://rspamd.com/apt-stable/ $(lsb_release -cs) main" | tee -a /etc/apt/sources.list.d/rspamd.list

Update the apt cache and install:

apt update && apt install rspamd

Instead of modifying the stock config files we will create new files in the /etc/rspamd/local.d/ directory which will overwrite the default setting.

/etc/rspamd/local.d/worker-normal.inc contains information about the port on which Rspamd listens. Create the following file to configure the Rspamd normal worker to listen only to localhost interface:

nano /etc/rspamd/local.d/worker-normal.inc

and enter the following:

bind_socket = "127.0.0.1:11333";
bind_socket = "[::1]:11333";

Configure a proxy between Postfix and Rspamd, it listens on port 11332 and uses milter to communicate between the two tools. Edit the file /etc/rspamd/local.d/worker-proxy.inc:

nano /etc/rspamd/local.d/worker-proxy.inc

and enter the following:

bind_socket = "127.0.0.1:11332";
bind_socket = "[::1]:11332";
milter = yes;
timeout = 120s;
upstream "local" {
  default = yes;
  self_scan = yes;
}

Set an encrypted password for the worker:

rspamadm pw --encrypt -p your_secret_password

obviously replacing 'your_secret_password' with your password of choice.

Copy the output into /etc/rspamd/local.d/worker-controller.inc

nano /etc/rspamd/local.d/worker-controller.inc
bind_socket = "127.0.0.1:11334";
bind_socket = "[::1]:11334";
bind_socket = "/tmp/rspamd-controller.sock mode=0666 owner=_rspamd";
password = "$2$khz7u8nxgggsfay3qta7ousbnmi1skew$zdat4nsm7nd3ctmiigx9kjyo837hcjodn1bob5jaxt7xpkieoctb";

Set the milter headers in the file /etc/rspamd/local.d/milter_headers.conf:

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

Configuring Rspamd to use Redis

Configure redis to be used with rspamd by creating the following 3 files:

nano /etc/rspamd/local.d/redis.conf

Change the password to the one set in the corresponding redis config...

servers = "localhost:6380";
timeout = 1s;
db = "0";
password = "opHequ75iJgKnc7AyNJp995jhbzTKOSr";
nano /etc/rspamd/local.d/classifier-bayes.conf

Change the password to the one set in the corresponding redis config...

backend = "redis";
servers = "localhost:6381";
db = "0";
password = "opHequ75iJgKnc7AyNJp995jhbzTKOSr";
autolearn = true;
nano /etc/rspamd/override.d/worker-fuzzy.inc

Change the password to the one set in the corresponding redis config...

#
# Fuzzy Storage Master Worker on Charlotte
#
# Stores fuzzy hashes of messages.
# https://rspamd.com/doc/workers/fuzzy_storage.html
#

# number of worker instances to run
count = 1; # Disabled by default

# Listen on localhost
bind_socket = "127.0.0.1:11333";
bind_socket = "[::1]:11333";

# Store the hashes in Redis.
backend = 'redis';
servers = "localhost:6382";
timeout = 1s;
db = 0;
password = 'opHequ75iJgKnc7AyNJp995jhbzTKOSr';

# Expiration time of stored fuzzy hashes (default: 2 days)
expire = 90d;

# Allow localhost to perform changes to fuzzy storage.
allow_update = "127.0.0.1, ::1";

Finally, add the user '_rspamd' to the group 'redis':

usermod -a -G redis _rspamd

Adding Headers

Ww can add more information like the router the email travelled or extended headers added by the various mail server on the way to the destination. Such extended headers begin with an “X-“. rspamd can add such headers to help you filter out spam. We can do that by creating a new override file:

nano /etc/rspamd/override.d/milter_headers.conf

Add the following content to the file:

extended_spam_headers = true;

Restart RSpamd:

systemctl restart rspamd

Configuring Postfix

We need to configure Postfix to use the Rspamd milter.

Run the following commands to update the Postfix main configuration file:

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

Restart the Postfix service for changes to take effect:

systemctl restart postfix

Configuring Dovecot

Next we configure Dovecot to use Rspamd.

Open the file /etc/dovecot/conf.d/20-lmtp.conf and edit is as follows:

nano /etc/dovecot/conf.d/20-lmtp.conf
protocol lmtp {
  postmaster_address = postmaster@example.com
  mail_plugins = $mail_plugins sieve
}

Open the file /etc/dovecot/conf.d/20-imap.conf and edit is as follows:

nano /etc/dovecot/conf.d/20-imap.conf
protocol imap {
  mail_plugins = $mail_plugins imap_quota imap_sieve
}

Edit the file /etc/dovecot/conf.d/20-managesieve.conf as follows:

nano /etc/dovecot/conf.d/20-managesieve.conf
service managesieve-login {
  inet_listener sieve {
    port = 4190
  }
}

service managesieve {
  process_limit = 1024
}

Open and edit the file /etc/dovecot/conf.d/90-sieve.conf as follows:

nano /etc/dovecot/conf.d/90-sieve.conf
plugin {
    # sieve = file:~/sieve;active=~/.dovecot.sieve
    sieve_plugins = sieve_imapsieve sieve_extprograms
    sieve_after = /etc/dovecot/sieve-after
    sieve = file:/var/mail/vmail/sieve/%d/%n/scripts;active=/var/mail/vmail/sieve/%d/%n/active-script.sieve

    # From elsewhere to Junk folder
    imapsieve_mailbox1_name = Spam
    imapsieve_mailbox1_causes = COPY
    imapsieve_mailbox1_before = file:/etc/dovecot/sieve/learn-spam.sieve

    # From Junk folder to elsewhere
    imapsieve_mailbox2_name = *
    imapsieve_mailbox2_from = Spam
    imapsieve_mailbox2_causes = COPY
    imapsieve_mailbox2_before = file:/etc/dovecot/sieve/learn-ham.sieve

    sieve_pipe_bin_dir = /etc/dovecot/sieve
    sieve_global_extensions = +vnd.dovecot.pipe
}

Create a directory for the sieve scripts:

mkdir -p /etc/dovecot/sieve-after

Create a global sieve filter in the file /etc/dovecot/sieve-after/spam-to-folder.sieve. It will move emails marked as spam directly to the spam folder:

nano /etc/dovecot/sieve-after/spam-to-folder.sieve
require ["fileinto","mailbox"];

if anyof(
    header :contains ["X-Spam-Flag"] "YES",
    header :contains ["X-Spam"] "Yes",
    header :contains ["Subject"] "*** SPAM ***"
    )
{
    fileinto :create "Spam";
    stop;
}

Compile the script:

sievec /etc/dovecot/sieve-after/spam-to-folder.sieve

Create a new directory /etc/dovecot/sieve to put the sieve files in:

mkdir /etc/dovecot/sieve

Create a script, named /etc/dovecot/sieve/learn-spam.sieve, that will be triggered each time when you manually move an email into the spam folder:

nano /etc/dovecot/sieve/learn-spam.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve"];
pipe :copy "rspamd-learn-spam.sh";

Create a script, named /var/mail/vmail/sieve/global/report-ham.sieve, that will be triggered each time when you move an email out of the spam folder:

nano /etc/dovecot/sieve/learn-ham.sieve
require ["vnd.dovecot.pipe", "copy", "imapsieve", "variables"];
if string "${mailbox}" "Trash" {
  stop;
}
pipe :copy "rspamd-learn-ham.sh";

Restart Dovecot:

systemctl restart dovecot

Compile the sieve scripts and set permissions:

sievec /etc/dovecot/sieve/learn-spam.sieve
sievec /etc/dovecot/sieve/learn-ham.sieve
chmod u=rw,go= /etc/dovecot/sieve/learn-{spam,ham}.{sieve,svbin}
chown vmail.vmail /etc/dovecot/sieve/learn-{spam,ham}.{sieve,svbin}

And the last step is to create the simple shell scripts that do the actual spam/ham training.

nano /etc/dovecot/sieve/rspamd-learn-spam.sh
#!/bin/sh
exec /usr/bin/rspamc learn_spam
nano /etc/dovecot/sieve/rspamd-learn-ham.sh
#!/bin/sh
exec /usr/bin/rspamc learn_ham

and make them executable:

chmod u=rwx,go= /etc/dovecot/sieve/rspamd-learn-{spam,ham}.sh
chown vmail.vmail /etc/dovecot/sieve/rspamd-learn-{spam,ham}.sh

Restart Dovecot:

systemctl restart dovecot

Enable and restart Rspamd:

systemctl enable rspamd
systemctl restart rspamd

Creating DKIM Keys

This is not necessary if you've already configured DKIM using OpenDKIM. If this is the case then create the following:

nano /etc/rspamd/local.d/dkim_signing.conf

Enter the following line:

enabled = false;

If you wish to use RSpamd to deal with DKIM signing then follow the below steps:

First we create the folder to store our DKIM keys:

mkdir /var/lib/rspamd/dkim/

and then we create the keys for each of the domains that we handle, for example:

rspamadm dkim_keygen -b 2048 -s mail -d example.com -k /var/lib/rspamd/dkim/example.com.mail.key | tee -a  /var/lib/rspamd/dkim/example.com.mail.pub
rspamadm dkim_keygen -b 2048 -s mail -d another-example.com -k /var/lib/rspamd/dkim/another-example.com.mail.key | tee -a var/lib/rspamd/dkim/another-example.com.mail.pub

The public and private keys should now be stored in /var/lib/rspamd/dkim/

We now change the permissions of the directory for security:

chown -R _rspamd: /var/lib/rspamd/dkim
find /var/lib/rspamd/dkim -name "*.key" -exec chmod 440 {} \;
find /var/lib/rspamd/dkim -name "*.pub" -exec chmod 440 {} \;

and finally we configure RSpamd so it knows where to find the keys:

nano /etc/rspamd/local.d/dkim_signing.conf

Enter the following text:

path = "/var/lib/rspamd/dkim/$domain.$selector.key";
selector_map = "/etc/rspamd/dkim_selectors.map";
allow_username_mismatch = true;

Create /etc/rspamd/dkim_selectors.map:

nano /etc/rspamd/dkim_selectors.map
example.com mail
another-example.com mail

and restart RSpamd:

systemctl restart rspamd

DNS entries will also need to be entered using whichever DNS manager you use. For each of the domains you manage, run the following command:

cat /var/lib/rspamd/dkim/example.com.mail.pub

This will output something like the following:

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

The pieces inside the quotes need to be concatenated together and entered as a TXT DNS record with the name mail._domainkey

for example:

v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqdBRCqYzshc4LmmkxUkCH/rcIpSe/QdNIVmBrgqZmZ5zzWQi7ShdFOH7V32/VM1VRk2pkjDV7tmfbwslsymsfxgGhVHbU0R3803uRfxAiT2mYu1hCc9351YpZF4WnrdoA3BT5juS3YUo5LsDxvZCxISnep8VqVSAZOmt8wFsZKBXiIjWuoI6XnWrzsAfoaeGaVuUZBmi4ZTg0O4ylnVlIz11McdZTRe1FlONOzO7ZkQFb7O6ogFepWLsM9tYJ38TFPteqyO3XBjxHzp1AT0UvsPcauDoeHUXgqbxU7udG1t05f6ab5h/Kih+jisgHHF4ZFK3qRtawhWlA9DtS35DlwIDAQAB

Configuring Nginx

To access the RSpamD web interface, we need to create a website in Nginx.

First we'll use acme.sh to create the certificates for the site. Change to root user with:

su -

Issue the RSA certificates with:

~/.acme.sh/acme.sh --issue --dns dns_cloudns -d rspamd.example.com --keylength 4096 --key-file /etc/letsencrypt/rsa-certs/rspamd.example.com/privkey.pem --ca-file /etc/letsencrypt/rsa-certs/rspamd.example.com/chain.pem --cert-file /etc/letsencrypt/rsa-certs/rspamd.example.com/cert.pem --fullchain-file /etc/letsencrypt/rsa-certs/rspamd.example.com/fullchain.pem --pre-hook "mkdir -p /etc/letsencrypt/rsa-certs/rspamd.example.com" --post-hook "find /etc/letsencrypt/rsa-certs/rspamd.example.com/ -name '*.pem' -type f -exec chmod 600 {} \;" --renew-hook "find /etc/letsencrypt/rsa-certs/rspamd.example.com/ -name '*.pem' -type f -exec chmod 600 {} \; -exec service nginx reload \;"

and ECC certificates with:

~/.acme.sh/acme.sh --issue --dns dns_cloudns -d rspamd.example.com --keylength ec-384 --key-file /etc/letsencrypt/ecc-certs/rspamd.example.com/privkey.pem --ca-file /etc/letsencrypt/ecc-certs/rspamd.example.com/chain.pem --cert-file /etc/letsencrypt/ecc-certs/rspamd.example.com/cert.pem --fullchain-file /etc/letsencrypt/ecc-certs/rspamd.example.com/fullchain.pem --pre-hook "mkdir -p /etc/letsencrypt/ecc-certs/rspamd.example.com" --post-hook "find /etc/letsencrypt/ecc-certs/rspamd.example.com/ -name '*.pem' -type f -exec chmod 600 {} \;" --renew-hook "find /etc/letsencrypt/ecc-certs/rspamd.example.com/ -name '*.pem' -type f -exec chmod 600 {} \; -exec service nginx reload \;"

Exit root by typing exit.

Create the file as follows:

nano /etc/nginx/sites-available/rspamd.example.com

and enter the following (see the Nginx tutorial for more information on the includes):

server {

    listen 99 ssl http2;
    listen [::]:99 ssl http2;

    server_name rspamd.example.com;
    client_max_body_size 10M;

    ssl_certificate /etc/letsencrypt/rsa-certs/rspamd.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/rsa-certs/rspamd.example.com/privkey.pem;
    ssl_certificate /etc/letsencrypt/ecc-certs/rspamd.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/ecc-certs/rspamd.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/ecc-certs/rspamd.example.com/chain.pem;

    include /etc/nginx/custom-config/ssl.conf;
    include /etc/nginx/custom-config/header.conf;

    location / {
        include /etc/nginx/custom-config/proxy.conf;
        proxy_pass http://127.0.0.1:11334;
        client_max_body_size 10M;
    }
}

I have used a different port. This way I have more control over security and I can restrict the port to my own static IP addresses. It's a good idea to do this with any server management web tools such as PHPMyAdmin and Webmin.

Enable the website:

ln -s /etc/nginx/sites-available/rspamd.example.com /etc/nginx/sites-enabled/

and reload nginx

service nginx reload

The website is accessed using the password you configured at the start of this guide.

Using ClamAV

This step only applies if you have installed and are running ClamAV.

Add x-virus to the milter headers in the file /etc/rspamd/local.d/milter_headers.conf:

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

Create the file override.d/antivirus.conf:

nano /etc/rspamd/override.d/antivirus.conf

Enter the following text:

clamav {
  attachments_only = false;
  symbol = "CLAM_VIRUS";
  type = "clamav";
  action = "reject";
  servers = "/run/clamav/clamd.ctl";
}

Add the _rspamd user to the clamav group (required to access socket):

usermod -a -G clamav _rspamd

Reload Rspamd:

service rspamd reload

Explanation:

Attachment_only = false defines whether just attachments are scanned or whether the entire email including images gets scanned.

symbol = "CLAM_VIRUS" Adds a symbol named CLAM_VIRUS that can be used to assign scores or added as email headers.

type = "clamav" sets a few defaults in the antivirus module that tell rspamd how to talk to ClamAV

action = "reject" is an optional parameter that we use to instantly reject the email if a virus is found. We do not add a value to the spam score. Instead we refuse to accept the email during the incoming SMTP connection.

servers = "/var/run/clamav/clamd.ctl" defines the way to communicate with ClamAV. In this case we tell it to use the Unix socket used by clamav-daemon

Testing

Now we can test the virus scanner configuration and make sure it's working. First we download a test signature to use:

wget https://secure.eicar.org/eicar.com

And then we can use the swaks utility to send a test email:

apt update && apt install swaks
swaks --to user@example.org --attach - --server localhost < eicar.com`

Swaks' primary design goal is to be a flexible, scriptable, transaction-oriented SMTP test tool. It handles SMTP features and extensions such as TLS, authentication, and pipelining; multiple version of the SMTP protocol including SMTP, ESMTP, and LMTP; and multiple transport methods including UNIX-domain sockets, internet-domain sockets, and pipes to spawned processes.

Further Reading: http://www.jetmore.org/john/code/swaks/latest/doc/ref.txt

Other Modules

Greylisting

Create the greylist.conf file:

nano /etc/rspamd/local.d/greylist.conf

Enter the following line:

servers = "localhost:6380";

To whitelist certain domains, create the file greylist-whitelist-domains.inc:

nano /etc/rspamd/local.d/greylist-whitelist-domains.inc

and simply add domainsn that you wish to whitelist, for example:

gmail.com
hotmail.com
github.com
outlook.com

Phishing

To enable the use of the openphish.com database, create the phishing.conf file:

nano /etc/rspamd/local.d/phishing.conf

Enter the following line:

openphish_enabled = true;

Firewall

RSpamd needs to be able to communicate to the RSpamd server on destination port 11335. Add the following rule to iptables to allow this:

iptables -A OUTPUT ! -o lo -p udp -d 88.99.142.95 -m conntrack --ctstate NEW -m udp --dport 11335 -j ACCEPT -m comment --comment "RSpamd"

Spam Training

Method 1: Untroubled.org

Spam archives can be found at http://untroubled.org/spam/

An example of using one of them to train RSpamd follows:

First install p7zip:

apt update && apt install p7zip p7zip-full

Create a spam directory and move into it:

mkdir ~/spam && cd ~/spam

Download an archive:

wget http://untroubled.org/spam/2020-01.7z

Extract the archive:

7z x 2020-01.7z

Learn the spam:

rspamc learn_spam ~/spam/2020/01/

repeat the steps with as many archives as you want.

You'll probably also want to exclude this spam directory from any virus scans you do in the future.

Method 2: GMail

If your gmail account collects quite a decent amount of spam, then its possible to export the spam folder using Google Takeout and getting RSpamd to learn from it.

First of all, you'll probably want to have a trawl through the gmail spam folder and delete any emails that shouldn't be classed as spam.

Once you're happy that your spam folder contains nothing but spam, go to Google Takeout here:

https://takeout.google.com/settings/takeout?pli=1

Under the 'Select data to include' section, click 'Deselect all'

Scroll down and tick the box to the right of 'Mail'

Click on the button beneath that currently says 'All Mail data included'

Make sure everything is unticked except 'Spam'

Click 'OK' and then 'Next Step'

Choose the option to send a download link to email and proceed

Once you've got the download link, download and then send the file to your server using whichever method you're comfortable with ie sftp, ssh, rsync, etc...

I personally uploaded the file to my Nextcloud and then copied it from there to my home directory.

Assuming that the takeout file is now in your home directory, unzip the archive to the spam directory (created in method 2):

Use the appropriate line depending on whether your archive is a zip or a tgz

unzip takeout-20200402T110047Z-001.zip -d ~/spam
tar -zvxf takeout-20200402T110047Z-001.zip -C ~/spam

Install mb2md. This utility converts mbox format mail archives to the maildir format that RSpamd understands.

apt update && apt install mb2md

Now use the utility to convert the mbox file to maildir:

mb2md -s ~/spam/Takeout/Mail/ -d ~/spam

And finally, have RSpamd learn the spam:

rspamc learn_spam ~/spam/.Spam_mbox/cur/