Sign inSign up

ricariel/rspamd

By ricariel

•Updated about 8 hours ago

Rspamd image on Debian Trixie with opinionated defaults and env-var wiring

Image
0

50K+

ricariel/rspamd repository overview

⁠rspamd-docker

A production-ready Rspamd⁠ container image built on the official rspamd/rspamd image, with an opinionated default configuration, runtime env-var wiring, and optional integration with a range of external spam-fighting services.

The container runs as the unprivileged user 11333 (_rspamd).


⁠Table of Contents


⁠Ports

PortProtocolPurpose
11332TCPMilter protocol (Postfix/Dovecot integration)
11333TCPNormal worker — spam scanning endpoint
11334TCPController / Web UI
11335UDP/TCPFuzzy storage

⁠Quick Start

docker run -d \
  --name rspamd \
  -p 11332:11332 \
  -p 11333:11333 \
  -p 11334:11334 \
  -e REDIS=redis:6379 \
  -e RSPAMD_PASS=changeme \
  ricariel/rspamd

The generated web-UI password is printed to stdout on first start (when no worker-controller.inc exists yet). Open http://<host>:11334 to access the dashboard.


⁠Scoring & Detection

⁠Action Thresholds

The following thresholds are baked into the image (conf/local.d/actions.conf):

ActionScoreEffect
greylist4Soft-reject; legitimate servers retry
add_header6Adds X-Spam header
rewrite_subject7Prepends ***SPAM*** to subject
reject15Message is rejected outright

No single signal should reach 15 on its own (except explicit hard-blocks like country blocks or filename blocks). The design goal is 2 to 3 moderate hits combining to cross the threshold.

⁠Blocklists (RBLs)

Default-module RBLs — handled by Rspamd's built-in rbl module, scored via conf/local.d/rbl_group.conf using the module's own symbol names:

ListSymbolsNotes
Spamhaus ZEN (SBL/XBL/PBL)RCVD_IN_ZEN_BLOCKED_OPENDNS, …IP reputation
Spamhaus DBLURIBL_SBL_CSS, DBL_SPAM, …Domain reputation
MailSpikeRBL_MAILSPIKE_WORST (+7), RWL_MAILSPIKE_EXCELLENT (−2)IP reputation + whitelist
DNSWLRCVD_IN_DNSWL_HI (−2), RCVD_IN_DNSWL_MED (−1)Negative score for good senders
SpamEatingMonkeySEM_FRESH15, SEM_URIBLDomain freshness + reputation

Custom RBLs — defined in conf/local.d/rbl.conf, scored in conf/local.d/rbl_group.conf:

ListSymbolScoreNotes
InterServer IPRBL_INTERSERVER+4IP blocklist
InterServer SARBLSA_INTERSERVER+2Broader SA-level block
InterServer GoodRBLGOOD_INTERSERVER−0.5IP whitelist
InterServer URIINTERSERVER_RULE_URIBL_RBLINT+4Domain/URI blocklist
URLhaus (active)URLHAUS_URIBL_ACTIVE+7abuse.ch live malware URLs
URLhaus (offline)URLHAUS_URIBL_OFFLINE+2Recently removed entries
MailBaby DQS EmailMAILBABY_DQS_EMAIL+6E-mail address hash RBL

Optional: mount /data/local.d/custom/dqs-rbl.conf to enable the paid Spamhaus DQS feed.

⁠Active Detection Modules

Beyond RBLs, the image enables and configures several additional Rspamd modules:

ModuleConfig filePurpose
MX Checkmx_check.confVerifies that the sender domain has a working MX record. Domains with no MX are greylisted (greylist_invalid = true).
URL Redirectorurl_redirector.confFollows redirect chains (bit.ly, tracking URLs, etc.) before checking against URI blocklists. redirectors_only = false means any redirect is followed, not just known shorteners.
Phishingphishing.confPhishTank (via rspamd.com proxy) + OpenPhish public feed for URL reputation.
Known Sendersknown_senders.confTracks domains with large legitimate sender populations (e.g. Gmail, Outlook) to reduce false positives.
HTTP Headershttp_headers.confScores based on suspicious or missing HTTP-related headers.
Repliesreplies.confMarks replies to outbound mail with action = "no action" — your own replies are never rejected.
Greylistinggreylist.confMajor mail providers (Gmail, Outlook, GMX, Yahoo, Mailchimp, Sendgrid, etc.) are exempt from greylisting via greylist-whitelist-domains.inc since they do not always retry from the same IP.

