
Running a mail server without spam filtering is like leaving your front door wide open. Every unfiltered message that lands in a user’s inbox is a trust problem waiting to happen. This guide shows you exactly how to install Rspamd on Debian 13, configure it with Valkey caching, connect it to Postfix via milter, and get DKIM signing working so your outgoing mail reaches inboxes instead of spam folders.
Rspamd is a fast, open-source spam filtering engine used by high-volume mail servers worldwide. It scores every message using SPF, DKIM, DMARC, Bayesian filtering, greylisting, and fuzzy hashing simultaneously. On Debian 13 (Trixie), the full stack integrates cleanly with systemd journald, making monitoring straightforward across all mail services.
By the end of this guide, your server will have a production-ready Rspamd setup with Postfix milter integration, Valkey statistics caching, DKIM signing for outgoing mail, greylisting protection, and spam header injection for Dovecot Sieve routing.
Prerequisites
Before you begin this Linux server tutorial, make sure the following are in place:
System Requirements:
- Debian 13 (Trixie) installed and fully updated
- Root or sudo access
- Minimum 2 GB RAM (4 GB+ recommended for production)
- Minimum 2 CPU cores and 20 GB free disk space
Software Requirements:
- Postfix installed and accepting mail on port 25
curl,gnupg2, andlsb-releaseavailable via APT- systemd active (default on Debian 13)
Network Requirements:
- Firewall open on ports 25 (SMTP), 587 (submission), and 465 (SMTPS)
- DNS records configured: A, MX, PTR
- A working outbound internet connection for APT downloads
Verify your system is ready:
free -h # Check available RAM
df -h / # Check disk space
nproc # Check CPU count
systemctl status postfix # Confirm Postfix is running
Understanding the Mail Flow Architecture
Before touching your server, it helps to understand what you are building. Here is the complete pipeline this guide sets up:
Incoming mail:
- Mail arrives at Postfix on port 25
- Postfix passes it to Rspamd via milter protocol (port 11332)
- Rspamd queries Valkey for statistics, greylisting data, and Bayesian scores
- Rspamd adds spam score headers to the message
- Mail returns to Postfix with headers attached
- Postfix delivers to Dovecot via LMTP
- Dovecot Sieve checks headers and routes spam to the Junk folder
Outgoing mail (authenticated users):
- User sends via port 587 or 465
- Postfix forwards to Rspamd
- Rspamd signs the message with a DKIM signature
- Postfix sends the signed message
Valkey acts as the Redis-compatible key-value store that holds Bayesian statistics, rate limiting counters, fuzzy hashes, and greylisting data. It connects to Rspamd via a Unix socket for best performance and security.
Step 1: Install and Configure Valkey
Why Valkey Instead of Redis
Redis changed its open-source licensing in 2024. Valkey is the Linux Foundation-backed, fully open-source drop-in replacement that is already available in the official Debian 13 repositories. It is 100% Redis-compatible, which means Rspamd works with it without any code changes.
Install Valkey
apt update
apt install -y valkey
valkey-server --version
You should see Valkey 7.2.5 or newer in the output.
Configure Valkey for Rspamd
Rspamd recommends using a Unix socket instead of TCP. This improves performance and removes unnecessary network exposure.
Edit the Valkey configuration file:
nano /etc/valkey/valkey.conf
Find and update the following settings:
# Disable TCP - use Unix socket only
port 0
# Socket path - must be named exactly valkey.sock
unixsocket /run/valkey/valkey.sock
unixsocketperm 770
# Memory limit (adjust based on your server)
maxmemory 256mb
maxmemory-policy volatile-ttl
# Persist greylisting data across restarts
save 900 1
save 300 10
save 60 10000
What these settings do:
port 0disables TCP listening entirely, blocking any network-based accessunixsocket /run/valkey/valkey.sockcreates the Unix socket Rspamd will connect tounixsocketperm 770allows group members (including_rspamd) to read and write the socketmaxmemory 256mbcaps RAM usage; increase to 512mb on servers handling over 1,000 emails per hourmaxmemory-policy volatile-ttlrespects Rspamd’s own TTLs and evicts expiring data first- The
savelines persist data to disk so greylisting survives a server restart
Start Valkey and Verify
systemctl enable valkey
systemctl start valkey
systemctl status valkey
# Test the socket connection
valkey-cli -s /run/valkey/valkey.sock ping
# Expected output: PONG
Add the Rspamd User to the Valkey Group
Rspamd runs as the _rspamd user, which needs permission to access the socket:
usermod -a -G valkey _rspamd
# Verify group membership
groups _rspamd
# Expected: _rspamd valkey
Prevent Valkey from Being Auto-Removed
If APT considers Valkey an automatic dependency, apt autoremove will silently remove it during routine maintenance. This breaks Rspamd’s statistics with no obvious error. Mark it as manually installed:
apt-mark manual valkey-server valkey-tools
# Confirm
apt-mark showmanual | grep valkey
Step 2: Add the Official Rspamd Repository and Install Rspamd on Debian 13
Why Use the Official Repository
The Debian 13 repository includes Rspamd, but it may lag several months behind the current release. The official Rspamd repository ships the newest version with the latest spam rules, which update two to four times per day.
Add the Repository
# Install prerequisites
apt install -y curl gnupg2 lsb-release
# Create the modern APT keyrings directory
mkdir -p /etc/apt/keyrings
# Import the Rspamd GPG key using the modern keyring method
curl -fsSL https://rspamd.com/apt-stable/gpg.key | \
gpg --dearmor -o /etc/apt/keyrings/rspamd.gpg
# Add the Rspamd repository
echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] http://rspamd.com/apt-stable/ $(lsb_release -cs) main" | \
tee /etc/apt/sources.list.d/rspamd.list
# Update package list
apt update
Note: Debian 13 uses /etc/apt/keyrings/ for all GPG keys. Never use the deprecated apt-key method on Trixie.
Install Rspamd
apt install --no-install-recommends -y rspamd
# Verify the version
rspamd --version
# Expected: Rspamd 3.13.x or newer
# Confirm the service is running
systemctl status rspamd
Rspamd starts automatically with a default configuration. All customizations go into /etc/rspamd/local.d/ and never into the main rspamd.conf file.
Step 3: Configure Rspamd on Debian 13
Configuration File Hierarchy
Rspamd uses a layered configuration system:
/etc/rspamd/rspamd.conf— Main config file. Never edit this./etc/rspamd/local.d/— Your local overrides. All changes go here./etc/rspamd/override.d/— Full overrides that replace entire sections. Rarely needed.
Connect Rspamd to Valkey
Create the Redis configuration file that points Rspamd at your Valkey socket:
cat > /etc/rspamd/local.d/redis.conf << 'EOF'
servers = "/run/valkey/valkey.sock";
write_servers = "/run/valkey/valkey.sock";
read_servers = "/run/valkey/valkey.sock";
EOF
Configure Logging to systemd Journal
Debian 13 uses journald as the standard logging backend. Configure Rspamd to match Postfix and Dovecot:
cat > /etc/rspamd/local.d/logging.inc << 'EOF'
type = "console";
level = "info";
log_usec = true;
EOF
Using type = "console" routes Rspamd output through systemd, which captures it into journald. This means you can monitor the full mail stack with a single journalctl command.
Configure Spam Action Thresholds
These thresholds control what Rspamd does at each spam score level:
cat > /etc/rspamd/local.d/actions.conf << 'EOF'
# Reject obvious spam
reject = 15.0;
# Add spam headers (mail goes to Junk via Sieve)
add_header = 6.0;
# Greylist suspicious mail
greylist = 4.0;
EOF
Score breakdown:
| Score Range | Action | What Happens |
|---|---|---|
| 0 – 3.99 | No action | Delivered to INBOX |
| 4.0 – 5.99 | Greylist | Temporarily deferred; legitimate servers retry |
| 6.0 – 14.99 | Add header | Headers added; Sieve routes to Junk |
| 15.0+ | Reject | Rejected at SMTP level; sender receives bounce |
Configure the Milter Worker
Rspamd’s proxy worker handles milter connections from Postfix:
cat > /etc/rspamd/local.d/worker-proxy.inc << 'EOF'
bind_socket = "127.0.0.1:11332";
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
EOF
Configure Spam Headers
These headers are what Dovecot Sieve reads to route spam to the Junk folder:
cat > /etc/rspamd/local.d/milter_headers.conf << 'EOF'
use = ["x-spam-status", "x-spam-level", "authentication-results"];
extended_spam_headers = true;
EOF
Headers added to every message:
X-Spam-Status: No, score=-0.80— Simple yes/no spam indicator with scoreX-Spam-Level: *******— Visual representation; each*equals one spam pointX-Spamd-Result— Full rule breakdown showing every check that firedAuthentication-Results— SPF, DKIM, and DMARC results in one place
Test and Restart
# Check for configuration errors
rspamadm configtest
# Expected: syntax OK
# Restart Rspamd to load all changes
systemctl restart rspamd
Step 4: Integrate Rspamd with Postfix
Connect Postfix to Rspamd using the milter protocol. Use postconf rather than manually editing main.cf:
postconf -e "smtpd_milters = inet:127.0.0.1:11332"
postconf -e "non_smtpd_milters = inet:127.0.0.1:11332"
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"
What each setting does:
smtpd_milters— Applies Rspamd to all incoming mail arriving on port 25non_smtpd_milters— Applies Rspamd to locally generated mail like bounce messagesmilter_protocol = 6— Sets the milter protocol versionmilter_mail_macros— Passes the client IP, hostname, and auth status to Rspamd for scoringmilter_default_action = accept— If Rspamd is unreachable, Postfix accepts mail anyway; you never lose messages because of a filter outage
Reload Postfix and Verify
systemctl reload postfix
# Confirm Rspamd is listening on the milter port
ss -tlnp | grep 11332
# Expected: LISTEN 0 4096 127.0.0.1:11332
Step 5: Set Up DKIM Signing
Why DKIM Matters
Without DKIM, receiving mail servers have no way to verify your messages are genuine. Your emails score lower at Gmail and Outlook, DMARC fails, and inbox placement drops. With DKIM, your outgoing mail carries a cryptographic signature that proves authenticity and improves deliverability.
Generate DKIM Keys
mkdir -p /var/lib/rspamd/dkim
rspamadm dkim_keygen \
-s mail \
-d yourdomain.com \
-k /var/lib/rspamd/dkim/yourdomain.com.mail.key \
> /var/lib/rspamd/dkim/yourdomain.com.mail.txt
What gets created:
.keyfile — Private key that stays on your server and signs mail. Keep this secret..txtfile — Public key formatted as a DNS TXT record. This goes into DNS.
Set Permissions
chown -R _rspamd:_rspamd /var/lib/rspamd/dkim
chmod 640 /var/lib/rspamd/dkim/*.key
chmod 644 /var/lib/rspamd/dkim/*.txt
Private keys must be readable only by _rspamd. If someone gets your private key, they can forge mail from your domain.
Configure DKIM Signing in Rspamd
cat > /etc/rspamd/local.d/dkim_signing.conf << 'EOF'
path = "/var/lib/rspamd/dkim/$domain.$selector.key";
selector = "mail";
sign_authenticated = true;
sign_local = false;
use_domain = "header";
allow_username_mismatch = true;
EOF
Rspamd automatically substitutes $domain and $selector with the correct values per message. Setting sign_authenticated = true ensures only mail from real users on ports 587 and 465 gets signed.
Publish the DNS TXT Record
View the generated record:
cat /var/lib/rspamd/dkim/yourdomain.com.mail.txt
You will see output similar to:
mail._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=MIGfMA0GCSqGSIb3DQEBA...IDAQAB" ) ;
In your DNS control panel, add a TXT record with:
- Name:
mail._domainkey - Value: The full key string as one line, with all quotes, parentheses, and line breaks removed
DNS propagation typically takes up to 48 hours, though most resolvers pick it up within 30 minutes.
Restart and Verify
rspamadm configtest
systemctl restart rspamd
# Check for DKIM activity
journalctl -u rspamd --since "1 minute ago" | grep -i dkim
Step 6: Monitor Rspamd with systemd Journal
Since Rspamd logs to journald on Debian 13, all monitoring happens through journalctl. This matches Postfix, Dovecot, and any other modern service running on your server.
Core Monitoring Commands
# Live Rspamd log feed
journalctl -u rspamd -f
# Monitor the full mail stack together (recommended)
journalctl -u postfix -u dovecot -u rspamd -f
# Errors only
journalctl -u rspamd -p err
# Activity from the last hour
journalctl -u rspamd --since "1 hour ago"
# Check Valkey connection
journalctl -u rspamd | grep -E "redis|valkey" | tail -n 10
# Watch DKIM signing
journalctl -u rspamd -f | grep --line-buffered -i dkim
Reading a Spam Score Log Entry
A typical Rspamd log entry looks like this:
rspamd_task_write_log: id: <abc123@domain.com>,
ip: 198.51.100.1, from: <sender@external.com>,
(default: F (no action): [-0.80/15.00]
[R_SPF_ALLOW(-0.20), DMARC_POLICY_ALLOW(-0.50),
R_DKIM_ALLOW(-0.20), MIME_GOOD(-0.10)])
How to read this:
(no action)— Mail is clean, delivered to INBOX[-0.80/15.00]— Score is -0.80 out of the 15.0 reject thresholdR_SPF_ALLOW(-0.20)— SPF passed, score reduced by 0.20R_DKIM_ALLOW(-0.20)— DKIM passed, score reduced by 0.20
Negative scores indicate trusted, well-authenticated senders. High positive scores indicate spam.
Step 7: Test the Full Installation
Send a Test Email
echo "Testing Rspamd integration" | mail -s "Rspamd Test" user@yourdomain.com
# Watch the logs as the message processes
journalctl -u postfix -u rspamd -f
Verify Spam Headers in the Delivered Message
Open the message in your mail client, view source, and confirm these headers exist:
X-Spam-Status: No, score=-0.80
X-Rspamd-Action: no action
X-Spamd-Result: default: False [-0.80 / 15.00];
Authentication-Results: yourdomain.com; spf=pass; dkim=none; dmarc=none;
Test DKIM Signing
Send a message to an external address and check the raw headers for a DKIM-Signature: field. You can also test your full setup at mail-tester.com for a score out of 10.
Verify Valkey Is Working
valkey-cli -s /run/valkey/valkey.sock info keyspace
# After processing some mail, this should show database keys
Test Spam Detection with GTUBE
The Generic Test for Unsolicited Bulk Email (GTUBE) string triggers any working spam filter. Send a message containing it to confirm Rspamd flags obvious spam correctly.
Troubleshooting Common Issues
| Problem | Symptom | Fix |
|---|---|---|
| Valkey socket name mismatch | Rspamd logs cannot connect to redis |
Check /etc/valkey/valkey.conf and confirm unixsocket is set to /run/valkey/valkey.sock |
_rspamd not in Valkey group |
Bayesian filtering and greylisting silently broken | Run usermod -a -G valkey _rspamd then systemctl restart rspamd |
Valkey removed by apt autoremove |
Stats stop working after maintenance | Run apt-mark manual valkey-server valkey-tools |
| DKIM key not found | DKIM_SIGNED never appears in logs |
Verify path with ls /var/lib/rspamd/dkim/ and check ownership with ls -la /var/lib/rspamd/dkim/ |
| Milter connection refused | Postfix logs milter: can't connect to filter |
Run ss -tlnp | grep 11332 and confirm Rspamd is listening on 127.0.0.1:11332 |
| No spam headers in delivered mail | X-Spam-Status is missing |
Confirm postconf -n | grep milter shows the correct milter address |
| Config changes not applying | Behavior unchanged after edits | Always run rspamadm configtest and systemctl restart rspamd after any change in /etc/rspamd/local.d/ |
For any persistent issue, start with:
journalctl -u rspamd -p err
This shows only error-level messages and cuts through the noise fast.
Congratulations! You have successfully installed Rspamd. Thanks for using this tutorial to install the latest version of Rspamd open-source spam filtering system on Debian 13 “Trixie” Linux system. For additional help or useful information, we recommend you check the official Rspamd website.