"Postfix'e bir spam filtresi tak" dendiğinde refleks hep aynı: amavisd-new'i kur, arkasına SpamAssassin bağla, content_filter ile mesajı kuyruktan çıkarıp tarayıcıya ver, taransın, tekrar 10025 portundan Postfix'e enjekte et. Bu mimari çalışır ama üç yerinden sızdırır. Re-injection her mesaja gecikme ve ekstra bir kuyruk döngüsü ekler. Karar tek bir eşiğe indirgenir: eşik altı temiz, üstü spam. Ve en kötüsü, o kararın neden verildiği opaktır; bir mesaj neden 5.8 puan aldı, hangi sinyal onu itti, dışarıdan göremezsin.
rspamd bu modeli tersine çevirir. Mesaj daha SMTP oturumu kapanmadan, milter içinde puanlanır. Onlarca sinyalden (DKIM, SPF, DMARC, Bayes, URL itibarı, başlık tutarlılığı) toplam bir skor üretir; kararı — geç bırak, başlık ekle, greylist, reddet — senin belirlediğin eşiklere göre verir ve her kararı canlı bir web arayüzünde sembol sembol okursun. Bu yazıda rspamd'ı amavis tarzı re-injection ile değil, rspamd_proxy'nin self-scan (milter) modunda kuracağız. 2026'da doğru mimari bu: tek worker hem milter uç noktası hem tarayıcı, oturum içinde puanlama, re-injection yok.
Ana fikri baştan söyleyelim, çünkü tüm ayarlar bunun etrafında dönüyor: rspamd'da "skor" bir çıktı değil, senin kontrol ettiğin bir kadrandır. Web arayüzü de o kadranı gerçek postayla kalibre ettiğin yerdir.
Mimari: neden milter, worker'lar ne iş yapıyor
Milter olmanın kazancı somut. Mesaj Postfix'in smtpd sürecinden çıkmadan taranır; skor reject eşiğini geçerse Postfix gönderen MTA'ya daha DATA aşamasında 550 döner. Spam senin diskine hiç yazılmaz, kuyruğa girmez, re-injection turu yaşamaz. amavis kurulumunda mesaj önce kabul edilir, sonra taranır, sonra karar verilir; rspamd'da karar oturumun içindedir.
rspamd üç worker'la çalışır ve bunları karıştırmamak kurulumun yarısıdır:
- `normal` (11333) — asıl tarama motoru. Sembolleri hesaplar, skoru üretir.
- `controller` (11334) — web arayüzü, öğrenme (learn) uç noktaları ve istatistikler. Skoru burada izler, false-positive'leri buradan eğitirsin.
- `rspamd_proxy` (11332) — milter uç noktası.
self_scanmodunda ayrı bir tarayıcıya proxy yapmak yerine tarama işini de kendisi yapar. Postfix bu porta bağlanır.
Arka planda Redis (6379) durur: Bayes istatistikleri, greylist kayıtları, ratelimit sayaçları ve fuzzy hash'ler hep orada tutulur. Redis olmadan rspamd çalışır ama öğrenmez ve hatırlamaz.
Config felsefesi tek cümle: /etc/rspamd/ altındaki base dosyalarına asla dokunma. Her ekleme /etc/rspamd/local.d/ altına gider (base ile birleşir), her ezme /etc/rspamd/override.d/ altına (base'i tamamen değiştirir). Base dosyaları paket güncellemesinde üzerine yazılır; senin local.d dosyaların kalır. En sık yapılan hata bir seçeneği override.d'ye koyup neden local.d'deki komşusunun çalışmadığına şaşırmaktır.
Kurulum: depo, paket, Redis
Distro deposundaki rspamd genelde eskidir; sembol kuralları ve DMARC modülü hızla gelişir. Güncel 3.x dalını almak için resmî depoyu kullan.
apt install -y lsb-release wget gpg
mkdir -p /etc/apt/keyrings
wget -O- https://rspamd.com/apt-stable/gpg.key | \
gpg --dearmor > /etc/apt/keyrings/rspamd.gpg
echo "deb [signed-by=/etc/apt/keyrings/rspamd.gpg] \
http://rspamd.com/apt-stable/ $(lsb_release -cs) main" \
> /etc/apt/sources.list.d/rspamd.list
apt update
apt install -y rspamd redis-server
systemctl enable --now redis-server rspamdRedis'i localhost'a bağlı tut ve bellek politikasını ayarla. Greylist ve ratelimit verisi süreli olduğundan allkeys-lru mantıklı bir seçim, ama Bayes'i kaybetmemek için kalıcılığı (AOF ya da RDB) açık bırak.
# /etc/redis/redis.conf
bind 127.0.0.1
maxmemory 512mb
maxmemory-policy allkeys-lru
appendonly yesKurulumu iki komutla doğrula: rspamc stat istatistik döndürüyorsa controller ayakta, ss -lntp | grep -E '1133[234]' üç portu da dinliyor gösteriyorsa worker'lar yerinde.
rspamd_proxy'yi milter (self-scan) modunda çalıştırmak
İşin özü burası. rspamd_proxy'yi milter yap ve self-scan aç ki ayrı bir proxy→tarayıcı hattına gerek kalmadan tek worker hem Postfix'in bağlandığı uç hem de tarama motoru olsun.
# /etc/rspamd/local.d/worker-proxy.inc
milter = yes;
timeout = 120s;
upstream "local" {
default = yes;
self_scan = yes;
}
bind_socket = "localhost:11332";worker-normal ve controller için de bind adreslerini sabitle. Controller'ı burada 0.0.0.0'a açmak en klasik güvenlik hatası — sadece localhost, dışarıya nginx üzerinden.
# /etc/rspamd/local.d/worker-normal.inc
bind_socket = "localhost:11333";
# /etc/rspamd/local.d/worker-controller.inc
bind_socket = "localhost:11334";Redis backend'ini tüm modüllere tek yerden tanıt:
# /etc/rspamd/local.d/redis.conf
servers = "127.0.0.1:6379";Reload et ve portları doğrula:
systemctl reload rspamd
ss -lntp | grep -E '1133[234]'Postfix'i milter'a bağlamak
Postfix tarafında dört satır kritik. smtpd_milters gelen postayı 11332'ye yönlendirir; non_smtpd_milters aynı milter'ı giden posta için de devreye alır — bunu atlamak, DKIM imzalamanın çalışmamasının bir numaralı sebebidir, çünkü rspamd imzayı milter aşamasında ekler.
# /etc/postfix/main.cf
smtpd_milters = inet:localhost:11332
non_smtpd_milters = $smtpd_milters
milter_protocol = 6
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
milter_default_action = acceptmilter_default_action = accept pazarlık konusu değil. rspamd çökerse ya da yanıt vermezse Postfix milter'ı atlar ve postayı akıtmaya devam eder (fail-open). Alternatifi tempfail, ki o zaman rspamd'ın her hıçkırığında meşru posta geri teper. Bir spam filtresi asla mail akışını kesen tek nokta olmamalı.
milter_mail_macros satırı, oturumdaki SASL kimliğini (auth_authen) ve istemci bilgisini rspamd'a taşır. Bu olmadan rspamd, kimliği doğrulanmış kullanıcıların giden postasını anonim trafikten ayıramaz ve ratelimit'i yanlış uygular.
postfix reloadTest için tek satırlık bir mektup gönder ve başlıklara bak; X-Spamd-Result, X-Spam-Level ve X-Rspamd-Server başlıkları belirdiyse milter zinciri kuruldu demektir.
Controller ve web arayüzü: parola, reverse proxy
Controller'ın iki parolası olur: password salt-okunur işlemler (istatistik, history görüntüleme) içindir; enable_password ise öğrenme ve karantina gibi durum değiştiren işlemler içindir. İkisini ayrı tutmak, panele bakan birinin yanlışlıkla Bayes'i eğitmesini engeller. Hash'leri rspamadm pw üretir.
rspamadm pw
# Enter password:
# $2$xic4x...uzun-hash...# /etc/rspamd/local.d/worker-controller.inc
bind_socket = "localhost:11334";
password = "$2$xic4x...hash1...";
enable_password = "$2$k9m2p...hash2...";Controller'ı doğrudan internete açma. Önüne nginx koy, TLS'i orada sonlandır, istersen ikinci katman HTTP basic auth ekle.
location /rspamd/ {
proxy_pass http://127.0.0.1:11334/;
proxy_set_header Host $host;
# auth_basic "rspamd"; auth_basic_user_file /etc/nginx/.rspamd;
}Panelde ne izlersin: Throughput grafiği (saatlik action dağılımı), History tablosu (her mesajın skoru, tetiklenen sembolleri ve verilen action'ı satır satır), Symbols sekmesi (hangi kuralın kaç puan taşıdığı) ve canlı Scan / Learn kutuları.
Skoru okumak: action eşikleri ve semboller
rspamd'ın kalbi şu denklem: skor = tetiklenen tüm sembollerin puanlarının toplamı, ve bu skor bir action zincirinden geçer. Varsayılan eşikler:
# /etc/rspamd/local.d/actions.conf
greylist = 4;
add_header = 6;
# rewrite_subject = 8; # opsiyonel
reject = 15;Skor 4'ü geçerse greylist (geçici erteleme), 6'yı geçerse X-Spam başlığı eklenir, 15'i geçerse mesaj reddedilir. Bu bir bayrak değil, kalibre edilebilir bir kadran.
Semboller iki yönde çalışır. Pozitif olanlar skoru yukarı iter: BAYES_SPAM, MISSING_MID (Message-ID yok), R_SUSPICIOUS_URL, FORGED_SENDER, DMARC_POLICY_REJECT. Negatif olanlar aşağı çeker, yani beyaz listeleme etkisi yapar: BAYES_HAM, R_DKIM_ALLOW, R_SPF_ALLOW, DMARC_POLICY_ALLOW, MAILLIST. Meşru bir kurumsal mektup çoğu zaman DKIM+SPF+DMARC üçlüsünden gelen negatif puanlarla rahatça temiz kalır; imzasız, DMARC'sız bir sahtecilik girişimi ise pozitif sembolleri toplayıp reject bandına tırmanır.
Bir mesajın neden o skoru aldığını görmek için .eml dosyasını doğrudan rspamd'a ver:
rspamc symbols < mesaj.emlÇıktı her sembolü puanıyla döker; web UI'daki History satırının komut satırı karşılığı budur. Aynı özeti mesaj başlığında da görürsün:
X-Spamd-Result: default: False [3.20 / 15.00];
BAYES_HAM(-2.10)[99.98%];
R_DKIM_ALLOW(-0.20);
R_SPF_ALLOW(-0.20);
MIME_GOOD(-0.10)Canlı izleme, Bayes eğitimi ve DKIM imzalama
Web arayüzünün asıl değeri burada ortaya çıkar. History'de gerçek postanın nasıl puanlandığını izlersin; bir false-positive gördüğünde satırı seçip Learn ham, kaçmış bir spam gördüğünde Learn spam dersin. Komut satırı karşılığı:
rspamc learn_spam spam.eml
rspamc learn_ham temiz.emlÖlçekli çalışırken tek tek eğitmek yerine kullanıcıların IMAP Junk klasörünü otomatik öğrenmeye bağlamak daha sağlıklıdır. Kritik nokta şu: Bayes sınıflandırıcısı yeterli örnek görmeden hiçbir BAYES_* sembolü basmaz. Varsayılan asgari eşik yaklaşık 200 örnektir (min_learns) ve ham ile spam örneklerini dengeli tutmak gerekir — 500 spam, 10 ham ile eğitirsen sınıflandırıcı yanlı olur. İlerlemeyi rspamc stat ile izle; learned: sayaçlarının ikisi de büyümeli.
Giden postayı imzalamak için dkim_signing modülü devreye girer. non_smtpd_milters satırının doğru olduğundan emin ol, yoksa imza hiç eklenmez.
# /etc/rspamd/local.d/dkim_signing.conf
domain {
evilmail.pro {
path = "/var/lib/rspamd/dkim/evilmail.pro.key";
selector = "mail";
}
}
allow_username_mismatch = true;Anahtarı rspamadm dkim_keygen ile üret; selector ve domain'i açıkça geç, çıktıyı _rspamd kullanıcısına oku:
mkdir -p /var/lib/rspamd/dkim
rspamadm dkim_keygen -s mail -d evilmail.pro \
-k /var/lib/rspamd/dkim/evilmail.pro.key
chown _rspamd:_rspamd /var/lib/rspamd/dkim/evilmail.pro.keyKomut, DNS'e koyacağın TXT kaydını doğrudan basar:
mail._domainkey.evilmail.pro. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCS..."DNS yayıldıktan sonra kendine bir mektup gönder; R_DKIM_ALLOW sembolünün negatif puanla göründüğünü web UI'da doğrula. O sembol görünüyorsa imza zinciri uçtan uca çalışıyor demektir.
Devreye alma kontrol listesi
Canlıya geçmeden önce şu satırların hepsini tik'le:
ss -lntp | grep -E '1133[234]'üç portu da dinliyor mu?main.cf'temilter_default_action = acceptmı? (fail-open)- Controller
localhost:11334'e bağlı mı, dışarıya yalnızca nginx üzerinden mi açık? passwordveenable_password$2$...hash'i mi, düz metin değil?non_smtpd_milterstanımlı mı? (yoksa DKIM imzalanmaz)- Redis kalıcılığı (AOF/RDB) açık mı? (Bayes'i restart'ta kaybetme)
- DKIM TXT kaydı yayıldı mı,
R_DKIM_ALLOWgörünüyor mu?
Ve tekrar tekrar kanayan klasik tuzaklar: base config'i düzenleyip local.d'nin neden çalışmadığına şaşmak; reject eşiğini erkenden 6'ya çekip birkaç meşru bültenle beraber gerçek postayı da kaybetmek; non_smtpd_milters'ı unutup imzasız giden posta yollamak; ve controller'ı 0.0.0.0'a açıp öğrenme uç noktasını internete servis etmek. rspamd'ın gücü kararın senin elinde olmasında — o eli, web arayüzünde gerçek postayı izleyip eşikleri kendi trafiğine göre çekerek kullan.