Notable composite rules (composites.conf):

SymbolExpressionScorePurpose
SUSPICIOUS_DIRECT_DELIVERYONCE_RECEIVED_STRICT & MISSING_MID & !WHITELISTED_FWD_HOST+4.0Single-hop delivery with no Message-ID — typical spam MO
RELAY_DENIEDNON_LOCAL_RCPT & NON_LOCAL_IP+20.0Open relay attempt
FREEMAIL_POLICY_FAILUREFREEMAIL_FROM & !DMARC_POLICY_ALLOW+16.0Freemail sender with broken DMARC policy

⁠Environment Variables

All variables are optional unless marked required. The entrypoint re-generates affected config files from scratch on every container start, so every restart is fully idempotent.

⁠Core
VariableDefaultDescription
REDIS—Redis connection string, e.g. redis:6379. Enables history, greylist, ratelimit, DMARC stats, neural network, and more. Strongly recommended.
RSPAMD_PASSrandomPassword for the web UI / controller socket. A random password is generated and logged on first start if omitted. Accepts either a plain-text string or a pre-hashed value (starting with $).
SECURE_IP127.0.0.1IP that is allowed to call the controller without a password (e.g. a trusted proxy).
DNS—Hostname of a custom DNS resolver. It is resolved and written to local_dns.inc as the primary nameserver, with a public resolver as fallback. The entrypoint then blocks until the resolver answers a test query.
WAITFOR—Space-separated list of tcp://host:port targets to wait for before startup (uses dockerize). E.g. tcp://redis:6379 tcp://clamav:3310.

CONTROLIP, DNSSEC and NOGREY are printed by the entrypoint at startup but are not wired to any configuration. Setting them has no effect. Disable greylisting through a mounted /data/local.d/greylist.conf instead.

⁠External Services

Each service runs as a separate sidecar container. Set the variable to the container's hostname (the port is fixed per service).

VariablePortServiceDescription
CLAMAV3310ClamAV⁠Virus scanning with custom pattern matching. Configured with patterns for common malware families, phishing, PUA, and macro-based threats.
VIRUSTOTAL—VirusTotal⁠Set to your API key. Submits attachments to VirusTotal. Triggers when ≥ 3 engines flag a file, rejects when ≥ 7.
OLEFY10050Olefy⁠Python sidecar running oletools. Scans Office documents for macros, IOCs, obfuscated VBA, and malware.
DCCIFD10045DCC⁠Distributed Checksum Clearinghouse — bulk-mail detection via hash comparison.
RAZORFY11342Razorfy⁠Sidecar exposing Razor2, a collaborative spam-digest network.
PYZOR24441Pyzor⁠Sidecar running Pyzor, another collaborative spam-digest service (complements Razor).
GOOGLE_API_KEY—Google Safe BrowsingSet to your API key to enable URL reputation checks against Google Safe Browsing.
BAZAAR—abuse.ch MalwareBazaar⁠Set to any non-empty value. Downloads the full MD5 hash list from MalwareBazaar every 12 h and uses it for fuzzy attachment matching.
⁠Dynamic Rule Feeds

All feeds are handled by a single background process, update_daemon.sh, started by the entrypoint when at least one feed is enabled. It runs every enabled feed once at startup and then every 12 hours.

Each feed compares the remote ETag against the one stored from the last successful download and skips the transfer when nothing changed, so the interval costs a HEAD request per feed rather than a full download.

