Server Fault is a question and answer site for system and network administrators. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a VPS which is originally destined to be a webserver but some minimal mail capabilities are needed to be deployed as well, including sending and receiving as standalone server.

The current setup is the following:

  • Postfix reveices the mail, the users are in virtual tables, stored in MySQL
  • on connection all servers are tested with policyd-weight service against some DNSBLs
  • all mail is runs through SpamAssassin spamd with the help of spamc client
  • the mail is then delivered with Dovecot 2' LDA (local delivery agent), virtual users as well

As you saw...

  • there's no virus scanner running, and that's for a reason: clamav eats all the memory possible and also, virus mails are all filtered out with this setup (I've tested the same with ClamAV enabled for 1,5 years, no virus mail ever got even to ClamAV)
  • I don't use amavisd and I really don't want to. You only need that monster if you have plenty of memory and lots of simultaneous scanners. It's also a nightmare to fine tune by hand.
  • I run policyd-weight instead of policyd and native DNSBLs in postfix. I don't like to send someone away because a single service listed them.

Important statement: everything works fine. I receive very small amount of spam, nearly never get a false positive and most of the bad mail is stopped by policyd-weight. The only "problem" that I feel the services at total uses a bit much memory alltogether.

I've already cut the modules of spamassassin (see below), but I'd really like to hear some advices how to cut the memory footprint as low as possible, mostly: what plugins SpamAssassin really needs and what are more or less useless, regarding to my current postfix & policyd-weight setup?

SpamAssassin rules are also compiled with sa-compile (sa-update runs once a week from cron, compile runs right after that)

These are some of the current configurations that may matter, please tell me if you need anything more.

postfix/ (parts only)

dovecot   unix  -       n       n        -      -       pipe
  flags=DRhu user=vmail:vmail argv=/usr/bin/spamc -e /usr/lib/dovecot/deliver -d ${recipient} -f {sender}

postfix/ (parts only)

smtpd_helo_required = yes
smtpd_helo_restrictions = permit_mynetworks,

smtpd_recipient_restrictions =  permit_mynetworks,
        check_policy_service inet:,

policyd-weight.conf (parts only)

$REJECTMSG = "550 Mail appeared to be SPAM or forged. Ask your Mail/DNS-Administrator to correct HELO and DNS MX settings or to get removed from DNSBLs";

$DEFER_ACTION = '450';
$DNSERRMSG = '450 No DNS entries for your MTA, HELO and Domain. Contact YOUR administrator';

# 1: ON, 0: OFF (default)
# If ON request that ALL clients are only checked against RBLs
$dnsbl_checks_only = 0;

# 1: ON (default), 0: OFF
# When set to ON it logs only RBLs which affect scoring (positive or negative)

## DNSBL settings
@dnsbl_score = (
        # host,                 hit,    miss,   log name
        '',       3,      -1,     '',
        '',      3,      -1,     '',
        '',      3,      -1,     '',
        '',       3,      -1,     '',
        '',     3,      -1,     '',
        '',     3,      -1,     '',
        '',      3,      -1,     '',
        '',        3,      -1,     '',

# If Client IP is listed in MORE DNSBLS than this var, it gets REJECTed immediately

# alternatively, if the score of DNSBLs is ABOVE this level, reject immediately

$MAXDNSBLMSG = '550 Az levelezoszerveruk IP cime tul sok spamlistan talahato, kerjuk ellenorizze! / Your MTA is listed in too many DNSBLs; please check.';

## RHSBL settings
@rhsbl_score = (
        '',              4,      0,      '',
        '',               4,      0,      '',
        '',         4,      0,      '',
#       '',  0.1,    0,      '',
#       '',       0.1,    0,      ''

# skip a RBL if this RBL had this many continuous errors

# skip a RBL for that many times

## cache stuff
# must be a directory (add trailing slash)
$LOCKPATH = '/var/run/policyd-weight/';

# socket path for the cache daemon.
$SPATH = $LOCKPATH.'/polw.sock';

# how many seconds the cache may be idle before starting maintenance routines
#NOTE: standard maintenance jobs happen regardless of this setting.

# after this number of requests do following maintenance jobs: checking for config changes

# negative (i.e. SPAM) result cache settings ##################################

# set to 0 to disable caching for spam results. To this level the cache will be cleaned.
$CACHESIZE = 2000;

# at this number of entries cleanup takes place

$CACHEREJECTMSG  = '550 temporarily blocked because of previous errors';

# after NTTL retries the cache entry is deleted
$NTTL = 1;

# client MUST NOT retry within this seconds in order to decrease TTL counter
$NTIME = 30;

# positve (i.,e. HAM) result cache settings ###################################

# set to 0 to disable caching of HAM. To this number of entries the cache will be cleaned

# at this number of entries cleanup takes place

$POSCACHEMSG = 'using cached result';

#after PTTL requests the HAM entry must succeed one time the RBL checks again
$PTTL = 60;

# after $PTIME in HAM Cache the client must pass one time the RBL checks again.
#Values must be nonfractal. Accepted time-units: s, m, h, d
$PTIME = '3h';

# The client must pass this time the RBL checks in order to be listed as hard-HAM
# After this time the client will pass immediately for PTTL within PTIME
$TEMP_PTIME = '1d';

## DNS settings

# Retries for ONE DNS-Lookup

# Retry-interval for ONE DNS-Lookup

# max error count for unresponded queries in a complete policy query

$MAXDNSERRMSG = 'passed - too many local DNS-errors';

# persistent udp connection for DNS queries.
#broken in Net::DNS version 0.51. Works with Net::DNS 0.53; DEFAULT: off
$PUDP= 0;

# Force the usage of Net::DNS for RBL lookups.
# Normally policyd-weight tries to use a faster RBL lookup routine instead of Net::DNS
$USE_NET_DNS  = 0;

# A list of space separated NS IPs
# This overrides resolv.conf settings
# Example: $NS = '';
# DEFAULT: empty
$NS  = '';

# timeout for receiving from cache instance

# If set to 1 policyd-weight closes connections to smtpd clients in order to avoid too many
#established connections to one policyd-weight child

# scores for checks, WARNING: they may manipulate eachother
# or be factors for other scores.
#  HIT score, MISS Score
@client_ip_eq_helo_score = (1.5, -1.25 );
@helo_score  = (1.5, -2 );
@helo_score  = (0, -2 );
@helo_from_mx_eq_ip_score= (1.5, -3.1  );
@helo_numeric_score= (2.5,  0 );
@from_match_regex_verified_helo= (1,-2 );
@from_match_regex_unverified_helo = (1.6, -1.5  );
@from_match_regex_failed_helo  = (2.5,  0 );
@helo_seems_dialup = (1.5,  0 );
@failed_helo_seems_dialup= (2, 0 );
@helo_ip_in_client_subnet= (0,-1.2  );
@helo_ip_in_cl16_subnet  = (0,-0.41 );
#@client_seems_dialup_score  = (3.75, 0 );
@client_seems_dialup_score  = (0, 0 );
@from_multiparted  = (1.09, 0 );
@from_anon= (1.17, 0 );
@bogus_mx_score = (2.1,  0 );
@random_sender_score  = (0.25, 0 );
@rhsbl_penalty_score  = (3.1,  0 );
@enforce_dyndns_score = (3, 0 );

spamassassin/init.pre (I've put the .pre files together)

loadplugin Mail::SpamAssassin::Plugin::Hashcash
loadplugin Mail::SpamAssassin::Plugin::SPF
loadplugin Mail::SpamAssassin::Plugin::Pyzor
loadplugin Mail::SpamAssassin::Plugin::Razor2
loadplugin Mail::SpamAssassin::Plugin::AutoLearnThreshold
loadplugin Mail::SpamAssassin::Plugin::MIMEHeader
loadplugin Mail::SpamAssassin::Plugin::ReplaceTags
loadplugin Mail::SpamAssassin::Plugin::Check
loadplugin Mail::SpamAssassin::Plugin::HTTPSMismatch
loadplugin Mail::SpamAssassin::Plugin::URIDetail    
loadplugin Mail::SpamAssassin::Plugin::Bayes
loadplugin Mail::SpamAssassin::Plugin::BodyEval
loadplugin Mail::SpamAssassin::Plugin::DNSEval
loadplugin Mail::SpamAssassin::Plugin::HTMLEval
loadplugin Mail::SpamAssassin::Plugin::HeaderEval
loadplugin Mail::SpamAssassin::Plugin::MIMEEval
loadplugin Mail::SpamAssassin::Plugin::RelayEval
loadplugin Mail::SpamAssassin::Plugin::URIEval
loadplugin Mail::SpamAssassin::Plugin::WLBLEval
loadplugin Mail::SpamAssassin::Plugin::VBounce
loadplugin Mail::SpamAssassin::Plugin::Rule2XSBody

spamassassin/ (parts)

use_bayes                       1
bayes_auto_learn                1
bayes_store_module              Mail::SpamAssassin::BayesStore::MySQL
bayes_sql_dsn                   DBI:mysql:db:
bayes_sql_username              user
bayes_sql_password              pass
bayes_ignore_header             X-Bogosity
bayes_ignore_header             X-Spam-Flag
bayes_ignore_header             X-Spam-Status

### User settings
user_scores_dsn                 DBI:mysql:db:
user_scores_sql_password        user
user_scores_sql_username        pass
user_scores_sql_custom_query    SELECT preference, value FROM _TABLE_ WHERE username = _USERNAME_ OR username = '$GLOBAL' OR username = CONCAT('%',_DOMAIN_) ORDER BY username ASC

# for better speed
score DNS_FROM_AHBL_RHSBL       0
score DNS_FROM_RFC_DSN          0
score __DNS_FROM_RFC_POST       0
score __DNS_FROM_RFC_ABUSE      0
score __DNS_FROM_RFC_WHOIS      0


As adaptr advised I remove policyd-weight and configured postfix postscreen, this resulted approximately -15-20 MB from RAM usage and a lot faster work. I'm not sure it's working at full capacity but it seems promising.

share|improve this question
Upgrade to postfix 2.8+; postscreen pretty much obviates the need for policyd-weight: it includes full DNSBL and RHSBL white- and blacklisting, and weighted DNSBL scoring. – adaptr Mar 22 '12 at 14:17
@adaptr it seems I have postfix 2.8.5-2~build1, server is ubuntu 11.10. I did not notice this new function in postfix but it seems promising - the only problem that I'm unable to find any example configurations for it and the man page is kind of a puritan one. Can you point or post an example please? – petermolnar Mar 22 '12 at 14:33
OK, I've got it more or less configured, except I'm not sure it's watching for smtps connections as well. If anyone can answer for this, the detailed questions is here:… – petermolnar Mar 22 '12 at 15:41
The official postscreen documentation should suffice to start with; of course, you need to understand how to configure postfix in general to make use of it. – adaptr Mar 22 '12 at 15:54

I would recommend you to upgrade to postfix 2.8+ and deploy postscreen; this is specifically designed as a zombie/DNSBL triage server and handles multiple blacklists at high speed.

It also offers fully-weighted black/whitelist scoring, explicit whitelisting, and more.

With respect to your second question, I suggest you check out spamass-milter; an in-line milter is much more efficient than an external process.

share|improve this answer
I don't want to sound hasty but after a few hours running with postscreen on and policyd-weight off RAM usage seems noticably lower. I'm really graceful for the tip but I still would like to hear tips on SpamAssassin as well. – petermolnar Mar 22 '12 at 20:55

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.