The Perfect SpamSnake - Ubuntu Jeos 9.10 - Page 2

4. Caching Dnsmasq

apt-get install dnsmasq

Edit /etc/dnsmasq.conf and make Dnsmasq listen on localhost:


Edit /etc/resolv.conf and append the following to the top of the list:



5. Install Apache2 and Mysql

apt-get install apache2 php5-cli libapache2-mod-php5 mysql-client mysql-server libdbd-mysql-perl php5-gd php5-mysql


Install MySql

You will be asked to provide a password for the MySQL root user - this password is valid for the user root@localhost as well as [email protected], so we don't have to specify a MySQL root password manually later on:

New password for the MySQL "root" user: <-- yourrootsqlpassword
Repeat password for the MySQL "root" user: <-- yourrootsqlpassword


Install Apache2

apt-get install apache2 apache2-doc apache2-mpm-prefork apache2-utils apache2-suexec

Next we install PHP5 as an Apache module:

aptitude install libapache2-mod-php5 php5 php5-common php5-curl php5-dev php5-gd php5-idn php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-mhash php5-ming php5-mysql php5-pspell php5-recode php5-snmp php5-sqlite php5-tidy php5-xmlrpc php5-xsl

Next we edit /etc/apache2/mods-available/dir.conf and change the DirectoryIndex line:

<IfModule mod_dir.c>
          #DirectoryIndex index.html index.cgi index.php index.xhtml index.htm
          DirectoryIndex index.html index.htm index.shtml index.cgi index.php index.php3 index.xhtml

Now we have to enable some Apache modules (rewrite, suexec, include):

a2enmod rewrite
a2enmod suexec
a2enmod include

Restart Apache:

/etc/init.d/apache2 restart


Install Postfix:

Install the packages:

apt-get install postfix postfix-mysql postfix-doc procmail



You will be asked two questions. Answer as follows:

General type of mail configuration: --> Internet Site
System mail name: -->

Stop Postfix:

postfix stop

We’ll want to edit Postfix with the below:

We need to add two items below the pickup service type. The pickup service "picks up" local mail (local meaning "on this machine") and delivers it. This is a way to bypass content filtering for mail generated by this machine.

It should look like this when you are done:

pickup    fifo  n       -       -       60      1       pickup
         -o content_filter=
         -o receive_override_options=no_header_body_checks

Note: For this step, make sure to replace [email protected], and with real values that matches your setup.


postconf -e "alias_maps = hash:/etc/aliases"
postconf -e "myorigin ="
postconf -e "myhostname ="
postconf -e "mynetworks =,”
postconf -e "message_size_limit = 10485760"
postconf -e "local_transport = error:No local mail delivery"
postconf -e "mydestination = "
postconf -e "local_recipient_maps = "
postconf -e "virtual_alias_maps = hash:/etc/postfix/virtual"

Create /etc/postfix/virtual and add the following:

postmaster [email protected]
abuse [email protected]
root [email protected]


postmap /etc/postfix/virtual
postconf -e "relay_recipient_maps = hash:/etc/postfix/relay_recipients"

Create /etc/postfix/relay_recipients and add the following: OK OK


postmap /etc/postfix/relay_recipients
postconf -e "transport_maps = hash:/etc/postfix/transport"

Create /etc/postfix/transport and add the following: smtp:[192.168.0.x] smtp:[192.168.0.x]


postmap /etc/postfix/transport
postconf -e "relay_domains = hash:/etc/postfix/relay_domains"

Create /etc/postfix/relay_domains and add the following: OK OK


postmap /etc/postfix/relay_domains
postconf -e "smtpd_helo_required = yes"
postconf -e "smtpd_sender_restrictions = reject_non_fqdn_sender, reject_unknown_sender_domain, permit"
postconf -e "smtpd_recipient_restrictions = reject_non_fqdn_recipient, permit_mynetworks, reject_unauth_destination, reject_unauth_pipelining, reject_rbl_client, reject_rbl_client, permit"
postconf -e "smtpd_data_restrictions = reject_unauth_pipelining"

Final look at the Postfix install:

less /etc/postfix/

Check the contents of the file for errors and repair if needed. Fire up Postfix:

postfix start

Check that Postfix responds:

telnet 25

You should see:

220 [yourFQDNhere] ESMTP Postfix (Ubuntu)


6. Install Razor, Pyzor, DCC and Clamav

apt-get install razor pyzor clamav-daemon


DCC Configuration

Install DCC from .deb source:

cd /tmp
wget && dpkg -i dcc-common_1.3.113-0ubuntu1~ppa1~karmic1_i386.deb
wget && dpkg -i dcc-server_1.3.113-0ubuntu1~ppa1~karmic1_i386.deb
wget && dpkg -i dcc-client_1.3.113-0ubuntu1~ppa1~karmic1_i386.deb

