
Anyone who has run a mail server for more than a few months knows the drill: spam volume creeps up, SpamAssassin starts choking under load, and eventually you’re staring at a load average that has no business being that high on a box that only handles mail. Rspamd solves that problem elegantly — it’s written in C, handles thousands of messages per minute without breaking a sweat, and integrates with Redis for statistics instead of writing bloated flat files to disk.
This guide walks through a production-grade Rspamd installation on Ubuntu 26.04 LTS, the kind you’d actually want running on a mail server that handles real traffic, not just a lab demo. It covers the official APT repository setup, Redis backend configuration, Postfix milter integration, DKIM signing, and the security hardening steps that get skipped far too often in quick-start tutorials. Along the way, there’s troubleshooting guidance drawn from the errors that actually show up in journalctl and /var/log/mail.log when things go sideways — because they will, eventually, especially the first time DNS resolution misbehaves under RBL query load.
Rspamd (short for “Rapid Spam Daemon”) isn’t just a spam filter bolted onto Postfix. It’s a full analysis engine that combines Bayesian classification, DNS blacklists, fuzzy hashing, SPF/DKIM/DMARC validation, and optional neural network scoring into a single scoring pipeline. Every message gets a numeric score built from individual “symbols,” and that score determines whether the message gets delivered, greylisted, tagged, or rejected outright. If you’re migrating from SpamAssassin, the jump in throughput alone justifies the switch — Rspamd typically processes messages in single-digit milliseconds where SpamAssassin can take seconds under heavy Perl regex load.
Before diving into commands, it’s worth setting expectations: this isn’t a five-minute install if you want it done right. Budget 30-45 minutes for a proper setup including Redis, DKIM, and milter integration testing.
Why Rspamd Instead of SpamAssassin or Amavis
Anyone who has profiled a mail server under spam load has seen the pattern — SpamAssassin’s Perl-based regex engine burns CPU cycles fast, and Amavis adds another layer of process overhead on top of that. Rspamd was built specifically to avoid this. It runs as a persistent daemon with worker processes instead of spawning a new process per message, which means no fork/exec overhead per email.
The practical difference shows up during traffic spikes. A server that gets hit with a sudden inbound spam wave — say, a botnet testing open relays or a compromised account spraying outbound junk — will show Rspamd’s worker queue depth rising gracefully, while a SpamAssassin setup under the same load often triggers OOM killer events or maxes out available Perl interpreter slots. Rspamd’s Redis-backed statistics also mean Bayesian learning persists reliably across restarts, something that flat-file Bayes databases in SpamAssassin handle far less gracefully at scale.
Prerequisites Before You Start
Get these sorted before touching the Rspamd repository, because half of the “it doesn’t work” support threads trace back to a missing prerequisite rather than a broken config.
- Ubuntu 26.04 LTS server with root or sudo access
- A working MTA — this guide assumes Postfix, though Rspamd also integrates with Exim (limited support) and Sendmail
- A domain with DNS you control, for DKIM and SPF records
- At least 1 vCPU and 512MB-1GB RAM dedicated to Rspamd and Redis combined, more if you expect high volume
- Basic comfort with the Linux command line and systemd service management
If you’re running this on a VPS with 512MB total RAM, expect Redis and Rspamd to compete for memory under load — plan for at least 1GB total system memory on anything handling more than a trickle of mail.
Step 1: Update the System and Install Dependencies
Start clean. A stale package cache is a common source of GPG key mismatches during repository setup.
sudo apt update && sudo apt upgrade -y
sudo apt install -y curl gnupg2 lsb-release ca-certificates
The lsb-release package matters here because the repository URL construction below depends on lsb_release -cs returning the correct Ubuntu codename.
Step 2: Add the Official Rspamd APT Repository
Do not rely on Ubuntu’s default universe repository for Rspamd if you want current releases with active security patches — the version bundled in Ubuntu’s own archives lags behind and sometimes ships with known bugs already fixed upstream. Use the official Rspamd repository instead, and use the modern signed-by method rather than the deprecated apt-key add approach, which Ubuntu has fully removed support for in recent releases.
# Add the Rspamd GPG signing key
curl -fsSL https://rspamd.com/apt-stable/gpg.key | \
sudo gpg --dearmor -o /usr/share/keyrings/rspamd.gpg
# Register the repository, scoped to this key
echo "deb [signed-by=/usr/share/keyrings/rspamd.gpg] https://rspamd.com/apt-stable/ $(lsb_release -cs) main" | \
sudo tee /etc/apt/sources.list.d/rspamd.list
# Refresh package lists
sudo apt update
This method avoids the old-style trusted keyring approach entirely, which is important — APT now flags unscoped keys as deprecated, and eventually as a hard error.
Step 3: Install Rspamd and Redis
Rspamd needs Redis for statistics storage, fuzzy hash caching, and Bayesian classifier data. Skipping Redis leaves Rspamd running on in-memory defaults that don’t survive a restart, which defeats the purpose of building spam-learning history over time.
sudo apt install -y rspamd redis-server
sudo systemctl enable --now rspamd
sudo systemctl enable --now redis-server
Confirm both services are actually running rather than just “started successfully” in the terminal — a service can start and crash within seconds if the config has an issue.
sudo systemctl status rspamd redis-server
Both should show active (running). Then check the listening ports, since Rspamd exposes three by default:
sudo ss -tlnp | grep rspamd
You should see 127.0.0.1:11333 (the normal scanning worker), 127.0.0.1:11334 (the controller/web UI), and 127.0.0.1:11332 (the proxy worker used for milter integration). If any of these ports are missing, check journalctl -u rspamd -n 50 immediately — don’t move on to Postfix integration with a half-broken worker setup.
Step 4: Configure Redis for Rspamd
Never leave Redis exposed on its default configuration without at least binding it to localhost. Edit /etc/redis/redis.conf:
sudo nano /etc/redis/redis.conf
Set or confirm these directives:
bind 127.0.0.1 ::1
maxmemory 512mb
maxmemory-policy volatile-ttl
The maxmemory-policy setting matters more than people realize — without it, Redis will keep accumulating fuzzy hash and statistics data indefinitely until it hits system memory limits, which on a smaller VPS turns into an OOM event at the worst possible time (usually during a traffic spike, because that’s when Redis is writing the most). Restart Redis after editing:
sudo systemctl restart redis-server
redis-cli ping
A PONG response confirms Redis is alive and reachable.
Now tell Rspamd where to find it. Create /etc/rspamd/local.d/redis.conf:
servers = "127.0.0.1:6379";
Never edit files directly inside /etc/rspamd/ — that directory holds the default configs shipped by the package, and any upgrade will overwrite your changes silently. The local.d/ directory merges with defaults, while override.d/ completely replaces a given setting. This distinction trips up a lot of first-time Rspamd admins who wonder why their config “disappeared” after an apt upgrade.
Step 5: Set the Controller (Web UI) Password
The web interface at port 11334 ships without a password by default in some install paths, which is a genuinely bad idea to leave open even on localhost, because anything running on the same box (or accessible through a reverse proxy misconfiguration) could hit it. Generate a hashed password:
rspamadm pw
Enter your passphrase when prompted, then copy the resulting hash into /etc/rspamd/local.d/worker-controller.inc:
password = "$2$your_generated_hash_here";
bind_socket = "localhost:11334";
The explicit bind_socket line is worth adding even though localhost is often the default — it removes any ambiguity about whether the controller is reachable externally. Restart Rspamd to apply:
sudo systemctl restart rspamd
Step 6: Configure Spam Score Thresholds
Rspamd’s default action thresholds are sane for most deployments but rarely match a specific mail server’s traffic pattern exactly. Create /etc/rspamd/local.d/actions.conf:
reject = 15;
add_header = 6;
greylist = 4;
These numbers represent cumulative symbol scores, not fixed rules — a message accumulates points from dozens of individual checks (SPF failure, missing DKIM, RBL hits, Bayesian classification, phishing heuristics), and the total determines the action taken. If you’re migrating off SpamAssassin, resist the temptation to copy over old thresholds directly; Rspamd’s scoring model isn’t a 1:1 match, and blindly porting numbers tends to produce either a flood of false positives or a filter that lets everything through.
For servers that handle sensitive B2B mail where a false positive costs a client relationship, consider running conservative thresholds initially:
reject = 999;
add_header = 1;
greylist = 999;
This effectively disables rejection while still tagging suspicious mail with headers, letting you compare Rspamd’s judgment against real traffic before flipping the switch to full enforcement.
Step 7: Integrate Rspamd with Postfix
This is where most of the actual value gets realized — Rspamd needs to sit in the mail path as a milter. Edit /etc/postfix/main.cf:
smtpd_milters = inet:localhost:11332
milter_default_action = accept
milter_protocol = 6
The milter_default_action = accept line matters for availability: if Rspamd is temporarily unreachable (say, during a restart for config changes), Postfix will accept mail rather than bounce it. Some administrators prefer tempfail here for stricter security posture, but that trade-off depends heavily on how critical zero mail loss is for your organization versus how tolerant you are of a brief window of unfiltered mail.
Configure the proxy worker in /etc/rspamd/local.d/worker-proxy.inc:
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
Restart both services:
sudo systemctl restart rspamd
sudo systemctl restart postfix
Send a test message through the server and check /var/log/mail.log for Rspamd processing entries, and inspect the delivered message headers for X-Spam and X-Spamd-Result — their presence confirms the milter pipeline is functioning correctly.
Step 8: Configure DKIM Signing
Outbound mail without DKIM signing gets flagged by nearly every major receiving mail provider these days — Gmail and Yahoo’s bulk sender requirements made this non-negotiable a while back. Generate a keypair:
sudo rspamadm dkim_keygen -s mail -d yourdomain.com -k /var/lib/rspamd/dkim/yourdomain.com.mail.key
Fix ownership, since the default DKIM directory often doesn’t exist post-install and needs to be created and owned correctly:
sudo mkdir -p /var/lib/rspamd/dkim
sudo chown _rspamd:_rspamd /var/lib/rspamd/dkim
sudo chown _rspamd:_rspamd /var/lib/rspamd/dkim/yourdomain.com.mail.key
sudo chmod 600 /var/lib/rspamd/dkim/yourdomain.com.mail.key
Configure the signing module in /etc/rspamd/local.d/dkim_signing.conf:
domain {
yourdomain.com {
selectors [
{
path = "/var/lib/rspamd/dkim/yourdomain.com.mail.key";
selector = "mail";
}
]
}
}
The rspamadm dkim_keygen command also prints the exact TXT record to publish in DNS — copy it into your DNS zone for mail._domainkey.yourdomain.com. A mismatched selector name between the config and the DNS record is one of the more common gotchas here; if outbound mail suddenly starts getting flagged after a DKIM setup, check that the selector string in both places matches character-for-character.
Step 9: Run the Configuration Wizard (Optional but Recommended)
For anyone who wants a guided pass through the essential settings before going fully manual, Rspamd ships an interactive wizard:
sudo rspamadm configwizard
It walks through Redis connection details, controller password setup, and DKIM signing in one guided flow — genuinely useful the first time, less necessary once you’ve done this a handful of times and know the config file layout by heart.
Verifying the Installation
Confirm configuration syntax is valid before restarting anything in production:
sudo rspamadm configtest
Test message scanning directly:
echo "Test message" | rspamc
Expect output showing symbol results, a computed spam score, and an action recommendation. Then check the web dashboard at http://your-server-ip:11334 (through an SSH tunnel or VPN if the controller isn’t exposed externally, which it shouldn’t be) to confirm statistics and configuration panels load correctly.
Performance Tuning for Production Workloads
A default Rspamd install handles moderate traffic fine, but a server pushing tens of thousands of messages daily benefits from specific tuning.
- CPU: Rspamd scales workers based on CPU core count automatically, but explicitly set
worker normal { count = 4; }in/etc/rspamd/local.d/worker-normal.incon multi-core boxes to guarantee parallel scanning capacity during traffic spikes - Memory: Cap Redis
maxmemorydeliberately rather than letting it grow unbounded — a Redis instance that consumes all available RAM will eventually get killed by the OOM reaper, taking Bayesian statistics down with it - Disk I/O: Move
/var/log/rspamd/logging to a separate disk or uselog_type = "syslog";with rate limiting if verbose logging is generating heavy write I/O on busy servers - Network: Run a local recursive DNS resolver like Unbound rather than pointing Rspamd at public resolvers — Rspamd performs intensive DNS lookups for RBLs, DKIM, and DMARC checks, and public resolvers like 8.8.8.8 or 1.1.1.1 rate-limit RBL queries specifically, causing timeouts under load
- Enable neural network scoring for improved detection accuracy once you have enough learned Bayesian data (a few thousand ham/spam samples minimum) to make it worthwhile
On a real production box handling several thousand messages an hour, the single biggest performance win tends to be the local DNS resolver — skipping it is the most common cause of mysteriously slow scan times that otherwise look like a CPU or memory bottleneck.
Security Hardening Checklist
Security here isn’t optional polish — an exposed Rspamd controller or an unsecured Redis instance is a real attack surface.
- Set a strong controller password using
rspamadm pwand never leave the default unauthenticated state active - Bind the controller worker to localhost explicitly with
bind_socket = "localhost:11334"; - Firewall the milter port so only your MTA can reach it:
sudo ufw allow from <mta-ip> to any port 11332 proto tcpand explicitly deny 11334 from external access - Verify file ownership on
/var/lib/rspamdis set to_rspamd:_rspamdwith restrictive permissions (chmod 750) - Keep the system patched —
sudo apt update && sudo apt upgradeon a regular schedule, since Rspamd security advisories do occasionally surface and unpatched daemons handling untrusted mail content are a real risk vector - Use HTTPCrypt encryption if running multiple Rspamd instances that need to communicate across a network for shared fuzzy hash storage or clustered scanning
Troubleshooting Common Issues
Rspamd service fails to start
Check sudo journalctl -u rspamd -n 50 first, then run rspamadm configtest to catch syntax errors in your local.d overrides. A single misplaced semicolon in UCL config syntax will silently prevent the service from starting.
Permission denied errors on /var/lib/rspamd
This usually happens after manual DKIM key placement or a fresh install where the directory structure wasn’t fully created. Fix it with:
sudo chown -R _rspamd:_rspamd /var/lib/rspamd /var/log/rspamd
Web interface unreachable
Confirm the controller worker is actually running on port 11334 with sudo lsof -i :11334, and double-check firewall rules aren’t blocking the tunnel or VPN path you’re using to reach it.
Redis connection failures
Run redis-cli ping to confirm Redis itself is healthy, then rspamc stat to verify Rspamd can actually reach it. A common cause is Redis binding only to a non-default interface after a config edit gone wrong.
Mail passing through unfiltered
Verify the Postfix milter line is correctly pointing to port 11332, and confirm the Rspamd proxy worker is actually running that milter mode — check /etc/rspamd/local.d/worker-proxy.inc for the milter = yes; directive.
Poor spam detection accuracy despite correct setup
This almost always traces back to insufficient Bayesian training data. Feed it real samples:
rspamc learn_spam /path/to/known_spam.eml
rspamc learn_ham /path/to/known_good.eml
Detection accuracy improves noticeably once the classifier has a few hundred learned examples in each category.