Spam and viruses (particularly worms) are the bane of many email-user's existence. The spam clogs up your inbox, making you dread checking your email, and virally infected emails threaten to take over your computer. Well, if you're using Windows, maybe they do. Otherwise, they're just an additional nuisance...
Anyhow, spam and viruses are both major concerns where I work, and prior attempts to curtail them weren't entirely effective. Our mail server is Microsoft Exchange and most mail clients are Microsoft Outlook, but there isn't a huge budget for additions like a commercial spam and/or virus scanner, so an assortment of rules is all that was in place before I came on board. Enter the "entirely open-source, no software to purchase, just gimme a spare machine, spam and virus filtering mail proxy". I'd set this up at the last place I worked, so it was my first project at the new job.
Everything in the document is based off the combination of Matthias Saou's "Installing a mail server on Red Hat Linux 7.3" document, the Sender Policy Framework pages and the official postfix website docs for postfix 2.1. Every component was installed from rpms, though I created my own postfix 2.1 rpm (based off Red Hat's postfix 2.0.x spec files), as there were no postfix 2.1 rpms I could find anywhere when I put this together (2.1 had just been released). Anything that is incorrect in this document is probably my fault and/or lack of understanding, so let me know if you think something is awry.
While this document should apply more or less equally to any recent Red Hat offering (or derivative thereof, such as White Box or CentOS), at the time, all the Linux systems at my place of work ran Red Hat Linux 7.3, so that's what I used for the base OS for this project.
On top of what Red Hat distributed with RHL7.3, this system included (as of this writing):
The mailgraph and queuegraph portions aren't necessary for a functional system, but are nice as a quick and easy way to check on how your filter is performing. Speaking of performance, I should note that I'm running this setup on a PIII-733 system with 512MB of RAM, handling mail for 25 users (roughly 50-100 messages per minute), and haven't seen CPU utilization spikes above 20%.
With this software setup, once you have all the packages installed, 99% of the configuration work is done in /etc/postfix/main.cf, /etc/postfix/master.cf and /etc/amavisd.conf. One small edit to /etc/clamav.conf and some additional custom rule files in /etc/mail/spamassassin/ should comprise the other 1%. For reference, I'm including sanitized copies of my production config files for the big three. You can also drop these in place after editing them, if you want to go with a setup closer to mine than to the stock configuration and save yourself some time. You can get them right here:
Start out with at least a basic server installation of Red Hat Linux (7.3 in my case). After installing the OS, you'll need to download some additional components we'll need. First off, download and install apt from FreshRPMs, http://freshrpms.net/. (For RHL7.3, simply rpm -Uvh http://ftp.freshrpms.net/pub/freshrpms/redhat/7.3/apt/apt-0.5.5cnc5-fr0.rh73.2.i386.rpm). Once it is installed, edit /etc/apt/sources.list and add the following:
### Red Hat Linux 7.3 rpm http://ayo.freshrpms.net redhat/7.3/i386 os updates ### Dag RPM Repository for Red Hat Linux 7.3 rpm http://apt.sw.be redhat/7.3/en/i386 dag ### ATrpms for Red Hat Linux 7.3 rpm http://apt.physik.fu-berlin.de redhat/7.3/en/i386 at-good ### Fedora Legacy updates rpm http://download.fedoralegacy.org/apt redhat/7.3/i386 updates
Now, as root, run the command apt-get update, which will fetch the list of available packages apt can install. At this point, I'd highly recommend running apt-get dist-upgrade, which will upgrade all the packages on your system to the very latest versions (and we're only using stable repositories here that I've used regularly and consider very reliable). For quick reference, here are the commands to run:
# apt-get update # apt-get dist-upgrade (answer Y when prompted)
The dist-upgrade will take a while, depending a lot on how much you've installed and how fast your internet connection is, but when this part is done, for those running RHL7.3, I'd highly recommend installing one of the kernels provided by ATrpms. The best option for this install is probably the 2.4.20-31.7 kernel, which is based of Red Hat's own sources and spec files for RHL9, but with NPTL support removed. This was the last errata kernel Red Hat released for RHL9 before it went end-of-life also, and the RHL7.x, 8.0 and 9 kernels were all in sync before 7.x and 8 went EOL, so this ends up being exactly the kernel Red Hat would have put out if RHL7.3 weren't EOL. Anyhow, install it with apt, like so:
# apt-get install kernel#2.4.20-31.7 (or kernel-smp#2.4.20-31.7 if you have an smp machine)
The proper architecture (athlon, i686, i586, etc) is detected automatically by apt, so no, you don't have to specify your architecture on the install line. Next up, edit /etc/grub.conf to set the newly installed kernel as your default (typically, edit default=1 to default=0) and restart the system.
Once the system reboots on the new kernel, you'll install most of the additional necessary packages and all their dependencies, with the command:
# apt-get install amavisd-new clamav clamd clamav-db spamassassin
The last remaining piece of the puzzle is postfix 2.1.x, which is available from ATrpms, though because RHL7.3 ships with postfix 1.x, to avoid auto-upgrading postfix for ATrpms users that have reason to stay with 1.x, it is in a lower stability class, at-testing, though I assure you its quite stable. To simplify dependency resolution, edit the ATrpms entry in /etc/apt/sources.list, so that it reads like so:
### ATrpms for Red Hat Linux 7.3 #rpm http://apt.physik.fu-berlin.de redhat/7.3/en/i386 at-good rpm http://apt.physik.fu-berlin.de redhat/7.3/en/i386 at-testing
Now run another apt-get update to get the necessary info about postfix into your apt cache and install postfix:
# apt-get update # apt-get install postfix
After installing postfix, switch back to at-good in your sources.list and apt-get update again, or you could end up installing something you didn't want. The only remaining pieces left to grab are the latest SPF policy daemon, mailgraph and queuegraph, all of which we'll cover later in this document. On to configuration changes...
If your system happens to have sendmail installed (Red Hat won't let you not install it, unless you've customized anaconda) and set as the default mta, run the command:
# redhat-switchmail
In the redhat-switchmail utility, select postfix as your mta, and the utility will perform the necessary steps to disable sendmail and enable postfix. The default postfix setup only allows mail relay from the localhost, so we've got some work to do. On to configuring postifx...
Going through my postfix main.cf file (mostly in order), here are the settings I've got, with attempts to explain those that I believe merit an explanation. The config file itself is heavily commented, and should pick up the slack on everything else.
While you're testing things out, you'll probably want to set postfix to soft bounce messages, just in case. Once I was confident I had things properly configured, I set:
soft_bounce = no
In conjunction with that setting, I'd also recommend setting your unknown recipient reject code to 450 while testing, and then to 550 when you are certain your setup is correct, like so:
unknown_local_recipient_reject_code = 550
However, the local recipient rejects only work if your system knows anything about local users. As I said before, in my case, our actual mail server is Microsoft Exchange, with a very twisted user database. I've seen some basic scripts to pull user info off an Exchange server, but they just don't seem to work in our setup (too many groups, sub-groups, etc), and maintaining an additional user database by hand on the filter machine just wasn't desirable, so I have the "local_recipient_maps" parameter commented out completely. If you aren't running Exchange, or have better luck scraping a user list off it, you may want to enable that to further reduce illicit traffic.
While postfix can typically auto-detect your host name and domain name, for assorted reasons, you may want to set these things manually. Maybe you have your filter machine behind a NAT firewall with a distinct host name (say filter.domain.com), but you want it to respond to incoming requests as something more standard, like mx.domain.com. I generally always set these values, just in case:
myhostname = mx.domain.com mydomain = domain.com
I also like to set the from domain for emails sent out by the filter machine to the hostname, rather than the domain name, so they stand out as being from a specific machine. This could be especially useful if you're running several such machines. If they were clustered, you might even have all of them identify themselves to the outside world as mx.domain.com, but set their domain of origin for messages they send out to mx1.domain.com, mx2.domain.com, etc. I've only got one, so I just set it to use the same value as myhostname:
myorigin = $myhostname
The default configuration for postfix is to only listen on the loopback interface (127.0.0.1) for smtp connections. We want to be able to accept incoming mail, so we need to listen on our network interface(s) as well. I'm lazy, so I just set postfix to listen on all interfaces, which in my case, is nothing more than loopback and one Ethernet card:
inet_interfaces = all
If you're running your filter machine behind a NAT firewall, you may need to tell postfix what the external IP is. I believe this isn't necessary when inet_interfaces is set to all, but if you use a more restricted inet_interfaces definition, you probably have to have proxy_interfaces set, which should extend the acceptable inet_interfaces list to listen for connections to your external IP:
proxy_interfaces = 11.22.33.44
This next configuration option is one of the key differences between a relaying filter and an end-point filtering mail server. Despite your first inclination, your domain name should NOT be included in the mydestination setting. Only include the local host name in mydestination, or postfix will attempt to deliver everything to user accounts local to the filter machine. This one bit me in the butt the first time I set this up, due to breezing over the documentation too quickly. I use this setting for mydestination:
mydestination = $myhostname, localhost.$mydomain
In my setup, the filter machine isn't used at all for outgoing mail relay. Such being the case, I have it locked down to only permit relaying either to my domains or from the local host. If you want to permit your users to use the filter for outbound mail, you might want to add your permitted IP addresses and/or subnets here, but I use this:
mynetworks = 127.0.0.0/8
In conjunction with the mynetworks setting, I have a defined list of domains to which relaying is permitted. The obvious ones are mydestination and mydomain, but I've actually got quite a few more domain names for which this machine relays mail. If you only have one or two extra domains, you can just add them to the list, but if you have quite a few, you might want to put them all in a file and reference the file instead. Its just a plain-text file, with one domain per line. My relay_domains variable looks like so:
relay_domains = $mydestination, $mydomain, /etc/postfix/relay-domains
Now we start getting into some of the more interesting stuff, as far as spam and virus counter-measures go. For starters, we'll require that incoming connections issue a standard smtp helo command, and we'll disable the smtp vrfy command. Any legitimate connecting mail server should supply a helo, so we'll hopefully cut out some of the traffic from shady spam and virus engines. The vrfy command is from a kinder, gentler time, and is used for verification that a user account exists on a destination mail server. Its been heavily abused by spammers, thus we'll disable it. We'd rather not let them know what our user names are. (Though in my case, since I've got no local_recipient_maps, I believe vrfy is useless anyhow). Here's the parameters for disabling helo and vrfy:
smtpd_helo_required = yes disable_vrfy_command = yes
The next section is critical in making sure you aren't running an open relay, and is also where we make our call to SPF. The order of the statements is important, because in the wrong order, despite all your other work, you can end up with an open relay. Checking against these rules stops at the first one matched. We start with permit_mynetworks, which says "pass anything originating from mynetworks", in this case, only localhost traffic. Next, we're rejecting any traffic that isn't to one of our domains defined in relay_domains. Anything that gets past those two checks will be traffic from the outside world, destined for one of our domains. So we pipe all that through the new (as of postfix 2.1) policy_service, the parameters for which are actually defined in master.cf. The only policy daemon I have defined handles SPF lookups, tagging and possible rejection. I'm not sure what else is available yet in the way of policy daemons, since postfix 2.1 just came out, but I'm sure there'll be more in the days ahead... The final permit is not necessary, since everything that makes it through the first two rules will match check_policy_service, but its there for safety's sake. (I believe its actually implied at the end of the list if it isn't already there). Here's my smtpd_recipient_restrictions setup:
smtpd_recipient_restrictions =
permit_mynetworks
reject_unauth_destination
check_policy_service unix:private/policy
permit
There's quite a bit more possible in this section, per some docs I found linked off the official postfix web site that I can't recall the location of off-hand, but some of them were a bit too restrictive for the type of mail my company receives and its paranoia over not wanting to lose any email. Just the same, below are some optional smtpd_recipient_restrictions options you can add that may be of use. Note that the last two are not RFC-compliant, and may reject more valid mail than you're willing to deal with. But here they are:
reject_non_fqdn_sender
reject_unknown_sender_domain
reject_invalid_hostname
reject_non_fqdn_hostname
We can also put a few restrictions specific to the data portion of the smtp connection. The only one I'm using rejects unauthorized pipelining (see RFC 2197). I'll have to dig around for some more possibles for this section (reject_many_rcpt is one, but I'm not sure what the threshold for "many" is, so its not enabled here)... All I've got is:
smtpd_data_restrictions =
reject_unauth_pipelining,
permit
If I'm recalling correctly, the default maximum message size postfix permits is 10MB. Some of my company's clients have the very bad habit of sending very big attachments via email, so we bumped that limit up to 50MB:
message_size_limit = 51200000
And in the final modifications to main.cf, we tell postfix how to get ahold of amavisd-new (which requires changes to master.cf, which we'll get to momentarily). We tell postfix to hand off to the smtp-amavis content filter at host address 127.0.0.1, port 10024. Theoretically, you can run amavisd-new, clamav and spamassassin on an entirely different machine from postfix, but why you would, I dunno... We're also going to limit the number of concurrent sessions the system can spawn, so as not to overload it (though again, I've never seen my relatively slow PIII-733 over 20% CPU utilization):
content_filter = smtp-amavis:[127.0.0.1]:10024 max_use = 10
This concludes our tour of main.cf, now on to master.cf, where we'll finish telling postfix about amavisd-new and spec out our SPF policy daemon.
We need to tack on a few entries in master.cf to finish defining how amavisd-new is contacted by postfix, how amavisd-new will get messages back to postfix, and the interface to the SPF policy daemon.
First, some parameters regarding the connection postfix establishes with amavisd-new. We use the same name, smtp-amavis, as defined in main.cf, with the same value for maxproc as we have for max_use in main.cf. We specify that we're talking to smtp-amavis using the smtp protocol, with a timeout of 1200 seconds to close the connection should something go haywire, and we're going to disable dns lookups, since we've presumably already taken care of all that when postfix first accepted the message. Here's those additions, with a nice little header:
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
smtp-amavis unix - - n - 10 smtp
-o smtp_data_done_timeout=1200
-o disable_dns_lookups=yes
Next up, we need to provide the means for amavisd-new to reinject mail to the postfix queue so that it can be forwarded on to its destination, be that our mail server, /dev/null or back to the sender in the form of a bounce. We tell postfix to run another smtpd listener on localhost port 10025, with heavily locked down connection settings, because we don't want someone trying to inject mail here when they shouldn't be:
127.0.0.1:10025 inet n - n - 10 smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=127.0.0.0/8
-o strict_rfc821_envelopes=yes
And finally, we need to tell postfix how to get in touch with that SPF policy daemon, which in reality, is nothing more than a perl script to which you specify the full path:
# Sender Policy Framework checking
policy unix - n n - - spawn
user=nobody argv=/usr/bin/perl /usr/libexec/postfix/smtpd-policy-spf.pl
To make that fully functional, you'll need to download the script from the SPF website and place it in /usr/libexec/postfix/, named per your configuration file (or vice versa). You can find it here: http://spf.pobox.com/postfix-policyd.txt. I simply downloaded it, renamed it to smtpd-policy-spf.pl and dropped it in /usr/libexec/postfix/.
And that's that for setting up postfix. When I get a chance, I'd like to actually put together an even better postfix 2.1 rpm for the world that has some of these changes already patched into the config files (or as alternate sample configs), along with the SPF policy daemon... Just an FYI, most main.cf changes take hold almost immediately, but changes to master.cf require reloading postfix (like our additional listener port 10025 and the bulk of the amavis port 10024 definition). Anyhow, on to configuring amavisd-new and clamav. We'll wait to restart postfix until after that's done, or it'll try injecting messages to amavisd before its properly configured to listen.
Many of the defaults in /etc/amavisd.conf work fine, but there are some mandatory changes, as well as a number of others I highly recommend. The config file itself is heavily documented, but I'll try to provide more "why" information here. For starters, you *must* set a proper $mydomain variable for amavisd to properly handle all your mail. Such as:
$mydomain = 'domain.com';
Additionally, for amavisd and clamav to be able to properly talk to one another (via UNIX domain sockets), you need to change the group under which amavisd-new runs. I use this user and group combination:
$daemon_user = "amavis"; $daemon_group = "clamav";
Ensure that amavisd is configured to inject messages back into postfix via smtp on 127.0.0.1, port 10025, by setting:
$forward_method = 'smtp:127.0.0.1:10025';
Just like postfix, amavisd needs to know what domains you're handling mail for. You likely don't need to set this parameter if you've disabled all virus and spam notifications (we'll get to that momentarily), but to be safe, I'd set it. Configure that list like so, adding whatever extra domains you have after $mydomain, which you defined a moment ago:
@local_domains_acl = ( ".$mydomain", '.domain.net', '.domain.org' );
$unix_socketname = "$MYHOME/amavisd.sock";
Make sure that amavisd is set to listen on port 10024, which is what we told postfix, and set amavisd to only accept connections from the localhost:
$inet_socket_port = 10024; $inet_socket_bind = '127.0.0.1'; @inet_acl = qw( 127.0.0.1 );
You have two options for logging in amavisd, one to just use a file, and the other to use syslog (and wherever that ends up sending the data). I use syslog and the mail facility, priority info, so that all my mail server data is in one log file, which makes life easy for mailgraph. Note that with even a log level of 2 (toward the low end of possibities 0-5), my mail server logs for a week of traffic wind up in the 800MB range (next on my list is to change the logrotate frequency from weekly to daily for /var/log/maillog). If you don't intend to use mailgraph, you might just go with having amavisd logging to its own file. Another advantage of syslog is that you can send all logs to a central log server if you wish. Anyhow, here's my relevant config lines:
$DO_SYSLOG = 1; $SYSLOG_LEVEL = 'mail.info'; $log_level = 2;
There's quite a bit of flexibility in amavisd for determining exactly what to do with messages that are flagged. Independent of one another, you can set viruses, spams, emails with banned attachments and emails with bad headers to bounce, discard or reject. There is another option, reject, which doesn't apply in the dual-MTA (postfix listening on port 25 and 10025) setup we're using, because we have no way to reject the original smtp connection after postfix has accepted it and passed the message on to amavisd (the reject option is designed for use with things like sendmail's milter interface to amavisd).
To start out, its probably best to set at least spam to pass, and possibly messages with bad headers, until you're certain you have your settings adjusted to avoid nuking legit email. I ran in such a fashion for about a month before switching over to automatic discarding of all junk. Note that we'll configure the levels at which spam would be discarded in just a moment. Personally, I'd start with this and work from there:
$final_virus_destiny = D_DISCARD; $final_banned_destiny = D_BOUNCE; $final_spam_destiny = D_PASS; $final_bad_header_destiny = D_BOUNCE;
You also have the option of sending notifications all over the place regarding messages flagged as one of the above types, again configurable on a per-type basis. You can notify the sender of any of them, which generally, in today's world of forged-sender spam and viruses, is a very bad idea. You'd probably just end up flooding yourself with bounces. Notifying the indended recipient might be a bit more useful for some of the types of flagged messages, though I've found it mostly useless. Many end users don't seem to grasp what exactly the notification is/was, so it just adds unnecessary confusion.
At least during the initial roll-out and testing/tweaking phase, I did find it useful to send notifications to an administrative account for regular examination. It was based on those reports that I fine-tuned our spamassassin setup. However, after getting comfortable with what we were tossing and what we were passing, I turned off all notifications. Instead, logwatch parses my mail logs and sends reports every night, so only one email instead of one for every spam, virus, etc. So to start out, I'd recommend you enable sending of notifications to an admin account or accounts:
$virus_admin = "virusadmin\@$mydomain"; $spam_admin = "spamadmin\@$mydomain";
You might also opt to quarantine viral or spammy messages. You can configure amavisd to save a copy of each virus or spam message, which may be of use for the ultra-paranoid who don't want to lose anything that might have been legitimate. While I was initially passing all spam, but discarding viruses (i.e., not delivering them to the intended recipient), I had this option enabled for viruses for a little while, and found it mostly useless. All it did was take up hard drive space. The detection of every virus gets logged, so you have a record of it, and I leave it up to the sender to disinfect their system and resend if they had something really important they sent that was infected. As for spams, I let all of them pass for a while, and set my discard threshold high enough, that I have 99.999% confidence nothing legitimate is being thrown away, so I have no real reason to use the quarantine option here. These options are well-documented in amavisd.conf though, should you wish to use them.
Should you so desire, you can also add a custom header to scanned mail. I find it useful, because I can just take a quick peek at the headers of a message to see if it passed through my mail filter or not. I use this setup, as proposed by the config file (but commented out by default):
$X_HEADER_TAG = 'X-Virus-Scanned'; $X_HEADER_LINE = "by amavisd-new at $mydomain";
The default banned filename list in amavisd.conf is fairly short and permissive. My company has strict guidelines about what people should and should not send us by email, so we have a much stricter banned filename list in place, though we did remove zip from the extended list of banned extensions (because our clients regularly send us zip files). I figure lock it down as much as possible, but you may find the default list sufficient. Here's what I'm using:
$banned_filename_re = new_RE(
qr'\.[^.]*\.(exe|vbs|pif|scr|bat|cmd|com|dll)$'i, # double extension
qr'.\.(ade|adp|bas|bat|chm|cmd|com|cpl|crt|exe|hlp|hta|inf|ins|isp|js|
jse|mdb|mde|msc|msi|msp|mst|pcd|pif|reg|scr|sct|shs|shb|vb|
vbe|vbs|wsc|wsf|wsh)$'ix, # banned extension - long
qr'^\.exe$'i, # banned file(1) types
qr'^application/x-msdo(wnload|s-program)$'i, # banned MIME types
);
After configuring a number of other options for spamassassin, we finally get around to setting the various thresholds. Personally, I thought this should be in the config file before setting the $final_spam_destiny parameter, as I wasn't entirely sure what it meant until after I'd seen the threshold settings here. But I digress... You can disable any of spamassassin's network-based tests, which I suppose could be useful if you have a slow link, but I'd highly recommend using them. To use them, make sure you have this setting:
$sa_local_tests_only = 0;
There are four thresholds at which amavisd takes action based on scores assigned to messages by spamassassin. At $sa_tag_level_deflt, informational headers, such as what tests the message hit on, are added to the message. These typically don't show up in an end-user's email client, unless you specifically view all headers (or raw source). I found this most useful for examining messages that got through and weren't tagged as spam when I (or an end user) thought they should have been.
At $sa_tag2_level_deflt, messages have headers added and (if configured) a spam tag added to the subject line. They are still NOT subject to your $final_spam_destiny setting. That kicks in at the next threshold, $sa_kill_level_deflt. Now, typically, the rule of thumb with spamassassin is that anything scoring over 5.0 is likely to be spam. I opt to add headers at 4.0, tag as spam at 6.0, but not auto-delete until 10.0. Then I'm dead-certain what I'm throwin out is spam, but users can still use a client-side filter to drop everything tagged between 6.0 and 9.9 into a folder for manual inspection. They can quickly delete the stuff that is truly junk, and I have them let me know if they have a false-positive.
There are whitelist (and blacklist) facilities provided directly in the amavisd config file, which you can use to remedy false-positives and false-negatives, but when possible, I try to adjust my rules and thresholds to compensate. I'll cover some basics on how I've done that in a minute... There is also the $sa_dsn_cutoff_level threshold, over which delivery status notifications will never be sent and the message will be discarded, but this is only relvant if you choose to bounce or pass spam. It does nothing in my case, since I'm already discarding everything over $sa_kill_level_deflt. Anyhow, here are some good starting threshold and tagging settings:
$sa_tag_level_deflt = 4.0; $sa_tag2_level_deflt = 6.0; $sa_kill_level_deflt = 10.0; $sa_dsn_cutoff_level = 20.0; $sa_spam_subject_tag = '[*SPAM*] ';
The last section you need to worry about is telling amavisd how to get in touch with what anti-virus scanning engine. In this case, we're only using clamav, because its free, and it works. I think some of the other options in the config file may also be free, but clamav is the one I've heard the most about and I've been extremely happy with it. Just make sure you comment out all the scanners you aren't using, and uncomment clamav:
@av_scanners = (
### http://www.clamav.net/
['Clam Antivirus-clamd',
\&ask_daemon, ["CONTSCAN {}\n", "/var/clamav/clamd.socket"],
qr/\bOK$/, qr/\bFOUND$/,
qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
);
There are a few more little changes you'll have to make for amavisd and clamav to properly converse with on another. First, edit the clamav config file (/etc/clamav.conf) and change "User clamav" to "User amavis". Now change the group ownership of /var/clamav to amavis (chgrp amavis /var/clamav) and set grour read/write on the entire directory (chmod -R g+rw /var/clamav). You also need to change the group ownership on /var/run/clamav (chgrp amavis /var/run/clamav/). And finally, add the user clamav to the amavis group (usermod -G amavis clamav). For good measure, if some amavisd and clamav still don't quite seem to be talking to one another as they should, you may want to also add user amavis to the clamav group (usermod -G clamav amavis).
Set amavisd and clamav to run at system boot time and start them up:
# /sbin/chkconfig amavisd on # /sbin/chkconfig clamd on # /sbin/service amavisd start # /sbin/service clamd start
I'd recommend following that up with a:
# /sbin/service clamd status
If the socket configuration for communication between amavisd and clamd isn't quite right, that command should give you an error message (process dead, couldn't connect to socket, or something like that). Adjust users and/or permissions as necessary, per just a few paragraphs ago...
At this point, you should have a working amavisd and clamav setup, so go ahead and bounce postfix:
/sbin/service postfix restart
A simple reload instead of restart might work, but hey, let's be thorough. You should now have a more or less completely functional filtering mail proxy. But wait, Jarod! Tell them what else they've won! Now for the weeks of fun tweaking to get things just right for your environment...
For most people, the default rule set will be sufficient to block the vast majority of spam. However, your typical email traffic may not be like most people, or maybe you want to tweak your rules even further to catch those bits that sneak by. Our email traffic happens to be a bit different than that of the average spamassassin user, plus those evil spamming buggers keep getting smarter about how to sneak things past. Such being the case, I've adjusted the scores assigned by certain tests (most of the faked header/helo ones) upward to ensure forgeries get flagged as spam. I've also added a number of custom rules, mostly taken from the SpamAssassin Rules Emporium, http://www.rulesemporium.com/. Some of these will likely be incorporated into the 2.70 spamassassin release, but I'm sticking with the stable 2.63 release for now.
When you're adjusting the scores assigned by spamassassin's built-in tests, simply add the rule name and new score you want to assign it at the end of /etc/mail/spamassassin/local.cf, such as these changes I'm using:
# Forged RCVD score FORGED_YAHOO_RCVD 5.0 score FORGED_HOTMAIL_RCVD2 5.0 score FORGED_HOTMAIL_RCVD 2.0 # Forged MUA score FORGED_MUA_AOL_FROM 4.5 # Forged HELO score FAKE_HELO_YAHOO 5.0 score FAKE_HELO_AOL 5.0 score FAKE_HELO_MSN 5.0 score FAKE_HELO_HOTMAIL 5.0 score RCVD_FAKE_HELO_DOTCOM 5.5 score NO_RDNS_DOTCOM_HELO 5.0 score FORGED_RCVD_NET_HELO 5.5 # Other forgeries score FORGED_AOL_HTML 3.0 score FORGED_OUTLOOK_TAGS 2.5 score MULTI_FORGED 3.5 score NO_RDNS_DOTCOM_HELO 5.0
These upwardly-adjusted scores help my system flag anything that appears to be a forgery as spam, even if it doesn't trigger any other rules, because it'll likely trigger at least two of these rules. Similarly, if there are rules that are constantly hitting on your valid traffic, you may want to add them here with a lower score than their default one.
Adding custom rules is just a matter of dropping additional *.cf files into /etc/mail/spamassassin/. I'm using a mixture of add-ons from SARE and some of those put out by Jennifer Wheeler (available under the Other Rules section on the SARE site). Simply download the .cf files you want to use from SARE, and drop them in place. Be sure to restart amavisd (service amavisd restart) after making any changes, because in my experience, they don't take hold until you restart amavisd.
I completely forgot about this part in draft one, this is just a place-holder, reminding me to put something here. You should be able to simply hit up Dan Bernstein's site for the requisite information though, at http://cr.yp.to/djbdns/dnscache.html.
While entirely optional, mailgraph and queuegraph have proved to be two fairly useful little cgis for me to keep tabs on how the mail filter is handling. I just dropped the cgis into /var/www/cgi-bin/ on my system, made a few edits per their respective documentation, put a few other files where instructed, and fired up apache. I'll try to get some more thorough documentation on this front, but I honestly can't remember exactly what I did now. Anyhow, fire up apache if/when you get things set up:
# /sbin/chkconfig httpd on # /sbin/service httpd start
You should be able to view the graph outputs at http://<your machine name or ip>/cgi-bin/mailgraph.cgi and queuegraph.cgi. You can view my example output (a snapshot off our system at work) at these two links:
http://wilsonet.com/mailfilter/mailgraph.html
http://wilsonet.com/mailfilter/queuegraph.html
The big gap in the output between June 6 and 7 in mailgraph was a scheduled power outage that went much longer than scheduled... Just after that, we had a huge spike in the number of deferred messages held by the filter machine, which you can see in queuegraph, because one of our AC units croaked after the power came back on, and our Exchange server bit the dust as a result... :-(
This concludes our tour, please send feedback, corrections, ideas, etc. to me, Jarod Wilson, by email at jarod@wilsonet.com. Bring it on, spammers, I have this setup in place for my own domain too. ;-)
2004.06.24 ---------- - updated to postfix 2.1.3 2004.06.23 ---------- - added missing apt-get install clamd and clamav-db - corrected @inet_acl for amavisd listener 2004.06.14 ---------- - added missing example config files - added placeholder for missing dnscache info - adapted to web site look instead of plain-text - posted postfix srpm and RHL7.3 rpm 2004.06.11 ---------- - initial release