Test our installation with:

cdcc info

You should get 'requests ok' from the servers. Install dependencies:

aptitude install libconvert-tnef-perl libdbd-sqlite3-perl libfilesys-df-perl libmailtools-perl libmime-tools-perl libmime-perl libnet-cidr-perl libsys-syslog-perl libio-stringy-perl libfile-temp-perl libole-storage-lite-perl libarchive-zip-perl libsys-hostname-long-perl libnet-cidr-lite-perl libhtml-parser-perl libdb-file-lock-perl libnet-dns-perl libncurses5-dev libdigest-hmac-perl libdigest-sha1-perl libnet-ip-perl liburi-perl libfile-spec-perl spamassassin libnet-ident-perl libmail-spf-query-perl libmail-dkim-perl dnsutils

Download and install the latest MailScanner:

tar xvfz MailScanner-install-4.78.17-1.tar.gz && cd MailScanner-install-4.78.17


Configuring Pyzor, Razor, MailScanner

Pyzor Configuration

Because pyzor doesn’t work with python2.6 very well, the workaround is to append the following to the first line of /usr/bin/pyzor to make it look like:

#!/usr/bin/python -Wignore::DeprecationWarning

Here we supply the IP address of the Pyzor server to Pyzor. This will create the server's IP address in a servers file therein. Then it will test the connection. If you are behind a firewall, open port 24441/udp in and out to your server. While you're at it also open up 6277/udp for DCC, 2703/tcp for Razor and 783/tcp for SpamAssassin:

mkdir /var/lib/MailScanner
pyzor --homedir=/var/lib/MailScanner discover
pyzor ping


Razor Configuration

Create the .razor configuration:

cd && rm /etc/razor/razor-agent.conf
mkdir /var/lib/MailScanner/.razor
razor-admin -home=/var/lib/MailScanner/.razor -create
razor-admin -home=/var/lib/MailScanner/.razor -discover
razor-admin -home=/var/lib/MailScanner/.razor -register
chown -R postfix:www-data /var/lib/MailScanner
chmod -R ug+rwx /var/lib/MailScanner

Make the following changes to /var/lib/MailScanner/.razor/razor-agent.conf:

debuglevel        = 0
razorhome 	  = /var/lib/MailScanner/.razor/


MailScanner Configuration

We need to make a directory for SpamAssassin in the spool and give postfix permissions to it, if you run sa-learn --force as root, bayes databese that is stored in these directories will change to root:root and spamassassin will error looking at the db. Just keep an eye on the mail.log and you'll remember to change the permissions back. Also disable the MailScanner default configs:

mkdir /var/spool/MailScanner/spamassassin

Backup your MailScanner.conf file:

cp /opt/MailScanner/etc/MailScanner.conf /opt/MailScanner/etc/MailScanner.conf.dist
vi /opt/MailScanner/etc/MailScanner.conf

Change the following parameters in MailScanner.conf:

