Dovecot LMTP ile Postfix Teslimatını Hızlandırmak ve Sieve'i Teslim Anında Çalıştırmak
Postfix'in klasik dovecot-lda teslimatı her mesaj için süreç fork eder, yüksek hacimde kuyruğu tıkar ve çok alıcılı mesajlarda alıcı-başına hata ayrımını kaybeder. LMTP kalıcı bir daemon olarak bu üç sorunu tek hamlede çözer: sıfır fork, per-RCPT SMTP durum kodları ve Pigeonhole Sieve'in native çalışması. Bu, LDA'dan LMTP'ye operasyonel geçiş rehberi — övgü yok, config ve ölçüm var.
EvilMail Team10 Temmuz 202610 dk okuma
200 alıcılı bir bültenin kuyruğa girdiği an sunucunun load average'ı 0.4'ten 6'ya tırmanıyorsa, suçlu neredeyse her zaman aynı: dovecot-lda. ps aux | grep deliver çıktısında onlarca kısa ömürlü deliver süreci görürsünüz — her biri saniyeler içinde doğup ölen, ama toplu halde CPU'yu ve disk I/O'sunu boğan süreçler. Çünkü Postfix'in klasik yerel teslimatında her mesaj sıfırdan bir başlangıçtır: fork + exec + doveconf parse + mail index aç + yaz + kapat. Mesaj başına. Kalıcı hiçbir şey yok.
LMTP (RFC 2033) bu modeli tersine çevirir. Teslimatı yapan daemon zaten çalışıyordur ve çalışmaya devam eder; Postfix mesajı bir socket üzerinden ona uzatır. Fork yok, config parse yok, index cache sıcak kalır. Üstelik LMTP, SMTP'nin türevi olduğu için her alıcı için ayrı bir yanıt kodu döndürür — 200 alıcılı mesajda biri quota-full ise sadece onu defer edip diğer 199'u teslim edebilirsiniz. Bu yazı bir "LMTP nedir" tanıtımı değil; dovecot-lda'dan LMTP'ye neden ve nasıl geçeceğinizin operasyonel rehberi.
dovecot-lda neden yavaş ve neyi kaybettiriyor
Klasik kurulumda Postfix local(8)
Dovecot LMTP + Postfix: Hızlı Teslimat ve Sieve Filtreleri | evilmail.pro — EvilMail Blog
veya
virtual(8)
teslimat ajanı,
mailbox_command
ya da bir
pipe
transport üzerinden her mesaj için yeni bir
dovecot-lda
(eski adıyla
deliver
) süreci başlatır. Bu sürecin ömrü tek bir mesaj kadardır. İçinde şunlar olur:
Fork + exec: Çekirdek yeni bir süreç yaratır, binary'yi yükler.
doveconf parse: Dovecot yapılandırması her çağrıda yeniden okunup ayrıştırılır.
Index açılışı: Kullanıcının mailbox index'i açılır, mesaj yazılır, index kapatılır. Sıcak cache diye bir şey yok — her seferinde soğuk başlangıç.
Düşük hacimde bu maliyet görünmez. Günde birkaç yüz mesaj alan kişisel bir sunucuda dovecot-lda gayet iyi çalışır; bu yazının önerisi "her yerde LMTP'ye geçin" değil. Ama eşik birkaç bin mesaj/gün seviyesini aştığında — özellikle mailing list ve çok alıcılı bültenler devreye girince — bu sabit maliyet mesaj sayısıyla çarpılır ve kuyruk tıkanır.
İkinci ve daha sinsi kayıp, alıcı-başına hata ayrımının çökmesi. Bir pipe transport tek bir exit code döndürür. Postfix bir mesajı 50 alıcıya virtual_transport üzerinden pipe ile teslim ederken içlerinden biri quota dolu olduğu için başarısız olursa, transport ya hepsini defer eder ya hepsini bounce eder. Postfix seçici retry yapamaz, çünkü hangi alıcının patladığını bilmez — elinde tek bir çıkış kodu vardır. Sonuç: 49 mutlu alıcı, 1 dolu kutu yüzünden mesajını tekrar tekrar alır ya da hiç alamaz.
Sieve tarafı da dağınıktır. dovecot-lda ile Sieve mümkündür ama zincirin dışında hissettirir; plugin her çağrıda yeniden yüklenir, global scriptler her teslimatta yeniden değerlendirilir.
LMTP farkı: kalıcı daemon, gerçek durum kodları
LMTP, SMTP'nin teslimat için sadeleştirilmiş bir türevidir. HELO yerine LHLO ile başlar ve tek kritik fark şudur: her `RCPT TO` için ayrı bir yanıt kodu döner. SMTP'de sunucu DATA sonrası tek bir yanıt verir ve kuyruklama sorumluluğu alıcıdadır; LMTP bu sorumluluğu göndericiye (yani Postfix'e) bırakır ve her alıcının kaderini ayrı ayrı raporlar.
Pratikte kazanç net:
Sıfır fork: Dovecot LMTP daemon'ı sürekli çalışır. Mesaj geldiğinde yeni süreç doğmaz, mevcut daemon işi alır. Index cache sıcak, config zaten yüklü.
Per-RCPT durum kodu: Bir alıcı geçici hatayla (452) reddedilirse Postfix onu defer edip tekrar dener, diğerlerini anında teslim eder. Kalıcı hata (552, örneğin quota) temiz bir bounce üretir. Seçici retry çalışır.
Native Sieve: Pigeonhole plugin'i LMTP zincirine bir satırla bağlanır ve teslim tam anında çalışır.
Dovecot ve Postfix aynı makinedeyse Unix socket kullanın — en hızlı, en güvenli seçenek. Mailstore ayrı bir sunucudaysa LMTP TCP port 24 üzerinden konuşulur, ama bu port asla internete açılmaz; yalnızca firewall arkası iç ağda.
Dovecot tarafı: LMTP servisini açmak
Önce protokol listesine lmtp ekleyin. Dovecot 2.3'te bu açık bir zorunluluktur; 2.4'te bazı dağıtımlar protokolleri otomatik yükler ama açıkça belirtmek her sürümde güvenlidir.
# /etc/dovecot/dovecot.conf
protocols = imap lmtp
Şimdi asıl kritik parça: LMTP socket'ini Postfix'in chroot spool'unun içine koymak. Postfix teslimat daemon'ları /var/spool/postfix/ altında chroot edilir; socket bu dizinin dışında kalırsa chroot'lu süreç ona erişemez ve teslimat başarısız olur.
# /etc/dovecot/conf.d/10-master.conf
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
# Ayrı mailstore sunucusu için (tek sunucuda gerekmez):
# inet_listener lmtp {
# port = 24
# }
}
user ve group mutlaka postfix olmalı. Yanlış sahiplik veya izinde log'da lmtp: Permission denied görürsünüz ve tüm teslimat durur. Değişikliği uygulayıp socket'i doğrulayın:
Baştaki s bunun bir socket olduğunu, rw------- izinlerin 0600, sahibinse postfix postfix olduğunu doğrular. Bu satırı görmeden Postfix tarafına geçmeyin.
Postfix tarafı: transport ve alıcı limiti
Sanal alan (virtual domain) kurulumunda teslimatı LMTP'ye yönlendiren tek ayar virtual_transport. Yol private/ ile başlar çünkü Postfix bunu kendi spool dizinine göre relative çözer:
mydestination içindeki yerel domainler için teslimat yapıyorsanız aynısını mailbox_transport ile ayarlarsınız. Sırada çoğu kişinin yanlış yaptığı ayar var: alıcı limiti.
lmtp_destination_recipient_limit, bir teslimat oturumunda kaç RCPT TO gönderileceğini belirler. Dovecot LMTP çoklu alıcıyı destekler ve LMTP'nin en büyük performans kazancı buradan gelir: tek bir oturumda, tek DATA gövdesiyle 50 alıcıya teslimat. Bu değeri 1'e çekmeyin — her alıcı için ayrı oturum açar, çoklu-alıcı avantajını tamamen öldürür ve sizi dovecot-lda performansına geri döndürür. 50 gibi bir üst sınır makuldür; çok yüksek değerler tek bir yavaş alıcının oturumu bloke etmesine yol açabilir. Ayarları doğrulayın:
Ağır Sieve scriptleriniz varsa master.cf'te LMTP transport'una -o lmtp_data_done_timeout= gibi bir zaman aşımı uzatması ekleyebilirsiniz, ama çoğu kurulum varsayılanlarla sorunsuz çalışır.
Sieve'i teslim anında çalıştırmak
LMTP'nin sessiz gücü de burada: Pigeonhole Sieve'i teslimat zincirine tek satırla bağlarsınız. Sieve artık ayrı bir çağrı değil, LMTP daemon'ının içinde teslim tam anında çalışan bir aşamadır.
dovecot-lda üzerinden gelen fallback teslimatlarda da Sieve çalışsın istiyorsanız aynı bloğu protocol lda için de eklemeyi unutmayın — aksi halde LMTP dışı yol Sieve'i atlar.
Asıl güç 90-sieve.conf'taki katmanlı yapıda. sieve_before global admin scriptlerini kullanıcı scriptinden önce çalıştırır (spam dosyalama, kurumsal kurallar); sieve_after ise catch-all için sona kalır:
Yürütme sırası kesindir ve okuyucuların en sık kafasını karıştıran şey de budur:
Bu sıranın güvenlik ağı şu: bir script derlenmezse (sözdizimi hatası vb.) o adım sessizce atlanır ve implicit keep devreye girer — mesaj INBOX'a düşer, asla kaybolmaz. Yine de global scriptlerinizi önceden derleyin ki teslimat anında derleme maliyeti ödemeyin:
.svbin binary'lerinin Dovecot'un okuyabileceği izinlere sahip olması gerekir. Bir uyarı: ManageSieve (port 4190) yalnızca kullanıcıların scriptlerini düzenlemesi içindir, teslimatla ilgisi yoktur — ikisini karıştırmayın. Quota plugin'i Sieve ile birlikte çalışıyorsa, kullanıcı sınırını aştığında LMTP 552 döndürür ve Postfix temiz bir bounce üretir.
Doğrulama ve hata ayıklama
Config'i restart etmeden önce elle bir LMTP oturumu sürmek, sorunları saniyeler içinde ortaya çıkarır. Socket'e doğrudan bağlanın:
bash
nc -U /var/spool/postfix/private/dovecot-lmtp
LHLO test
MAIL FROM:<[email protected]>
RCPT TO:<[email protected]>
DATA
Subject: lmtp test
gövde
.
Başarıda 250 2.0.0 <[email protected]> ... Saved görürsünüz. RCPT TO satırına gelen kod her şeyi söyler: 250 teslim edildi, 452 geçici defer, 552 kalıcı red (genelde quota). Bu manuel oturumda per-RCPT kodlarını canlı görmek, LMTP'nin dovecot-lda'dan neden üstün olduğunu somutlaştırır.
Uçtan uca test için swaks en pratik araç — bu kez tüm Postfix zinciri devrede:
Mailstore ayrı bir makinedeyse Unix socket yerine TCP kullanırsınız. Dovecot tarafında 10-master.conf içindeki inet_listener lmtp { port = 24 } satırını açın, Postfix tarafında transport'u değiştirin:
Tek kural, pazarlık payı yok: port 24 asla internete açılmaz. LMTP'de kimlik doğrulama yoktur; port 24'ü dışarı açmak, sunucunuzu herkesin kimlik doğrulamasız mesaj enjekte edebileceği açık bir relay'e çevirir. Yalnızca firewall arkası iç ağ, tercihen özel bir VLAN ya da VPN üzerinden.
Geçiş kontrol listesi
protocols satırına lmtp eklendi mi
LMTP socket'i Postfix spool'unun içinde ve srw-------postfix postfix izniyle mi
virtual_transport (gerekiyorsa mailbox_transport) lmtp:unix:private/dovecot-lmtp'ye çevrildi ve postfix reload yapıldı mı
lmtp_destination_recipient_limit makul (örn. 50), asla 1 değil
protocol lmtp bloğunda sieve plugin var; fallback için protocol lda da eklendi mi
Global sieve_before scriptleri sievec ile önceden derlendi mi
nc -U ile manuel oturum RCPT TO'ya 250 döndürüyor mu
swaks ile canlı test yapıldı ve mail.log'ta "sieve: msg stored" satırı görülüyor mu
Geçişin gerçekten işe yaradığını kanıtlamak için tek bir ölçüm yeterli: geçiş öncesi ve sonrası, aynı boyutta bir bülten gönderip mail.log'taki ilk RCPT ile son Saved satırı arasındaki timestamp farkını kıyaslayın. dovecot-lda'da her mesajın fork maliyetini ödeyen bir sistemde bu fark saniyelerle ölçülür; sıcak bir LMTP daemon'ında milisaniyelerle.