VariableDescription
HEINLEINEnables Heinlein Support SA rules⁠ — a curated SpamAssassin rule set loaded into Rspamd's SA compatibility layer. Also starts an auto-update daemon (every 12 h).
KAMEnables KAM.cf⁠ — Kevin A. McGrail's community SpamAssassin rules. Updated every 12 h.
SCHAALEnables schaal-it SA rules⁠ — German-language rule set. Updated every 12 h.
BAZAARSee External Services⁠ above — also activates SpamAssassin base rules when combined with HEINLEIN.

Note: HEINLEIN and BAZAAR both require the SpamAssassin base rule set, which is downloaded once from the Apache mirrors at container start. This adds ~30 s to the initial startup time.

⁠DMARC Aggregate Reporting

When DMARC_DOMAIN is set, Rspamd collects DMARC statistics (requires REDIS) and sends daily aggregate reports to domain owners whose mail you process.

VariableDefaultDescription
DMARC_DOMAIN—Required to enable reporting. The domain that appears as the report sender (your mail domain).
DMARC_ORG$DMARC_DOMAINOrganization name that appears in the report XML.
DMARC_REPORT_EMAILdmarc-report@$DMARC_DOMAINEnvelope-from / sender address of the report emails.
DMARC_SMTP127.0.0.1SMTP relay to use for sending reports. Typically points to your local Postfix.
DMARC_SMTP_PORT25SMTP port of the relay.

Reports are sent once per day (send_interval = 1d) with up to 1000 entries per report. The dmarc.conf is regenerated from scratch on every container start, so changing these variables takes effect on the next restart.


⁠Custom Configuration (/data)

Mount a directory to /data to inject or override any configuration file without rebuilding the image. The entrypoint symlinks files into the correct Rspamd config directories at startup.

/data/
├── local.d/          → /etc/rspamd/local.d/   (merged with built-in config)
│   ├── arc.conf      # override ARC signing key/selector
│   ├── dkim/         # DKIM private keys (see DKIM Signing)
│   └── maps.d/       # writable map files (greylist, bayes, etc.)
├── override.d/       → /etc/rspamd/override.d/ (replaces built-in config)
└── plugins.d/        → /etc/rspamd/plugins.d/

Files in /data/local.d/ that already exist in the built-in config are replaced (the original is removed and a symlink is created). A warning is printed to stdout for each replaced file.

Special handling:

  • /data/local.d/rspamd.conf.local → linked as /etc/rspamd/rspamd.conf.local
  • /data/local.d/dkim/ → linked as /etc/rspamd/local.d/dkim/
  • /data/local.d/maps.d/ → replaces the built-in maps.d/ directory

⁠DKIM Signing

Place your private key(s) in /data/local.d/dkim/ and create a /data/local.d/dkim_signing.conf:

# /data/local.d/dkim_signing.conf
domain {
  example.com {
    path = "/etc/rspamd/local.d/dkim/example.com.key";
    selector = "2024010101";
  }
}

The key file must be readable by the _rspamd user inside the container.


⁠ARC Signing & Verification

Verification is enabled in the base image by default — Rspamd validates incoming ARC chains and can trust forwarded mail (e.g. from mailing lists) even when SPF/DKIM fail for the forwarded copy.

SymbolScoreMeaning
ARC_ALLOW−1.0Valid, trusted ARC chain
ARC_INVALID+0.5Chain present but broken
ARC_REJECT+1.5Chain explicitly rejected by a prior hop
ARC_NA0.0No ARC headers (most direct mail)

Signing is disabled in the base image (no keys present). To enable it, mount an arc.conf via /data/local.d/arc.conf:

# /data/local.d/arc.conf
enabled = true;
sign_inbound = true;
allow_envfrom_empty = true;
allow_hdrfrom_mismatch = true;
allow_username_mismatch = true;
path = "/etc/rspamd/local.d/$selector.key";
selector = "20250101001";
try_fallback = true;
use_redis = false;

The key file referenced by path must also be mounted into the container.


⁠Fuzzy Hashing

The fuzzy storage combines two sources:

  • Public (fuzzy.rspamd.com:11335) — Rspamd's community hash database
  • Local (127.0.0.1:11335) — your own private fuzzy storage

Three local flags are pre-configured:

