Postfix Spam Filter using Ubuntu Dapper, MailScanner, SpamAssassin, Razor, Pyzor, DCC and ClamAV - Page 2
2 Setting up Postfix
We need some sample files from the Postfix source code, note that the source code we grab here is the original source code, before it is modified by the Ubuntu/Debian package maintainers:
tar xzvf postfix_2.3.3.orig.tar.gz
MAKE SURE you answer "n" to "overwrite?" Do each section separately:
cp -i /usr/share/postfix/main.cf.debian /etc/postfix/main.cf
cp -i /usr/local/src/postfix-2.3.3/conf/* /etc/postfix
cp -i /etc/postfix/header_checks /etc/postfix/body_checks
cp -i /etc/postfix/access /etc/postfix/sender_access
2.1 Edit master.cf
BTW watch for the two Postfix configuration files, both located in the /etc/postfix folder. More than one admin has gotten confused between master.cf and main.cf!
First backup the current master.cf:
cp /etc/postfix/master.cf /etc/postfix/master.cf-orig
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. Later we will create a daily/weekly report that this box will mail to us and because the report will contain contents that will classify the report itself as spam, this is a way to bypass content filtering for mail generated by this machine.
Add this just below the 'pickup' service type:
-o content_filter= -o receive_override_options=no_header_body_checks
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
2.2 Edit main.cf
This is the main configuration file for Postfix. For more information please read the comments in the main.cf file, the documentation in /usr/local/src/postfix-2.3.3/README_FILES, or the Postfix website http://www.postfix.org/documentation.html.
First we need to backup the main.cf file.
cp /etc/postfix/main.cf /etc/postfix/main.cf-orig
Since we are setting up our spamfilter to relay all of its mail to another server, we will be using what Postfix considers a "relay domain address class" which essentially means that we will use, out of the 300+ configurable parameters in Postfix, a small group of parameters that serves our purpose best. This address class is described here: http://www.postfix.org/ADDRESS_CLASS_README.html#relay_domain_class. We are also acting as a primary MX for another server so please read this appropriate section: http://www.postfix.org/STANDARD_CONFIGURATION_README.html#backup.
It is common in Postfix to store items in lookup tables. We are going to use several hash tables to store data that Postfix will use. Once we have plain text data in these tables, we use the postmap command to create binary files (Berkeley DB format) that Postfix will ultimately use to retrieve the data. For example, if you have a file called "sampletext" and you postmap sampletext, a new file is created "sampletext.db". Postfix will retrieve data from "sampletext.db", not "sampletext". There are more than a dozen other types of data files that Postfix can use to store data. Hash tables are an appropriate choice for several tables we will use, and pcre (Perl Compatible Regular Expressions) is appropriate for a couple tables we will use to hold content filtering data. In its simplest form a hash table is comprised of 2 pieces of data, a key and a value; typically referred to as the key/value pair. The key and the value are separated with whitespace (typically a space or tab). The data in a typical table that we use in Postfix would look something like this:
email@example.com OK firstname.lastname@example.org OK email@example.com OK
Suggested reading: http://www.postfix.org/DATABASE_README.html.
We will be using postconf to edit main.cf instead of typing in the perameters into the file with vi. The "" marks are required as it appears in the command boxes.
We simply need to make a correction to the default setting here:
postconf -e "alias_maps = hash:/etc/aliases"
Create the aliases file:
You will see there is now an aliases.db file in /etc/ directory. That is what Postfix usually reads. Now that you have a proper aliases file and because we are going to configure our system to relay all mail (no mail will be locally delivered), the aliases file will be ignored by Postfix. Instead we will set up virtual_alias_maps for address redirecting. Other programs may not work properly if the /etc/aliases file is missing so do not remove it.
The domain name that mail created on this machine appears to come from. For example, if cron sends mail to "firstname.lastname@example.org" it will appear to come from "email@example.com".
postconf -e "myorigin = example.com"
Obviously, in the above, and all the following commands, replace my example parameters, like "example.com", with your own specific values.
The fully-qualified domain name (FQDN) of the machine running the Postfix system.
postconf -e "myhostname = sfa.example.com"
These are the machines I trust, and will relay mail for, to any destination. Generally, this is set to my LAN, or just one, or a few trusted internal mail servers. Along with relay_domains, this is an important one to get right lest you run the possibility of becoming an "open relay". In other words, your box could accept and forward mail to domains for which it has no business doing so. Being an open relay is a serious issue, and can cause you to get blacklisted by various Internet anti-spam lists, among other problems. You can specify a single computer, multiple individual computers, or any computer on a specified network. You can also exclude certain hosts in your network by preceding the IP address with an exclamation mark. If you will be dealing with multiple internal mail servers, and/or want to allow several machines and/or subnets to relay through this server (careful!), just add them to this parameter in CIDR format and seperate the networks like this:
postconf -e "mynetworks = 127.0.0.0/8, 18.104.22.168/24, 10.10.10.10/24"
The above will allow the machines on the networks 22.214.171.124/24, and 10.10.10.10/24 to relay smtp mail through this box. The 127.0.0.0/8 is there to allow the local server to send, you need to at least put this one in. You could also specify a single computer's IP address. If you only know your dotted decimal netmask (i.e. 255.255.255.240) and need to convert it to CIDR format, try the http://www.wildpackets.com/products/free_utilities/ipsubnetcalc/overview. (Input an IP address on your network, select the subnet info tab, select your subnet mask, your network is Subnet ID/Mask Bits.) Or simply take a look at http://www.belchfire.net/webtools/cidr_conversion_table.html.
If you do not have any networks or computers that will relay through this server, run this command only with the 127.0.0.0/8 address.
Maximum size email that Postfix will let in the "front door".
postconf -e "message_size_limit = 10485760"
The above allows email up to 10MB, the value is in bytes (10*1024*1024). Mail larger than this may possibly get bypassed by the anti-virus scanner (ClamAV). You could increase this if you also configure ClamAV to scan files larger than 10MB. If you allow messages larger than 10MB, keep an eye on RAM.
Return an error message for local delivery attempts.
postconf -e "local_transport = error:No local mail delivery"
An empty mydestination tells Postfix this machine is not the final destination.
postconf -e "mydestination = "
An empty local_recipient_maps tells Postfix there are no local mailboxes.
postconf -e "local_recipient_maps = "
Our spamfilter must be able to receive mail for postmaster@yourIP. Reportedly, some things actually expect this ability to exist. We will also allow mail to abuse@yourIP. Since we do not allow local mail delivery, mail addressed to our spamfilter's IP address will get rejected with an error message. Setting up virtual_alias_maps allows email to these two accounts to be forwarded to an inside address. Make sure your Exchange server is set up to receive messages addressed to "root", "postmaster" and "abuse".
Set up a reference to the virtual file:
postconf -e "virtual_alias_maps = hash:/etc/postfix/virtual"
Then edit the virtual file:
Add these two lines to the top of the virtual file:
postmaster firstname.lastname@example.org abuse email@example.com
Save and exit the file, then create the binary file that Postfix will use:
/etc/postfix/relayhost tells or spamfilter how outgoing email should be sent. relayhost will contain the IP or FQDN of the email server you wish to use to send outbound email. In other words, non-local mail, mail bound for domains other than ours. Not to be confused with the /etc/postfix/transport file, transport is used to route incoming mail bound for one of our local domains. We will get to the transport in a moment.
If relayhost is blank, or not configured, then our spamfilter will be used for that purpose.
Note: The brackets  are required in this command.
postconf -e "relayhost = [mymailserver.example.com]"
Optionally you can setup your spamfilter as your outgoing SMTP server but you should first have your reverse DNS record in place and of course your "A" record and "MX" record so other servers on the Internet will accept your mail. When you reconfigure your clients and other SMTP servers to use our spamfilter for their outgoing mail that mail will go through the same scanning process as your inbound mail (unless you find some fancy tweaks to prevent it). If these are not yet in place, it is very useful to temporarily configure relayhost with your current, working, outgoing mail server.
Also, make sure that the relayhost you designate is configured to accept email from this machine and THAT machine is not using THIS machine for ITS outgoing mail (can you say "loop"?).
We are going to build a table of every single user in every single domain that we accept mail for. This table will be used to reject mail that is addressed to nonexistent users in our domain(s). DON'T FREAK OUT JUST YET... At this time we are only going to set up the structure of the table. If you are using Exchange, there are HOWTOs available that describe automating the process of building the relay_recipients table. It has been very common of late for spammers to launch dictionary attacks; sending thousands of messages to a domain using fabricated user names. Our spamfilter would have to process each and every one of these unless you put valid users in the relay_recipients table. Don't underestimate the importance of this and make sure you are not the only one in your organization who knows how to make changes to this file. We'll come back to automating this after your spamfilter is functional. If you have a manageable number of users, manually enter them.
Set up a reference to a file we will create to store the data:
postconf -e "relay_recipient_maps = hash:/etc/postfix/relay_recipients"
Then edit relay_recipients:
For the moment, we are going to accept mail for all users in our domain(s) so enter each domain you accept mail for in the following format:
@example.com OK @example2.com OK @example3.com OK
Then create the binary file that Postfix will use:
The entries above are temporary. They are wildcards that allow mail to your domains. You MUST remove the entries above at some point in the near future and replace them with every single one of your valid recipients' email addresses. When you are ready to enter each user individually in the relay_recipients file, you would first remove (or comment out) the data above that allows mail to all users in the domain, and then list each user individually in the form:
firstname.lastname@example.org OK email@example.com OK firstname.lastname@example.org OK
Actually, in this particular file the value "OK" listed after each user is not used for anything, but something must be there because a hash table requires a value after the key. Note that by eliminating email@example.com from this file, you can prevent users from the Internet from sending mail to firstname.lastname@example.org, but don't do this if some of your own servers need to use this machine to send mail to root. If you use Exchange, here are the HOWTOs. Even if you don't use Exchange, I found the information regarding file transfers useful. http://www2.origogeneris.com:4000/relay_recipients.html- http://www-personal.umich.edu/~malth/gaptuning/postfix/ - http://www.unixwiz.net/techtips/postfix-exchange-users.html - http://postfix.state-of-mind.de/patrick.koetter/mailrelay/ - http://doc.nettools.ru/Unix/Postfix&intserver/
Tells Postfix where to look for a transport file. We use the transport file to tell Postfix where to forward valid mail for our domain(s). Setting up transport is similar to setting up relay_recipients.
Create a reference to it in main.cf:
postconf -e "transport_maps = hash:/etc/postfix/transport"
Then edit transport:
Add 1 new line for each domain for which you will be handling mail, similar to the example below. The IP address is that of whatever server is the final destination of messages addressed to our domain(s) (our Exchange server). It does not matter where you place these items in the file, but I like to put them at the top.
example1.com smtp:[10.10.10.100] example2.com smtp:[10.10.10.101] example3.com smtp:[10.10.10.102]
DO include the brackets on these lines!). You can also use FQDN hostname instead of an IP address (i.e. smtp:[exchange1.example.com]).
Now to create the binary file Postfix will use:
What destination domains (and subdomains thereof) this system will relay mail for. You want to list here ONLY domains for which you are responsible for accepting mail. In addition to allowing mail to be relayed to these domains, this setting also infers that we do not relay mail to domains not listed here and therefore this is a critical component in preventing the spamfilter from becoming an open relay.
postconf -e "relay_domains = hash:/etc/postfix/relay_domains"
Add 1 new line for each domain for which you will be handling mail, similar to the example below:
example1.com OK example2.com OK example3.com OK
This file currently has a very similar format to relay_recipients do not mistake the two. This file cannot have '@' in front of the domain name. Just thought I'd mention it, some very smart people have been known to have done this...
Then create the binary file Postfix will use:
NOTE: relay_recipients, relay_domains, and transport are files you will become very intimate with. Every time you need to add users to a domain, add a domain or remove a domain from your list, you need to go to all three of these files and edit them. After the edit, run a postmap on each one and restart Postfix with 'postfix reload'. In the last page there is a 'Maintenance' part which contains a README that can be copied to your spamfilter as a quick reference for some common tasks.
If your current SMTP/POP3/IMAP server is configured to use address extensions (for example email@example.com) then recipient_delimiter should be set to match the delimiter you are currently using to separate the user name from the address extension. This has nothing to do with the comma you are using to separate multiple people you send email to (firstname.lastname@example.org, email@example.com, firstname.lastname@example.org) using your email client (MUA). You might be familiar with this if you use GMail. If you have a GMail account you can send email to it in this format, for example email@example.com and set a Filter up in GMail to tag everything with the 'testtag' in the to address and skip the inbox. Recently a common use for this feature is to use these tags when you subscribe to any web service and then filter according to the tag. Anyway, if you have it you'll know you have it if you have no idea what I'm talking about follow the "I Don't use recipient delimiters" instructions.
3 Typical settings - Choose one.
1. I Don't use recipient delimiters:
postconf -e "recipient_delimiter = "
2. I currently use the plus sign:
postconf -e "recipient_delimiter = +"
2. I currently use the minus sign:
postconf -e "recipient_delimiter = -"
2.2.15 NAT/Proxy Settings (Optional)
If (and only if) the IP address you present to the world is not the IP address of your spamfilter (you are configured to run behind a NAT firewall or a proxy server) go ahead and add the following two lines to main.cf, then uncomment and configure proxy_interfaces (126.96.36.199 represents the public IP address):
# Specify your NAT/proxy EXTERNAL address here. #proxy_interfaces = 188.8.131.52