%org-name% = ORGNAME
%org-long-name% = ORGFULLNAME
%web-site% = ORGWEBSITE
Run As User = postfix
Run As Group = www-data
Incoming Work Group = clamav
Incoming Work Permissions = 0644
Incoming Queue Dir = /var/spool/postfix/hold
Outgoing Queue Dir = /var/spool/postfix/incoming
MTA = postfix
Virus Scanners = clamd
Monitors for ClamAV Updates = /var/lib/clamav/*.cld /var/lib/clamav/*.cvd
Clamd Socket = /var/run/clamav/clamd.ctl
Clamd Lock File = /var/run/clamav/
Spam Subject Text = ***SPAM***
Send Notices = no
Spam List = ZEN
Spam Actions = deliver store header “X-Spam-Status: Yes”
High Scoring Spam Actions = store delete
Non Spam Actions = deliver store header “X-Spam-Status: No”
SpamAssassin User State Dir = /var/spool/MailScanner/spamassassin



Let's go ahead and put this in header_checks is required because it allows us to hold all incoming email in order for MailScanner to do its thing:

postconf -e "header_checks = regexp:/etc/postfix/header_checks"

Create /etc/postfix/header_checks and add the following:

/^Received:/ HOLD

Postmap it:

postmap /etc/postfix/header_checks


MailScanner Startup Script:

Save the following as /etc/init.d/mailscanner:

#! /bin/sh
# Provides:          MailScanner daemon
# Required-Start:    $local_fs $remote_fs
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Controls mailscanner instances
# Description:       MailScanner is a queue-based spam/virus filter
# Author: Simon Walter <[email protected]>
# PATH should only include /usr/* if it runs after the script
DESC="mail spam/virus scanner"
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$PNAME ] && . /etc/default/$PNAME
# Load the VERBOSE setting and other rcS variables
. /lib/init/
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
# sanity check for permissions
    echo >&2 "$0: $1"
    exit 1
    if [ ! -d $1 ]; then
        mkdir -p "$1" || \
            fail "directory $1: does not exist and cannot be created"
    actual="$(stat -c %U $1)"
    if [ "$actual" != "$2" ]; then
        chown -R "$2" "$1" || \
            fail "directory $1: wrong owner (expected $2 but is $actual)"
    actual="$(stat -c %G $1)"
    if [ "$actual" != "$3" ]; then
        chgrp -R "$3" "$1" || \
            fail "directory $1: wrong group (expected $3 but is $actual)"
user=$(echo $(awk -F= '/^Run As User/ {print $2; exit}' $CONFFILE))
group=$(echo $(awk -F= '/^Run As Group/ {print $2; exit}' $CONFFILE))
check_dir /var/spool/MailScanner       ${user:-postfix} ${group:-www-data}
check_dir /var/lib/MailScanner         ${user:-postfix} ${group:-www-data}
check_dir /var/run/MailScanner         ${user:-postfix} ${group:-www-data}
check_dir /var/lock/subsys	${user:-root}	${group:-root} #Required to Create Folder
check_dir /var/lock/subsys/MailScanner ${user:-postfix} ${group:-www-data}
# Function that starts the daemon/service
        # Return
        #   0 if daemon has been started
        #   1 if daemon was already running
        #   2 if daemon could not be started
        start-stop-daemon --start --quiet --startas $STARTAS --name $NAME --test > /dev/null \
                || return 1
        start-stop-daemon --start --quiet --nicelevel $run_nice --chuid postfix:www-data --exec $DAEMON --name $NAME -- $DAEMON_ARGS \
                || return 2
        # Add code here, if necessary, that waits for the process to be ready
        # to handle requests from services started subsequently which depend
        # on this one.  As a last resort, sleep for some time.
  # Set lockfile to inform cronjobs about the running daemon
        if [ $RETVAL -eq 0 ]; then
            touch /var/lock/subsys/mailscanner
            rm -f $stopped_lockfile
if [ $RETVAL -eq 0 ]; then
echo "MailScanner Started"
# Function that stops the daemon/service
        # Return
        #   0 if daemon has been stopped
        #   1 if daemon was already stopped
        #   2 if daemon could not be stopped
        #   other if a failure occurred
        start-stop-daemon --stop --retry=TERM/30 --name $NAME
        [ "$RETVAL" = 2 ] && return 2
  # Remove lockfile for cronjobs
        if [ $RETVAL -eq 0 ]; then
            rm -f /var/lock/subsys/mailscanner
            touch $stopped_lockfile
if [ $RETVAL -eq 0 ]; then
echo "MailScanner Stopped"
# Function that sends a SIGHUP to the daemon/service
do_reload() {
        start-stop-daemon --stop --signal 1 --quiet --name $NAME
        return 0
case "$1" in
        [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
        case "$?" in
                0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
                2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
        # If the "reload" option is implemented then remove the
        # 'force-reload' alias
        log_daemon_msg "Restarting $DESC" "$NAME"
        case "$?" in
                case "$?" in
                        0) log_end_msg 0 ;;
                        1) log_end_msg 1 ;; # Old process is still running
                        *) log_end_msg 1 ;; # Failed to start
                # Failed to stop
                log_end_msg 1
        echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
        exit 3
exit 0

Create Symlinks for mailscanner script to work:

chmod 755 /etc/init.d/mailscanner
ln -s ../init.d/mailscanner /etc/rc0.d/K20mailscanner
ln -s ../init.d/mailscanner /etc/rc1.d/K20mailscanner
ln -s ../init.d/mailscanner /etc/rc2.d/S20mailscanner
ln -s ../init.d/mailscanner /etc/rc3.d/S20mailscanner
ln -s ../init.d/mailscanner /etc/rc4.d/S20mailscanner
ln -s ../init.d/mailscanner /etc/rc5.d/S20mailscanner
ln -s ../init.d/mailscanner /etc/rc6.d/K20mailscanner

Start the system:

/etc/init.d/mailscanner start
/etc/init.d/postfix start

Check your logs for errors:

tail -f /var/log/mail.log

Share this page:

2 Comment(s)

Add comment


From: iser0073 at: 2010-07-26 12:40:04

Thanx for the coolest anti spam solutions I have found!! It is really appreciated.

In the line:

postconf -e "mynetworks =,”

 the ” at the end of this line translates to a . when copying and pasting from this guide, would be cool if you could simply replace it with a "

 Kind Regards,

From: devnull1369 at: 2010-08-20 20:54:06

DCC has moved.