FlagSymbolMax ScorePurpose
11LOCAL_FUZZY_DENIED20.0Confirmed spam/malware — learned via spamtrap
12LOCAL_FUZZY_PROB10.0Probable spam
13LOCAL_FUZZY_WHITE2.0Whitelisted hashes

The spamtrap (spamtrap.conf) automatically learns incoming mail to addresses listed in /var/lib/rspamd/spamtrap.map into flag 11.


⁠Multimap Rules

The image ships a large set of multimap rules covering German- and English-language spam categories. Rules are split by language and topic:

CategoryFiles
Body contentmultimap.body.{de,en}.{conf,...}
Sender addressmultimap.sender.{de,en}.{conf,...}
Subject linemultimap.subject.{de,en}.{conf,...}
Headersmultimap.header.conf
Whitelistsmultimap.whitelist.*.conf
Phishing URLsmultimap.base.body.href.phishingdb.conf

Maps are stored under conf/local.d/maps.d/. To add your own entries, mount a writable maps.d/ directory via /data/local.d/maps.d/.

The rule set in the image comes from martinschaible/rspamd-rules⁠, downloaded during the build. Do not edit the _multimap_*.conf files in this repository to add your own rules — a rebuild replaces them. Put local additions into mm_fabrice.conf, which multimap.conf includes and the build leaves alone.


⁠Docker Compose Example

services:
  rspamd:
    image: ricariel/rspamd:latest
    restart: unless-stopped
    ports:
      - "11332:11332"   # milter
      - "11333:11333"   # scanner
      - "11334:11334"   # web UI
    environment:
      REDIS: redis:6379
      RSPAMD_PASS: "changeme"
      CLAMAV: clamav
      OLEFY: olefy
      RAZORFY: razorfy
      PYZOR: pyzor
      BAZAAR: "1"
      HEINLEIN: "1"
      KAM: "1"
      DMARC_DOMAIN: "example.com"
      DMARC_SMTP: postfix
      WAITFOR: "tcp://redis:6379 tcp://clamav:3310"
    volumes:
      - /data/rspamd:/data    # custom config + DKIM keys

  redis:
    image: redis:7-alpine
    restart: unless-stopped
    volumes:
      - redis-data:/data

  clamav:
    image: clamav/clamav:stable
    restart: unless-stopped

  olefy:
    image: ghcr.io/heinleincloud/olefy:latest
    restart: unless-stopped

  razorfy:
    image: ghcr.io/heinleincloud/razorfy:latest
    restart: unless-stopped

  pyzor:
    image: ghcr.io/heinleincloud/pyzor:latest   # community image
    restart: unless-stopped

volumes:
  redis-data:
⁠Minimal setup (no external services)
services:
  rspamd:
    image: ricariel/rspamd:latest
    restart: unless-stopped
    ports:
      - "11333:11333"
      - "11334:11334"
    environment:
      REDIS: redis:6379
    volumes:
      - /data/rspamd:/data

  redis:
    image: redis:7-alpine
    restart: unless-stopped

⁠Building from Source

git clone https://git.zyria.de/pyrox/rspamd-docker
cd rspamd-docker
docker build -t rspamd-local .
⁠Image contents
ComponentSource
Base imageOfficial docker.io/rspamd/rspamd, pinned to an exact version
Extra packagesrazor, ldnsutils, bind9-dnsutils, redis-tools, wget, unzip, procps
Multimap rulesFetched at build time from martinschaible/rspamd-rules⁠

The Rspamd version is pinned in the FROM line and raised by Renovate, so a rebuild does not silently change the Rspamd version.

The build overlays the upstream multimap rules on top of the bundled snapshot. If the download fails — an air-gapped build, or --network=none — the build still succeeds and the bundled snapshot is used. The log line says which of the two happened.


⁠Docker Hub

docker pull ricariel/rspamd

https://hub.docker.com/r/ricariel/rspamd⁠

Tag summary

Content type

Image

Digest

sha256:df7f6959c…

Size

129.1 MB

Last updated

about 8 hours ago

docker pull ricariel/rspamd