Original of this document available at http://www.bowe.id.au/michael/isp/postfix-server.htm
CentOS is an Enterprise-class Linux Distribution derived from Redhat Enterprise Linux - pretty much the only difference is the Redhat branding has been removed. As such CentOS is a great choice of O/S because you can be assured it will be stable and well supported for drivers.
Fedora is another O/S that is very similar to CentOS. This guide will work fine on Fedora as well, with no changes required to the installation steps. If you are going to use Fedora there are a few things you need to be aware of :
If you are going to host more than few hundred mailboxes, I would suggest you have at least 2 disk drives in the server. IDE drives are OK, but SCSI ( possibly running in RAID configuration) will give better results when there are high disk loads
It is possible to build large servers using this design. Examples built include :
With these servers, the system load values on the mailserver are typically around 5 peaking at about 10. The Amavis boxes have similar readings. POP3 and SqWebMail used mainly, with a little bit of IMAP and IMP. Common to see around 100 POP3 sessions active. SMTP-MX concurrency set around 100, Maildrop concurrency set around 20.
Boot the CentOS 4.4 disk
Language selection :English (English)
Keyboard Configuration : US English
Upgrade Examine : Install CentOS
Installation Type : Server
Disk Partition Setup : Manually partition with Disk Druid
Your 1st disk doesn't need to be very large.
- /boot : ext3, 256Mb, force to be primary partition
- /tmp : ext3 - 2000Mb, force to be primary partition
- swap : 2000Mb, force to be primary partition
- / : ext3 - Fill to max available size, force to be primary partition
Your 2nd disk should be large. If its an IDE drive, you should put it on a separate controller to the 1st disk:
- /var/vmail : ext3, Fill to max available size, force to be primary partition. (This is where all our mailboxes and user websites are going to live)
If your server is going to be busy, and you have a 3rd disk you can make further enhancements. The disk doesn't need to be very large. Note, that if you have IDE drives, then this 3rd drive wont really help much unless you have a 3rd IDE controller available
- /var/spool/postfix : ext3. (Postfix uses this location for storing queued mail.)
Boot Loader Configuration : press next
Network Configuration :
Firewall Configuration :
Additional Language Support :
Timezone Selection :
Set root Password : ChooseSomethingGood!
Package Group Selection :
Configure the internationalisation settings. By default CentOS will set UTF8 ( Unicode ) character encoding schemes. but I find this causes problems with the console display in my SSH client. Also some perl programs are known to have problems with the UTF8
cp /etc/sysconfig/i18n /etc/sysconfig/i18n.original vi /etc/sysconfig/i18n# Remove any UTF-8 entries from the LANG line # ie change it from LANG="en_US.UTF-8" to LANG="en_US"LANG="en_US"
Import the GPG keys for software packages
rpm --import /usr/share/rhn/RPM-GPG-KEY*
Configure the log rotation scheme, to rotate daily, for 30 days, compressing the old logs
vi /etc/logrotate.conf#weekly daily#rotate 4 rotate 30#compress compress
Configure the NTP clock sync ( very important that mail servers have correct clock! )
vi /etc/ntp.conf#server 0.pool.ntp.org #server 1.pool.ntp.org #server 2.pool.ntp.org server ntp.yourdomain.com
Tweak the firewall rules. Need to add some extra ports
TCP 20 : ftp-data TCP 21 : ftp TCP 110 : pop3 TCP 143 : imap TCP 443 : https TCP 465 : smtps TCP 993 : imaps TCP 995 : pop3s UDP 161 : snmpvi /etc/sysconfig/iptables-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 110 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 143 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 443 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 465 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 993 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 995 -j ACCEPT -A RH-Firewall-1-INPUT -m state --state NEW -m udp -p udp --dport 161 -j ACCEPT
Configure which services are starting at boot time. The aim is to disable any unneeded services.
chkconfig apmd off chkconfig bluetooth off chkconfig cpuspeed off chkconfig cups off chkconfig httpd on chkconfig isdn off chkconfig mysqld on chkconfig netfs off chkconfig nfslock off chkconfig ntpd on chkconfig pcmcia off chkconfig portmap off chkconfig rpcgssd off chkconfig rpcidmapd off chkconfig saslauthd off chkconfig sendmail off# these two are in Fedora, but not CentOS chkconfig mDNSResponder off chkconfig nifd off
For your spool and mailbox partitions, set the noatime flag. This is an important performance tweak which works by preventing the need for writing any updates to the disk when processes are reading files ( eg when Postfix's qmgr process scans mail in the queue ). I had a busy server where loads dropped from a steady 20 to sub 10's by making this simple change! Also, as a security precaution, tweak the fstab, to disable /tmp from permitting SUID or exec functionality.
vi /etc/fstabLABEL=/tmp /tmp ext3 defaults,nosuid,noexec 1 2LABEL=/var/vmail /var/vmail ext3 defaults,noatime 1 2# and if you made a dedicated partition for the postfix mail queue... LABEL=/var/spool/postf /var/spool/postfix ext3 defaults,noatime 1 2
That noexec fstab tweak has an unfortunate side-effect of causing the "logrotate" script to break. A workaround for this is :
mkdir /var/logrotate.tmpvi /etc/cron.daily/logrotate#!/bin/sh export TMPDIR=/var/logrotate.tmp /usr/sbin/logrotate /etc/logrotate.conf
Take advantage of the colors and other advanced features of the vim editor, compared with basic vi editor
# only required on Fedora, a CentOS install appears to already default to vim echo "alias vi='vim'" >> /root/.bashrc
If you are using CentOS, you can grab the "fastestmirror plugin" for yum, as this should allow your rpm downloads to run quicker
yum install centos-yum yum-plugin-fastestmirrorvi /etc/yum.confplugins=1
Then give the server a reboot
shutdown -r now
Run the update manager. It will go and look for updated RPMs, then will download and install them.
TIP : If you are running a 64 bit platform eg Opteron, add this line to
the /etc/yum.conf to prevent conflicts between the 64bit and non-64bit
librariesvi /etc/yum.conf# add this line if you are running 64bit exclude=*.i386 *.i586 *.i686 |
Be warned that the first update pass on Fedora can be pretty large. Its not uncommon to see 250M+ of updates to be downloaded. CentOS isnt so "bleeding edge" so for that platform there are usually a lot less updates to download.
yum update
Enable ongoing auto-updating
crontab -e# Keep up to date. Lets only do it during business hours, just to be safe :-) # # Dont download kernel updates, or our /boot will overflow eventually. # Dont download mysql updates, as I have seen mysql shutdown and not automatically come back up. # # If we want to update kernel or mysql, we can run these manually via a "yum update". 50 10 * * 1-5 /usr/bin/yum --exclude=kernel* --exclude=hal --exclude=mysql* -y update
Give the server are reboot, so the new kernel that yum downloaded can take effect
shutdown -r now
SSL certificates will be used by Postfix (for SMTPS and TLS), Courier (for IMAPS and POP3S) and Apache (for HTTPS)
mkdir /usr/local/ssl cd /usr/local/ssl# Generate the RSA private-key for the server. # We don't want a pass phrase on this key, otherwise it will need to be entered # every time courier/apache/postfix starts. openssl genrsa -out mail.yourdomain.com.key 1024Generating RSA private key, 1024 bit long modulus ...................++++++ ........................++++++ e is 65537 (0x10001)
# Tighten the permissions on this key file chmod 600 mail.yourdomain.com.key# Generate a certificate request openssl req -new -key mail.yourdomain.com.key -out mail.yourdomain.com.csrYou are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [GB]:AU State or Province Name (full name) [Berkshire]:South Australia Locality Name (eg, city) [Newbury]:Adelaide Organization Name (eg, company) [My Company Ltd]:Yourcompany Limited Organizational Unit Name (eg, section) []:Hosting Services Common Name (eg, your name or your server's hostname) []:mail.yourdomain.com Email Address []:postmaster@yourdomain.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []:password An optional company name []:
At this point you would send your CSR off to a Certificate Authority for signing (such as Verisign or Thawte) . However if you wanted to do some in-house testing, we can set ourselves up as a CA, and then sign the CSR ourselves :
# generate RSA private-key for the CA openssl genrsa -des3 -out ca.key 1024Generating RSA private key, 1024 bit long modulus .....................++++++ ...............++++++ e is 65537 (0x10001) Enter pass phrase for ca.key:capass Verifying - Enter pass phrase for ca.key:capass
# tighten permissions on this private key chmod 600 ca.key# create a self signed CA certificate openssl req -new -x509 -days 365 -key ca.key -out ca.crtEnter pass phrase for ca.key:capass You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [GB]:AU State or Province Name (full name) [Berkshire]:SomeState Locality Name (eg, city) [Newbury]:SomePlace Organization Name (eg, company) [My Company Ltd]:Test CA Company Organizational Unit Name (eg, section) []:SomeGroup Common Name (eg, your name or your server's hostname) []:CA Signing Biz Email Address []:postmaster@nowhere
# Use this test CA to sign our server cert openssl x509 -req -days 365 -CA ca.crt -CAkey ca.key -set_serial 01 -in mail.yourdomain.com.csr -out mail.yourdomain.com.crtSignature ok subject=/C=AU/ST=SomeState/L=SomePlace/O=Test CA Company/OU=SomeGroup/CN=CA Signing Biz/emailAddress=postmaster@nowhere Getting CA Private Key Enter pass phrase for ca.key:capass
Combine the server key and certificate into a single file. Postfix and Apache can deal with two separate files, but Courier needs them both in one. To try and keep things consistent we will use a single file with all 3 apps
# create the PEM file in the format that courier wants (both the key and the cert in one file) cat mail.yourdomain.com.key mail.yourdomain.com.crt > mail.yourdomain.com.pem chmod 600 mail.yourdomain.com.pem
OK so you should now have something like this :
ls -altotal 36 drwxr-xr-x 2 root root 4096 Nov 28 22:02 . drwxr-xr-x 14 root root 4096 Nov 20 21:50 .. -rw-r--r-- 1 root root 1371 Nov 28 21:50 ca.crt -rw------- 1 root root 963 Nov 28 21:47 ca.key -rw-r--r-- 1 root root 1001 Nov 28 21:51 mail.yourdomain.com.crt -rw-r--r-- 1 root root 773 Nov 28 21:45 mail.yourdomain.com.csr -rw------- 1 root root 887 Nov 28 21:45 mail.yourdomain.com.key -rw------- 1 root root 1888 Nov 28 22:02 mail.yourdomain.com.pem
MySQL has been installed as part of the CentOS installation. Databases will be stored in /var/lib/mysql
Tune, based on how busy the MySQL is going to be. There are a few sample cnf files supplied so choose the one that best matches your needs. (IMPORTANT NOTE : MySQL query caching isn't enabled in any of the sample files except for my-large and my-huge. If you decide to use one of the smaller config files, it will be worth you while to copy the query_cache_size setting across from the large/huge files)
mv /etc/my.cnf /etc/my.cnf.original cp /usr/share/doc/mysql-server-4.1.20/my-medium.cnf /etc/my.cnf
. Edit the config file and make the following tweaks in the [mysqld] section
vi /etc/my.cnf# put this one in if its not there already query_cache_size= 64M# Our databases will only be accessed by programs running locally, so disable TCP connections and replication functions skip-networking #log-bin#Add an entry to tweak the max number of allowed connections #The default is 100. On a busy server you will probably need to increase this max_connections = 400# Record of any queries that run slowly log-slow-queries
Create the MySQL tables for Postfix to use.
mysqlGRANT SELECT ON postfix.* TO postfixuser@localhost IDENTIFIED BY 'postfixpass';CREATE DATABASE postfix; USE postfix;CREATE TABLE mailbox_domains (domain varchar(255) NOT NULL default '', description varchar(255) NOT NULL default 'Postfix virtual mailbox domain', maxaliases int(10) NOT NULL default '-1', maxmailboxes int(10) NOT NULL default '-1', maxquota int(10) NOT NULL default '-1', server varchar(255) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', modified datetime NOT NULL default '0000-00-00 00:00:00', modified_by varchar(255) NOT NULL default '', active tinyint(1) NOT NULL default '1', PRIMARY KEY (domain)) TYPE=MyISAM COMMENT='Postfix Virtual Mailbox Domains';CREATE TABLE mailbox (email varchar(255) NOT NULL default '', password varchar(255) NOT NULL default '', clear_password varchar(255) NOT NULL default '', name varchar(255) NOT NULL default '', maildir varchar(255) NOT NULL default '', mailquota int(10) NOT NULL default '20', ftpquota int(10) NOT NULL default '20', disableftp tinyint(1) NOT NULL default '0', disableimap tinyint(1) NOT NULL default '0', disablepop3 tinyint(1) NOT NULL default '0', disablewebmail tinyint(1) NOT NULL default '0', disablesmtpauth tinyint(1) NOT NULL default '0', virus_lover tinyint(1) default NULL, spam_lover tinyint(1) default NULL, banned_files_lover tinyint(1) default NULL, bad_header_lover tinyint(1) default NULL, bypass_virus_checks tinyint(1) default NULL, bypass_spam_checks tinyint(1) default NULL, bypass_banned_checks tinyint(1) default NULL, bypass_header_checks tinyint(1) default NULL, spam_tag2_level float default NULL, spam_kill_level float default NULL, server varchar(255) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', modified datetime NOT NULL default '0000-00-00 00:00:00', modified_by varchar(255) NOT NULL default '', active tinyint(1) NOT NULL default '1', PRIMARY KEY (email)) TYPE=MyISAM COMMENT='Postfix - Virtual Mailbox Maps';CREATE TABLE alias_domains (domain varchar(255) NOT NULL default '', description varchar(255) NOT NULL default 'Postfix virtual alias domain', maxaliases int(10) NOT NULL default '-1', server varchar(255) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', modified datetime NOT NULL default '0000-00-00 00:00:00', modified_by varchar(255) NOT NULL default '', active tinyint(1) NOT NULL default '1', PRIMARY KEY (domain)) TYPE=MyISAM COMMENT='Postfix Virtual Alias Domains';CREATE TABLE alias (address varchar(255) NOT NULL default '', goto text NOT NULL, server varchar(255) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', modified datetime NOT NULL default '0000-00-00 00:00:00', modified_by varchar(255) NOT NULL default '', active tinyint(1) NOT NULL default '1', PRIMARY KEY (address)) TYPE=MyISAM COMMENT='Postfix - Virtual Alias Maps';CREATE TABLE client_access (client varchar(255) NOT NULL default '', response varchar(255) NOT NULL default '', note varchar(255) NOT NULL default '', server varchar(255) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', modified datetime NOT NULL default '0000-00-00 00:00:00', modified_by varchar(255) NOT NULL default '', active tinyint(1) NOT NULL default '1', PRIMARY KEY (client)) TYPE=MyISAM COMMENT='Postfix - Client Access';CREATE TABLE sender_access (sender varchar(255) NOT NULL default '', response varchar(255) NOT NULL default '', note varchar(255) NOT NULL default '', server varchar(255) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', modified datetime NOT NULL default '0000-00-00 00:00:00', modified_by varchar(255) NOT NULL default '', active tinyint(1) NOT NULL default '1', PRIMARY KEY (sender)) TYPE=MyISAM COMMENT='Postfix - Sender Access';CREATE TABLE recipient_access (recipient varchar(255) NOT NULL default '', response varchar(255) NOT NULL default '', note varchar(255) NOT NULL default '', server varchar(255) NOT NULL default '', created datetime NOT NULL default '0000-00-00 00:00:00', modified datetime NOT NULL default '0000-00-00 00:00:00', modified_by varchar(255) NOT NULL default '', active tinyint(1) NOT NULL default '1', PRIMARY KEY (recipient)) TYPE=MyISAM COMMENT='Postfix - Recipient Access';quit
http://asg.web.cmu.edu/cyrus/download/sasl/
Grab the SQL modules for SASL
yum install cyrus-sasl-sql cyrus-sasl-devel
Create a config file so that Postfix will be able to use the SASL libraries to do SMTP authentications via MySQL
vi /usr/lib/sasl2/postfix.confpwcheck_method: auxprop auxprop_plugin: sql mech_list: CRAM-MD5 DIGEST-MD5 PLAIN LOGIN sql_engine: mysql sql_hostnames: localhost sql_user: postfixuser sql_passwd: postfixpass sql_database: postfix sql_verbose: yes sql_select: SELECT clear_password FROM mailbox WHERE email='%u@%r' AND disablesmtpauth=0
TIP : If you are using x86_64 platform ( eg Opteron ), you will need to put this file in a different place: /usr/lib64/sasl2/postfix.conf
Remove sendmail ( which is installed by default on CentOS )
yum remove sendmail
Install the prerequisites
yum install pcre-devel
Add the required user accounts to run the Postfix MTA
groupadd -r postfix useradd -r -g postfix -d /no/where -s /no/shell postfixgroupadd -r postdrop
Before we forget, tighten up the permissions on the SASL conf file, as it contains the database username/password
chown root.postfix /usr/lib/sasl2/postfix.conf chmod 640 /usr/lib/sasl2/postfix.conf
Add the account that will own all the virtual mail
groupadd -g 1001 vmail useradd -u 1001 -s /sbin/nologin -g vmail vmail
Download and extract the Postfix sources
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/postfix/official/postfix-2.4.1.tar.gztar xzf postfix-2.4.1.tar.gz chown -R root.root postfix-2.4.1 cd postfix-2.4.1
Compile, enabling the optional support for MySQL, SASL (SMTP-AUTH), SSL (SMTPS and TLS)
make -f Makefile.init makefiles \ 'CCARGS=-DHAS_MYSQL -I/usr/include/mysql -DUSE_SASL_AUTH -DUSE_CYRUS_SASL -I/usr/include/sasl -DUSE_TLS -I/usr/include/openssl' \ 'AUXLIBS=-L/usr/lib/mysql -lmysqlclient -lz -lm -lsasl2 -lssl -lcrypto'makemake install # (press enter to all the "make install" questions)
TIP : If you are using x86_64 platform ( eg Opteron ), you will need to
use a slightly modified make :make -f Makefile.init makefiles \ 'CCARGS=-DHAS_MYSQL -I/usr/include/mysql -DUSE_SASL_AUTH -DUSE_CYRUS_SASL -I/usr/include/sasl -DUSE_TLS -I/usr/include/openssl' \ 'AUXLIBS=-L/usr/lib64/mysql -lmysqlclient -lz -lm -lsasl2 -lssl -lcrypto' |
Some applications expect the sendmail binary to be available at /usr/lib/sendmail, but Postfix doesn't put it there, so lets make a symlink
ln -s /usr/sbin/sendmail /usr/lib/sendmail
vi /etc/postfix/master.cf
# Now enabled SMTP over SSL (smtps : port 465) # # To do this, we need to edit the maser.cf file. # The two line are already there, but are commented out. # To enable the service, we simply need to remove the comment markers ("#"). # # Note, there needs to be whitespace (either a space or tab) at the start of the 2nd line (in front of the -o)smtps inet n - n - - smtpd -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes
vi /etc/postfix/main.cf
# make the following changes :myhostname = mail.yourdomain.com mydomain = yourdomain.commydestination = $myhostname, localhost.$mydomain, localhost local_recipient_maps = unix:passwd.byname $alias_mapsmynetworks = $config_directory/mynetworks relayhost = [smarthost.yourdomain.com] #<-- if you have a smarthost serveralias_maps = hash:/etc/aliaseshome_mailbox = Maildir/# Next, add all these to the bottom of the file :disable_vrfy_command = yes smtpd_recipient_limit = 250 biff = no # (note this setting below only affects LOCAL mail delivery agent, not virtual mailboxes) mailbox_size_limit = 20480000 maximal_queue_lifetime = 5d message_size_limit = 18000000 delay_warning_time = 4h default_process_limit = 50 append_dot_mydomain = no parent_domain_matches_subdomains =################################################################################### ### ENABLE SASL SUPPORT ( SMTP-AUTH ) # smtpd_sasl_auth_enable = yes # Enable SASL support in postfix # smtpd_sasl_security_options = noanonymous # Anonymous logins will not be permitted # broken_sasl_auth_clients = yes # Allow RFC-broken mail clients like Outlook Express4 to use SMTP AUTH # smtpd_sasl_path = postfix # Tells SASL to get the config from /usr/lib/sasl2/postfix.conf # smtpd_sasl_local_domain = # If the user fails to nominate a domain, don't auto append one # smtpd_sasl_authenticated_header = yes # Include the authenticated username in the message headers. # Having this on will make it easier if a spammer cracks one of your user's weak passwords, # and starts using SMTP-AUTH to relay spam through your serversmtpd_sasl_auth_enable = yes smtpd_sasl_security_options = noanonymous broken_sasl_auth_clients = yes smtpd_sasl_path = postfix smtpd_sasl_local_domain = smtpd_sasl_authenticated_header = yes################################################################################### ### ENABLE TLS SUPPORT ( "STARTTLS" ... enables SSL to be negotiated during a SMTP connection ) # smtp_use_tls = no # dont enable TLS for outbound SMTP connections # smtpd_use_tls = yes # announce TLS availability for incoming SMTP connections # smtpd_tls_auth_only = no : # TLS is optional, not enforced # smtpd_tls_key_file : # specify the private key ( must not be encrypted - ie no password) # smtpd_tls_cert_file : # specify the certificate # smtpd_tls_session_cache_database : # nominate a server-side TLS session cache. Improves performance. # smtpd_tls_loglevel = 1 : # log basic TLS handshake and cert info # smtpd_tls_received_header = yes # record some protocol/cipher etc info in the Received header smtp_use_tls = nosmtp_use_tls = no smtpd_use_tls = yes smtpd_tls_auth_only = no smtpd_tls_key_file = /usr/local/ssl/mail.yourdomain.com.key smtpd_tls_cert_file = /usr/local/ssl/mail.yourdomain.com.crt smtpd_tls_session_cache_database = btree:/etc/postfix/tls_smtpd_scache smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes################################################################################### ### add $smtpd_recipient_restrictions to the standard list ### so that we can "proxy:" the check_client|sender|recipient_access entries proxy_read_maps = $local_recipient_maps, $mydestination, $virtual_alias_maps, $virtual_alias_domains, $virtual_mailbox_maps, $virtual_mailbox_domains, $relay_recipient_maps, $relay_domains, $canonical_maps, $sender_canonical_maps, $recipient_canonical_maps, $relocated_maps, $transport_maps, $mynetworks, $smtpd_recipient_restrictions################################################################################### ### DEFINE OUR SMTPD RESTRICTIONS, RELAY CONTROL, RBL BLOCKING ETC smtpd_helo_restrictions = smtpd_client_restrictions = smtpd_sender_restrictions =smtpd_recipient_restrictions = check_client_access proxy:mysql:/etc/postfix/mysql-client-access.cf, check_sender_access proxy:mysql:/etc/postfix/mysql-sender-access.cf, check_recipient_access proxy:mysql:/etc/postfix/mysql-recipient-access.cf, permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_invalid_helo_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_rbl_client list.dsbl.org, reject_rbl_client cbl.abuseat.org, reject_rbl_client dnsbl.njabl.org, permit
smtpd_data_restrictions = reject_unauth_pipelining, permit################################################################################### ### Virtual alias config virtual_alias_domains = proxy:mysql:/etc/postfix/mysql-virtual-alias-domains.cf virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual-alias-maps.cf, proxy:mysql:/etc/postfix/mysql-virtual-mailbox-to-alias-maps.cf################################################################################### ### Virtual mailbox config # virtual_mailbox_domains : A list of all the virtual mailbox domains # virtual_mailbox_base : This value will be prepended to all the virtual_mailbox_maps # virtual_mailbox_maps : Virtual email addr to disk location mappings # virtual_mailbox_limit : Maximal size of an individual mailbox/Maildir filevirtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf virtual_mailbox_base = /var/vmail virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf virtual_mailbox_limit = 20480000virtual_transport = maildrop maildrop_destination_recipient_limit = 1
Create the config files that tell Postfix how to access the various MySQL tables.
Note "hosts = localhost" means Postfix will use sockets, "hosts = 127.0.0.1" means Postfix will use TCP. We have disabled TCP access in MySQL (with the "skip-networking" config option), so make sure you stick with using the word localhost in these files. Also, sockets are faster than TCP.
echo "user = postfixuser" > /etc/postfix/mysql-virtual-mailbox-domains.cf echo "password = postfixpass" >> /etc/postfix/mysql-virtual-mailbox-domains.cf echo "hosts = localhost" >> /etc/postfix/mysql-virtual-mailbox-domains.cf echo "dbname = postfix" >> /etc/postfix/mysql-virtual-mailbox-domains.cf echo "query = SELECT 'ignored by postfix' FROM mailbox_domains WHERE domain='%s' AND active=1" >> /etc/postfix/mysql-virtual-mailbox-domains.cfecho "user = postfixuser" > /etc/postfix/mysql-virtual-mailbox-maps.cf echo "password = postfixpass" >> /etc/postfix/mysql-virtual-mailbox-maps.cf echo "hosts = localhost" >> /etc/postfix/mysql-virtual-mailbox-maps.cf echo "dbname = postfix" >> /etc/postfix/mysql-virtual-mailbox-maps.cf echo "query = SELECT 'ignored by postfix' FROM mailbox WHERE email='%s' AND active=1" >> /etc/postfix/mysql-virtual-mailbox-maps.cfecho "user = postfixuser" > /etc/postfix/mysql-virtual-alias-domains.cf echo "password = postfixpass" >> /etc/postfix/mysql-virtual-alias-domains.cf echo "hosts = localhost" >> /etc/postfix/mysql-virtual-alias-domains.cf echo "dbname = postfix" >> /etc/postfix/mysql-virtual-alias-domains.cf echo "query = SELECT 'ignored by postfix' FROM alias_domains WHERE domain='%s' AND active=1" >> /etc/postfix/mysql-virtual-alias-domains.cfecho "user = postfixuser" > /etc/postfix/mysql-virtual-alias-maps.cf echo "password = postfixpass" >> /etc/postfix/mysql-virtual-alias-maps.cf echo "hosts = localhost" >> /etc/postfix/mysql-virtual-alias-maps.cf echo "dbname = postfix" >> /etc/postfix/mysql-virtual-alias-maps.cf echo "query = SELECT goto FROM alias WHERE address='%s' AND active=1" >> /etc/postfix/mysql-virtual-alias-maps.cfecho "user = postfixuser" > /etc/postfix/mysql-client-access.cf echo "password = postfixpass" >> /etc/postfix/mysql-client-access.cf echo "hosts = localhost" >> /etc/postfix/mysql-client-access.cf echo "dbname = postfix" >> /etc/postfix/mysql-client-access.cf echo "query = SELECT response FROM client_access WHERE client = '%s' AND active=1" >> /etc/postfix/mysql-client-access.cfecho "user = postfixuser" > /etc/postfix/mysql-sender-access.cf echo "password = postfixpass" >> /etc/postfix/mysql-sender-access.cf echo "hosts = localhost" >> /etc/postfix/mysql-sender-access.cf echo "dbname = postfix" >> /etc/postfix/mysql-sender-access.cf echo "query = SELECT response FROM sender_access WHERE sender = '%s' AND active=1" >> /etc/postfix/mysql-sender-access.cfecho "user = postfixuser" > /etc/postfix/mysql-recipient-access.cf echo "password = postfixpass" >> /etc/postfix/mysql-recipient-access.cf echo "hosts = localhost" >> /etc/postfix/mysql-recipient-access.cf echo "dbname = postfix" >> /etc/postfix/mysql-recipient-access.cf echo "query = SELECT response FROM recipient_access WHERE recipient = '%s' AND active=1" >> /etc/postfix/mysql-recipient-access.cf#THIS IS A WORKAROUND TO ALLOW US TO USE CATCHALL ENTRIES IN THE VIRTUAL ALIAS MAPS. # # This issue is that Postfix will process all the alias entries before looking at the # virtual mailbox maps. Thus if you add a catchall entry for a virtual mailbox domain, # the catchall will grab all mail, and no mail will go to the virtual mailboxes. # # The only solution for virtual mailbox domains that have a catchall, is to populate # all the mailbox addresses into the alias table as well. The mailbox entries need to # be pointed back to themselves eg # # ADDRESS GOTO # user1@domain -> user1@domain # user2@domain -> user2@domain # @domain -> somewhere # # However we don't want to pollute our alias table with all these workaround records, # so we will define a lookup now that lets Postfix do the work for us. Then we modify # main.cf so that virtual_alias_maps changes from this : # # virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual-alias-maps.cf # # to this : # # virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual-alias-maps.cf, # proxy:mysql:/etc/postfix/mysql-virtual-mailbox-to-alias-maps.cf # # NOTE: I "stole" this workaround from # http://workaround.org/articles/ispmail-sarge/#mysql-virtual_email2email.cf # echo "user = postfixuser" >> /etc/postfix/mysql-virtual-mailbox-to-alias-maps.cf echo "password = postfixpass" >> /etc/postfix/mysql-virtual-mailbox-to-alias-maps.cf echo "hosts = localhost" >> /etc/postfix/mysql-virtual-mailbox-to-alias-maps.cf echo "dbname = postfix" >> /etc/postfix/mysql-virtual-mailbox-to-alias-maps.cf echo "query = SELECT email FROM mailbox WHERE email='%s' AND active=1" >> /etc/postfix/mysql-virtual-mailbox-to-alias-maps.cf# these files contain our database username/password, so tighten the security a bit chown root.postfix /etc/postfix/mysql-*.cf chmod 640 /etc/postfix/mysql-*.cf
Now we need to populate the mynetworks file. This file lists the IPs that are able to "relay" mail through your server. We put localhost into this file, so that scripts running on this server can relay mail to the internet. If you have workstations on a LAN, or other users on the internet with fixed-ip addresses, you can add them here as well, and these users will then be permitted to relay mail. For all other users who have mailboxes on your server, when sending mail they can either use SMTP-AUTH, or alternatively they could set their email client's SMTP server settings to point to their ISP's mail server.
echo '# Localhost' > /etc/postfix/mynetworks echo '127.0.0.0/8' >>/etc/postfix/mynetworks echo '' >>/etc/postfix/mynetworks echo '# MyCompany blocks' >>/etc/postfix/mynetworks echo 'xxx.xxx.xxx.xxx/24' >>/etc/postfix/mynetworks echo 'yyy.yyy.yyy.yyy/24' >>/etc/postfix/mynetworks
Double check that syslog is configured not to fsync after every output to maillog ( as this would bog server down badly )
vi /etc/syslog.conf-/var/log/maillog
Create a init script for postfix
echo '#!/bin/bash' > /etc/rc.d/init.d/postfix echo '#' >> /etc/rc.d/init.d/postfix echo '# postfix Postfix Mail Transfer Agent' >> /etc/rc.d/init.d/postfix echo '#' >> /etc/rc.d/init.d/postfix echo '# chkconfig: 2345 80 30' >> /etc/rc.d/init.d/postfix echo '# description: Postfix is a Mail Transport Agent, which is the program \' >> /etc/rc.d/init.d/postfix echo '# that moves mail from one machine to another.' >> /etc/rc.d/init.d/postfix echo '# processname: master' >> /etc/rc.d/init.d/postfix echo '# pidfile: /var/spool/postfix/pid/master.pid' >> /etc/rc.d/init.d/postfix echo '# config: /etc/postfix/main.cf' >> /etc/rc.d/init.d/postfix echo '# config: /etc/postfix/master.cf' >> /etc/rc.d/init.d/postfix echo '#' >> /etc/rc.d/init.d/postfix echo '# Source function library.' >> /etc/rc.d/init.d/postfix echo '. /etc/rc.d/init.d/functions' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo '# Source networking configuration.' >> /etc/rc.d/init.d/postfix echo '. /etc/sysconfig/network' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo '# Check that networking is up.' >> /etc/rc.d/init.d/postfix echo '[ ${NETWORKING} = "no" ] && exit 0' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo '[ -x /usr/sbin/postfix ] || exit 0' >> /etc/rc.d/init.d/postfix echo '[ -d /etc/postfix ] || exit 0' >> /etc/rc.d/init.d/postfix echo '[ -d /var/spool/postfix ] || exit 0' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'RETVAL=0' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'start() {' >> /etc/rc.d/init.d/postfix echo ' # Start daemons.' >> /etc/rc.d/init.d/postfix echo ' echo -n $"Starting postfix: "' >> /etc/rc.d/init.d/postfix echo ' alias_database=$(postconf -h alias_database 2>/dev/null)' >> /etc/rc.d/init.d/postfix echo ' RETVAL=$?' >> /etc/rc.d/init.d/postfix echo ' if [ $RETVAL -ne 0 ]; then' >> /etc/rc.d/init.d/postfix echo ' failure $"determination of alias_database"' >> /etc/rc.d/init.d/postfix echo ' echo' >> /etc/rc.d/init.d/postfix echo ' return 0' >> /etc/rc.d/init.d/postfix echo ' fi' >> /etc/rc.d/init.d/postfix echo ' if [ -n "$alias_database" ]; then' >> /etc/rc.d/init.d/postfix echo ' /usr/sbin/postalias ${alias_database//,} 2>/dev/null' >> /etc/rc.d/init.d/postfix echo ' RETVAL=$?' >> /etc/rc.d/init.d/postfix echo ' if [ $RETVAL -ne 0 ]; then' >> /etc/rc.d/init.d/postfix echo ' failure $"postalias $alias_database"' >> /etc/rc.d/init.d/postfix echo ' echo' >> /etc/rc.d/init.d/postfix echo ' return 0' >> /etc/rc.d/init.d/postfix echo ' fi' >> /etc/rc.d/init.d/postfix echo ' fi' >> /etc/rc.d/init.d/postfix echo ' /usr/sbin/postfix start 2>/dev/null 1>&2 && success || failure $"postfix start"' >> /etc/rc.d/init.d/postfix echo ' RETVAL=$?' >> /etc/rc.d/init.d/postfix echo ' [ $RETVAL -eq 0 ] && touch /var/lock/subsys/postfix' >> /etc/rc.d/init.d/postfix echo ' echo' >> /etc/rc.d/init.d/postfix echo ' return $RETVAL' >> /etc/rc.d/init.d/postfix echo '}' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'stop() {' >> /etc/rc.d/init.d/postfix echo ' # Stop daemons.' >> /etc/rc.d/init.d/postfix echo ' echo -n $"Shutting down postfix: "' >> /etc/rc.d/init.d/postfix echo ' /usr/sbin/postfix stop 2>/dev/null 1>&2 && success || failure $"postfix stop"' >> /etc/rc.d/init.d/postfix echo ' RETVAL=$?' >> /etc/rc.d/init.d/postfix echo ' [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/postfix' >> /etc/rc.d/init.d/postfix echo ' echo' >> /etc/rc.d/init.d/postfix echo ' return $RETVAL' >> /etc/rc.d/init.d/postfix echo '}' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'reload() {' >> /etc/rc.d/init.d/postfix echo ' echo -n $"Reloading postfix: "' >> /etc/rc.d/init.d/postfix echo ' /usr/sbin/postfix reload 2>/dev/null 1>&2 && success || failure $"postfix reload"' >> /etc/rc.d/init.d/postfix echo ' RETVAL=$?' >> /etc/rc.d/init.d/postfix echo ' echo' >> /etc/rc.d/init.d/postfix echo ' return $RETVAL' >> /etc/rc.d/init.d/postfix echo '}' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'abort() {' >> /etc/rc.d/init.d/postfix echo ' /usr/sbin/postfix abort 2>/dev/null 1>&2 && success || failure $"postfix abort"' >> /etc/rc.d/init.d/postfix echo ' return $?' >> /etc/rc.d/init.d/postfix echo '}' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'flush() {' >> /etc/rc.d/init.d/postfix echo ' /usr/sbin/postfix flush 2>/dev/null 1>&2 && success || failure $"postfix flush"' >> /etc/rc.d/init.d/postfix echo ' return $?' >> /etc/rc.d/init.d/postfix echo '}' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'check() {' >> /etc/rc.d/init.d/postfix echo ' /usr/sbin/postfix check 2>/dev/null 1>&2 && success || failure $"postfix check"' >> /etc/rc.d/init.d/postfix echo ' return $?' >> /etc/rc.d/init.d/postfix echo '}' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'restart() {' >> /etc/rc.d/init.d/postfix echo ' stop' >> /etc/rc.d/init.d/postfix echo ' start' >> /etc/rc.d/init.d/postfix echo '}' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo '# See how we were called.' >> /etc/rc.d/init.d/postfix echo 'case "$1" in' >> /etc/rc.d/init.d/postfix echo ' start)' >> /etc/rc.d/init.d/postfix echo ' start' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' stop)' >> /etc/rc.d/init.d/postfix echo ' stop' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' restart)' >> /etc/rc.d/init.d/postfix echo ' stop' >> /etc/rc.d/init.d/postfix echo ' start' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' reload)' >> /etc/rc.d/init.d/postfix echo ' reload' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' abort)' >> /etc/rc.d/init.d/postfix echo ' abort' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' flush)' >> /etc/rc.d/init.d/postfix echo ' flush' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' check)' >> /etc/rc.d/init.d/postfix echo ' check' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' status)' >> /etc/rc.d/init.d/postfix echo ' status master' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' condrestart)' >> /etc/rc.d/init.d/postfix echo ' [ -f /var/lock/subsys/postfix ] && restart || :' >> /etc/rc.d/init.d/postfix echo ' ;;' >> /etc/rc.d/init.d/postfix echo ' *)' >> /etc/rc.d/init.d/postfix echo ' echo $"Usage: postfix {start|stop|restart|reload|abort|flush|check|status|condrestart}"' >> /etc/rc.d/init.d/postfix echo ' exit 1' >> /etc/rc.d/init.d/postfix echo 'esac' >> /etc/rc.d/init.d/postfix echo ' ' >> /etc/rc.d/init.d/postfix echo 'exit $?' >> /etc/rc.d/init.d/postfixchmod 744 /etc/rc.d/init.d/postfix chkconfig --add postfix
Create the vmail tree
mkdir /var/vmail chown vmail.vmail /var/vmail
Tweak the aliases file. These mappings are used for system related mails eg crontab messages, postfix bounces etc. <username@mail.yourdomain.com>
vi /etc/aliasesroot: someone@yourdomain.comnewaliases
Try starting Postfix
/etc/rc.d/init.d/postfix startIf all goes well, you should be able to run "ps axf" see something like :
7184 ? Ss 0:00 /usr/libexec/postfix/master 7185 ? S 0:00 \_ pickup -l -t fifo -u 7186 ? S 0:00 \_ qmgr -l -t fifo -uAlso, you should take a look in the maillog file to see if any errors are being reported there
tail -f /var/log/maillog
Disable logwatch script from reporting on Postfix logs
The logwatch script runs nightly, and emails a report to the root user Unless your server is very low volume, I would recommend you tell logwatch not to report postfix stats, otherwise the report gets much too big
vi /etc/log.d/conf/logwatch.conf# Look for where it says "Service = All" and underneath that add this line : Service = -postfix
We want to have a 2nd IP address so that we can keep our MX-traffic separate from our customer-SMTP traffic
Customers will use the "mail.yourdomain.com" (192.168.1.10) name in their mail client's SMTP server settings, but in our zone files we will point the primary MX records to a different hostname such as "mail-mx.yourdomain.com" (192.168.1.11)
Having two interfaces allows us to set the Postfix MX concurrency to something sensibly low (to prevent a spam influx from overloading our server), while at the same time we can retain a high concurrency on the customer-SMTP settings so that our users don't ever see a connection-refused error
Let's assume our network interface is eth0. Then there is a file /etc/sysconfig/network-scripts/ifcfg-eth0 which looks like this:
DEVICE=eth0 BOOTPROTO=static BROADCAST=192.168.1.255 IPADDR=192.168.1.10 NETMASK=255.255.255.0 NETWORK=192.168.1.0 ONBOOT=yes TYPE=Ethernet
Now we want to create the virtual interface eth0:0 with the IP address 192.168.0.101. All we have to do is to create the file /etc/sysconfig/network-scripts/ifcfg-eth0:0 which looks like this:
DEVICE=eth0:0 BOOTPROTO=static BROADCAST=192.168.1.255 IPADDR=192.168.1.11 NETMASK=255.255.255.0 NETWORK=192.168.1.0 ONBOOT=yes TYPE=Ethernet
Once that has been done, you have to restart the network for the changes to take effect
/etc/rc.d/init.d/network restart
If you then run ifconfig, you should see something like this :
eth0 Link encap:Ethernet HWaddr 00:07:E9:4B:AD:83 inet addr:192.168.1.10 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:28442 errors:0 dropped:0 overruns:0 frame:0 TX packets:28385 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:14081755 (13.4 MiB) TX bytes:4847753 (4.6 MiB) eth0:0 Link encap:Ethernet HWaddr 00:07:E9:4B:AD:83 inet addr:192.168.1.11 Bcast:192.168.1.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:30 errors:0 dropped:0 overruns:0 frame:0 TX packets:30 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:2190 (2.1 KiB) TX bytes:2190 (2.1 KiB)
Tell Postfix which IP does what :
vi /etc/postfix/master.cf
# Change this :
smtp inet n - n - - smtpd# to this :
127.0.0.1:smtp inet n - n - 10 smtpd 192.168.1.10:smtp inet n - n - 100 smtpd 192.168.1.11:smtp inet n - n - 50 smtpd-mx -o smtpd_sasl_auth_enable=nocd /usr/libexec/postfix ln -s smtpd smtpd-mx
Notes :
Our MX concurrency has been set to a lower value (50) than our customer-SMTP concurrency (100). You can tweak the these values up/down (particularly the MX concurrency) to suit your server's power / load. For a small server I would recommend the SMTP-MX concurrency be set to something like 25. For a medium server you can set it to something like 50, for a large server you will need to use 100+.
We have created a new application-name called smtpd-mx. This is just a cosmetic tweak, so that when you are running commands like pstree, you can easily see exactly how many sessions of MX and customer-SMTP you have running :-)
For the smtpd-mx service, we have used a configuration option to disable SASL ( SMTP-AUTH ). In most scenarios, there is no need to have SMTP-AUTH enabled for MX traffic - disabling it will save some resources.
Also note that you might like to add additional IPs to the server as well (eth0:1 eth0:2 etc), one for each virtual domain you host. As this opens up options for other config tweaks which will be discussed later in this document. Eg setting a default pop3/imap smtp-auth ftp sqwebmail domain per hostname, and also allowing Postfix to attach one SSL cert per hostname.
Add entries to your reverse DNS
For each IP address, you need to make sure you have added a reverse DNS entry. If you fail to do this you might find your server is blocked by some mail servers. eg :
$ORIGIN 1.168.192.in-addr.arpa. 10 PTR mail.yourdomain.com. 11 PTR mail-mx.yourdomain.com.
http://sqlgrey.sourceforge.net/
Greylisting provides excellent protection against spammers, at the expense of slightly delaying some mail deliveries
Install the prerequisite Perl modules
perl -MCPAN -e shell# press enter through all the questions until you come to the region selections # At that point you will need to choose your preferred mirrorso conf prerequisites_policy follow install MD5 LWP Net::Server IO::Multiplex DBD::mysqlquit
Create the user account
groupadd sqlgrey useradd -r -m -g sqlgrey sqlgrey
Download and unpack the sources
cd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/sqlgrey/sqlgrey-1.6.7.tar.bz2 tar xjf sqlgrey-1.6.7.tar.bz2 chown -R root.root sqlgrey-1.6.7 cd sqlgrey-1.6.7
Create the MySQL database
mysqlCREATE DATABASE sqlgrey; GRANT ALL ON sqlgrey.* to sqlgrey@localhost; quit
( SQLgrey program will auto create its tables for us on startup )
Install the binaries and config files
make install# installed to /usr/sbin by default, I prefer to have them in /usr/local/sbin mv /usr/sbin/sqlgrey /usr/local/sbin mv /usr/sbin/update_sqlgrey_config /usr/local/sbin mv /usr/bin/sqlgrey-logstats.pl /usr/local/sbin# create the files that can be used for storing local whitelist entries touch /etc/sqlgrey/clients_ip_whitelist.local touch /etc/sqlgrey/clients_fqdn_whitelist.local
Make the following changes to the config file
vi /etc/sqlgrey/sqlgrey.confreconnect_delay = 1awl_age = 32 group_domain_level = 10db_type = mysqloptmethod = optoutadmin_mail = someadmin@yourdomain.com
TIP : If your are building a big/busy server you might like to reduce the amount of logging generated by sqlgrey by adjusting these settings :
loglevel = 1 log_override = conf:2
Install the init script
cp init/sqlgrey /etc/rc.d/init.d/sqlgreyvi /etc/rc.d/init.d/sqlgrey#go to the start section, and change the sqlgrey -d command to include the full path /usr/local/sbin/sqlgrey -d#go to the stop section, and change the sqlgrey -k command to include the full path /usr/local/sbin/sqlgrey -kchkconfig --add sqlgrey chkconfig sqlgrey on
Start the program
/etc/rc.d/init.d/sqlgrey startIf all goes well, ps axf should should show you something like this :
1898 ? Ss 0:00 /usr/bin/perl -w /usr/local/sbin/sqlgrey -d
Tweak the Postfix config, so incoming external mail gets routed via the greylisting daemon. ( You need to add the line shown in bold text )
vi /etc/postfix/main.cfreject_rbl_client list.dsbl.org, reject_rbl_client sbl-xbl.spamhaus.org, check_policy_service inet:127.0.0.1:2501, permitpostfix reload
Setup auto-downloading of rules. These will be stored into the clients_ip_whitelist and clients_fqdn_whitelist files.
crontab -e# download sqlgrey rules 0 0 * * * /usr/local/sbin/update_sqlgrey_config
For your local users who want to opt-out of the greylisting, you simply add their email address to the optout_email table :
mysqlUSE sqlgrey; -- this user wants to opt out INSERT INTO optout_email (email) VALUES ('someuser@somedomain.com'); -- all users on this domain want to opt out INSERT INTO optout_domain (domain) VALUES ('somedomainother.com'); quit
To reduce the load on your database server, you can put the most common hosts into the clients_ip_whitelist.local files. You can use sqlgrey-logstats.pl tool to extract this info from your logs.
If you have got secondary MX servers setup for your domain, you need to install SQLgrey on the secondary MX machines as well. Don't forget to put the secondary MX server IP's into the primary MX's clients_ip_whitelist.local file.
eg :
echo "*.yourdomain.com" > /etc/sqlgrey/clients_fqdn_whitelist.local echo "192.168" > /etc/sqlgrey/clients_ip_whitelist.local
Courier-authlib provides user authentication services to Courier-IMAP, Courier-POP3d, and SqWebMail
Install the prerequisites
yum install expect# This next one isnt used by authlib, but are used by several of the other courier tools # like maildrop and Courier-IMAP yum install gamin-devel
Download and unpack the sources
cd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/courier/courier-authlib-0.59.3.tar.bz2tar xjf courier-authlib-0.59.3.tar.bz2 chown -R root.root courier-authlib-0.59.3 cd courier-authlib-0.59.3
Configure, compile, install
./configure \ --prefix=/usr/local/courier-authlib \ --without-ipv6 \ --disable-root-check \ --without-authpwd \ --without-authshadow \ --without-authuserdb \ --without-authpgsql \ --without-authldap \ --without-authvchkpw \ --without-authcustom \ --without-authpam \ --without-authpipe \ --with-authmysql \ --with-authdaemon \ --with-redhatmake make check make install make install-configure
Tweak the config file so that courier-authlib can access the info from our database
vi /usr/local/courier-authlib/etc/authlib/authmysqlrcMYSQL_SERVER localhost MYSQL_USERNAME postfixuser MYSQL_PASSWORD postfixpass MYSQL_SOCKET /var/lib/mysql/mysql.sock MYSQL_PORT 0 MYSQL_OPT 0 MYSQL_DATABASE postfix MYSQL_USER_TABLE mailbox MYSQL_CRYPT_PWFIELD password MYSQL_CLEAR_PWFIELD clear_password #you can optionally enable this next setting if you want a particular domain to be appended #when users haven't specified a domain during authentication #DEFAULT_DOMAIN yourdomain.com MYSQL_UID_FIELD '1001' MYSQL_GID_FIELD '1001' MYSQL_LOGIN_FIELD email MYSQL_HOME_FIELD '/var/vmail' MYSQL_NAME_FIELD name MYSQL_MAILDIR_FIELD CONCAT(maildir,"Maildir/") MYSQL_QUOTA_FIELD CONCAT(mailquota*1024*1024,"S") MYSQL_AUXOPTIONS_FIELD CONCAT("disableimap=",disableimap,",disablepop3=",disablepop3,",disablewebmail=",disablewebmail) MYSQL_WHERE_CLAUSE active='1'
Tweak the config to disable some unneeded features
vi /usr/local/courier-authlib/etc/authlib/authdaemonrc#if your server is going to be very busy, you might need to increase this one daemons=5# Disable some unneeded functionality. # (Note that these could optionally be re-enabled per-user by adding appropriate columns to the mailbox database) # # wbnochangepass : In our case the postfix MySQL database will be maintained by our billing system, so although # sqwebmail has functionality to allow users to can change their passwords, these changes would # be overwritten by the billing system... So we will turn that option off # wbusexsender : Include an X-Sender header to all outgoing mail ( allows you to track actual sender, even if # user has altered their From address in sqwebmail ) # disableshared : We don't want shared folders, as this mail server is going to be used in ISP rather than corporate scenario # webnodsn : Hide the option " DEFAULTOPTIONS="wbnochangepass=1,wbusexsender=1,disableshared=1,wbnodsn=1"
Install the init script
cp courier-authlib.sysvinit /etc/rc.d/init.d/courier-authlib chmod 744 /etc/rc.d/init.d/courier-authlib chkconfig --add courier-authlib
Start the daemon
/etc/rc.d/init.d/courier-authlib startps axf should give something like this :
1515 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger -pid=/usr/local/courier-authlib/var/spool/authdaemon/pid -s 1516 ? S 0:00 \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond 1517 ? S 0:00 \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond 1518 ? S 0:00 \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond 1519 ? S 0:00 \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond 1520 ? S 0:00 \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond 1521 ? S 0:00 \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond
TROUBLESHOOTING TIP :
Courier-authlib includes a couple of debugging tools. These can be handy if you are having problems eg auth'ing via POP3, but aren't sure if its your POP3 config that's broken or whether its actually the courier-authlib that's not working properly.
# display all accounts /usr/local/courier-authlib/sbin/authenumerate# perform a test authentication, and show all values returned from courier-authlib /usr/local/courier-authlib/sbin/authtest someuser@yourdomain.com somepassword
Maildrop provides Postfix with a Maildir++ softquota-compatible way to deliver mail into user's mailboxes.
Note : Instead of using maildrop, many people use the "Postfix VDA" patch instead. This patch hacks the Postfix virtual delivery agent to (supposedly) support Maildir++ softquotas. However I would strongly recommend you don't use that patch! The doco etc for the patch makes it sounds like it does everything you need. However when you actually inspect the code it is a total debacle zone. There are numerous logic errors - the patch fails to follow the Maildir++ specs, and will cause a ridiculous amount of needless load on your server. Maildrop does everything correctly, doesn't require the Postfix source code to be patched ( which is good for Postfix's security/reliability ), and gives additional features like quota warnings. Maildrop also has the huge bonus of being from the same author as Courier-imap/pop3d/sqwebmail so you are guaranteed excellent interoperability between all your tools that touch the Maildir
Download and unpack the sources
cd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/courier/maildrop-2.0.4.tar.bz2tar xjf maildrop-2.0.4.tar.bz2 chown -R root.root maildrop-2.0.4 cd maildrop-2.0.4
Configure, compile, install
COURIERAUTHCONFIG=/usr/local/courier-authlib/bin/courierauthconfig \ CPPFLAGS=-I/usr/local/courier-authlib/include \ ./configure \ --enable-smallmsg=262144 \ --enable-maildirquotamake make install-strip make install-man
TIP: if you read the Maildrop docs, there is a configure option "--without-db" which sounds quite desirable. However its not a good idea to use that option because it will prevent some of the Maildrop autoresponder functionality from working properly.
Configure maildrop binary to have siud root. It needs root permissions to be able to connect to the Courier-authlib socket. It drops root permissions as soon as it determines the final account user and group id. ( You cant just go and grant world permissions on the socket, as this would allow anyone on the system to obtain any account's password ).
chmod u+s /usr/local/bin/maildrop
Setup automatic quota warnings
When you use the -w option with maildrop, it enables the sending of quota warning messages. The warning message is copied verbatim from /usr/local/etc/quotawarnmsg with the addition of the "Date:" and "Message-Id:" headers. The warning is repeated every 24 hours (at least), until the Maildir drops below X percent full.
cp maildir/quotawarnmsg /usr/local/etcvi /usr/local/etc/quotawarnmsg# tweak wording to suit your needsvi /etc/postfix/master.cf# Maildrop will use courier-authlib to lookup account data for the user specified in the -d option. # # The example here tells Postfix to launch a maximum of 10 simultaneous mailbox processes. # You might need to tweak this depending on how busy your server is. A higher number will # tell Postfix to try to deliver more messages per second, but setting the value too high can # cause problems if you run out of disk I/O. I would recommend setting this concurrency value # to 5 for a small server, 10 for medium, and 20 for large. # maildrop unix - n n - 10 pipe flags=DRhu user=vmail argv=/usr/local/bin/maildrop -w 80 -d ${recipient}postfix reload
Optionally can configure some global maildrop rules
vi /etc/maildroprc
# You can uncomment this next line if you want some debugging output. # Useful if you are doing some tweaking to try and get mail deliveries to follow # some more sophisticated rulesets. # #logfile "/var/log/maildroprc.log"# Per-user .mailfilter files are installed (eg by sqwebmail) into the user's home dir # at /var/vmail/yourdomain.com/u/user1/.mailfilter # # When maildrop runs, it is coded to look for any global rules in : /etc/maildroprc # and then next will look for any per-user rules in : $HOME/.mailfilter # # However, with a vmail style config we have a problem... $HOME doesn't point to a # per-user location. On a machine with all the accounts in /etc/passwd, $HOME would # point to the right place, but vmail systems are different because they host all the # mailboxes under a single UID. # # When postfix calls maildrop to perform a message delivery, # $HOME will contain the vmail home : /var/vmail # $DEFAULT will contain the path to the maildir eg : yourdomain.com/u/user1/Maildir # # So to allow us to still run per-user rules, we will add an INCLUDE command in # the global file so that we can still pick up any per-user filtering rules. ## if the user has a .mailfilter file, then execute it's contents now exception { include "$HOME/$DEFAULT/../.mailfilter" }
TIP : If you need to do some debugging of maildrop you can run it from the command prompt with verbose logging enabled. This will identify if its talking to the database successfully, and will also show up if there are permissions problems etc on the destination dir :
[root@mail01 ~]# maildrop -V9 -d someone@yourdomain.com maildrop: authlib: groupid=1001 maildrop: authlib: userid=1001 maildrop: authlib: logname=someone@yourdomain.com, home=/var/vmail, mail=yourdomain.com/s/someone/Maildir/ maildrop: Changing to /var/vmail<press CTRL-D here>
http://www.courier-mta.org/imap/
Download and unpack the sources
cd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/courier/courier-imap-4.1.3.tar.bz2tar xjf courier-imap-4.1.3.tar.bz2 chown -R root.root courier-imap-4.1.3 cd courier-imap-4.1.3
Configure, compile, install the program
COURIERAUTHCONFIG=/usr/local/courier-authlib/bin/courierauthconfig \ CPPFLAGS=-I/usr/local/courier-authlib/include \ ./configure \ --without-ipv6 \ --prefix=/usr/local/courier-imap \ --disable-root-check \ --with-redhatmake make install make install-configure
Appropriately tweak the config files
vi /usr/local/courier-imap/etc/imapd# If you are going to run a busy IMAP-based webmail package, you will need to substantially increase this. # The default value of 4 is insufficient even for servicing individual users, since clients like Thunderbird default to using up to 5 simultaneous connections # MAXPERIP=20# Add our collection of supported auth methods to the advertised capability string IMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA AUTH=CRAM-MD5 AUTH=CRAM-SHA1 AUTH=PLAIN AUTH=LOGIN IDLE"# we want to turn off the announcement of IMAP ACL extensions, as we dont need this ( we arent using shared folders ), # and the ACL stuff makes Thunderbird spit errors in some cases IMAP_ACL=0IMAP_CAPABILITY_TLS="$IMAP_CAPABILITY"# Enabled the enhanced IDLE functionality # This allows the IMAP server to notify your client when something has changed (eg a new message has arrived) IMAP_ENHANCEDIDLE=1# If you were going to have mainly Outlook Express based IMAP users, you can tell Courier-IMAP to name the trash folder "Deleted Items" # However in our case we are expecting most IMAP users to be webmail, so sticking with the default "Trash" foldername is probably best. #IMAP_TRASHFOLDERNAME="Deleted Items" #IMAP_EMPTYTRASH="Deleted Items":7# Enable the Courier-IMAP daemon IMAPDSTART=YESvi /usr/local/courier-imap/etc/imapd-ssl# enable courier-imaps (port 993) daemon IMAPDSSLSTART=YES# enable STARTTLS extensions for IMAP. Enabling this means "STARTTLS" will be added to the IMAP CAPABILITY line IMAPDSTARTTLS=YES# nominate where the SSL key/certificate can be found TLS_CERTFILE=/usr/local/ssl/mail.yourdomain.com.pemvi /usr/local/courier-imap/etc/pop3d# you would likely have to increase this for a busy server MAXDAEMONS=40# Add out collection of supported auth methods to the advertised capability string POP3AUTH="CRAM-MD5 CRAM-SHA1 PLAIN LOGIN"POP3AUTH_TLS="$POP3AUTH"# enabled the courier-pop3 daemon POP3DSTART=YESvi /usr/local/courier-imap/etc/pop3d-ssl# enable the courier-pop3s (port 995) daemon POP3DSSLSTART=YES# enable STARTTLS extensions for POP3. POP3_STARTTLS=YES# nominate where the SSL key/certificate can be found TLS_CERTFILE=/usr/local/ssl/mail.yourdomain.com.pem
Setup the init script
cp courier-imap.sysvinit /etc/rc.d/init.d/courier-imap chmod 744 /etc/rc.d/init.d/courier-imap chkconfig --add courier-imap
Create an empty shared folder index file, to prevent Courier-IMAP from complaining to syslog about it being missing. We aren't using shared folders at all on this server.
touch /usr/local/courier-imap/etc/shared/index
Start the daemons
/etc/rc.d/init.d/courier-imap startps axf should give something like this
14611 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger -pid=/var/run/imapd.pid -start -name=imapd /usr/local/couri 14612 ? S 0:00 \_ /usr/local/courier-imap/libexec/couriertcpd -address=0 -maxprocs=40 -maxperip=4 -nodnslookup -noident 14618 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger -pid=/var/run/imapd-ssl.pid -start -name=imapd-ssl /usr/loc 14619 ? S 0:00 \_ /usr/local/courier-imap/libexec/couriertcpd -address=0 -maxprocs=40 -maxperip=4 -nodnslookup -noident 14624 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger -pid=/var/run/pop3d.pid -start -name=pop3d /usr/local/couri 14625 ? S 0:00 \_ /usr/local/courier-imap/libexec/couriertcpd -address=0 -maxprocs=40 -maxperip=4 -nodnslookup -noident 14630 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger -pid=/var/run/pop3d-ssl.pid -start -name=pop3d-ssl /usr/loc 14631 ? S 0:00 \_ /usr/local/courier-imap/libexec/couriertcpd -address=0 -maxprocs=40 -maxperip=4 -nodnslookup -noident[
Disable logwatch script from reporting on imap logs
The logwatch script runs nightly, and emails a report to the root user. Unless your server is very low volume, I would recommend you tell logwatch not to report imap stats, otherwise the report gets much too big
vi /etc/log.d/conf/logwatch.conf# Look for where it says "Service = All" and underneath that add this line : Service = -imapd
Create some directory structure
mkdir -p /var/www/mail/html mkdir /var/www/mail/cgi-bin mkdir /var/www/mail/logs
Remark out the following modules, which are part of the standard Apache installation, but we wont need. This will reduce the bulk of Apache, and in my experience will make it more stable
vi /etc/httpd/conf/httpd.conf#LoadModule auth_anon_module modules/mod_auth_anon.so #LoadModule auth_dbm_module modules/mod_auth_dbm.so #LoadModule auth_digest_module modules/mod_auth_digest.so #LoadModule ldap_module modules/mod_ldap.so #LoadModule auth_ldap_module modules/mod_auth_ldap.so #LoadModule cern_meta_module modules/mod_cern_meta.so #LoadModule headers_module modules/mod_headers.so #LoadModule usertrack_module modules/mod_usertrack.so #LoadModule dav_module modules/mod_dav.so #LoadModule status_module modules/mod_status.so #LoadModule asis_module modules/mod_asis.so #LoadModule info_module modules/mod_info.so #LoadModule dav_fs_module modules/mod_dav_fs.so #LoadModule speling_module modules/mod_speling.so #LoadModule proxy_module modules/mod_proxy.so #LoadModule proxy_ftp_module modules/mod_proxy_ftp.so #LoadModule proxy_http_module modules/mod_proxy_http.so #LoadModule proxy_connect_module modules/mod_proxy_connect.so #LoadModule cache_module modules/mod_cache.so #LoadModule disk_cache_module modules/mod_disk_cache.so #LoadModule file_cache_module modules/mod_file_cache.so #LoadModule mem_cache_module modules/mod_mem_cache.so
Add these commands to the bottom of the file so that Apache can serve sqwebmail pages
vi /etc/httpd/conf/httpd.confLogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_vhostNameVirtualHost *:80<VirtualHost *:80># The first vhost entry is used if no hostname matches are found amongst other vhost entries. # So lets pop a "default" entry here to send any such requests through to our corporate webpage ServerAdmin webmaster@yourdomain.com DocumentRoot /var/www/mail/html ServerName placeholder-for-no-vhost-match ErrorLog /var/www/mail/logs/error_log CustomLog /var/www/mail/logs/access_log combined_vhost RewriteEngine On RewriteRule .* http://www.yourdomain.com/ [R,L]</VirtualHost><VirtualHost *:80>ServerAdmin webmaster@yourdomain.com DocumentRoot /var/www/mail/html ServerName mail.yourdomain.com ServerAlias webmail.yourdomain.com ServerAlias mail.hosteddomain1.com.au webmail.hosteddomain1.com ServerAlias mail.hosteddomain2.com.au webmail.hosteddomain2.com ServerAlias mail.hosteddomain3.com.au webmail.hosteddomain3.com ServerAlias mail.hosteddomain4.com.au webmail.hosteddomain4.com ServerAlias mail.hosteddomain5.com.au webmail.hosteddomain5.comErrorLog /var/www/mail/logs/error_log CustomLog /var/www/mail/logs/access_log combined_vhostRewriteEngine on RewriteRule ^/index\.html$ http://%{HTTP_HOST}/cgi-bin/sqwebmailScriptAlias /cgi-bin/ "/var/www/mail/cgi-bin/"<Directory "/var/www/mail/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory>BrowserMatch "MSIE [45]" nokeepalive downgrade-1.0 force-response-1.0</VirtualHost>
vi /etc/httpd/conf.d/ssl.conf<VirtualHost _default_:443>ServerAdmin postmaster@yourdomain.com DocumentRoot /var/www/mail/htmlSSLCertificateFile /usr/local/ssl/mail.yourdomain.com.crt SSLCertificateKeyFile /usr/local/ssl/mail.yourdomain.com.keyErrorLog /var/www/mail/logs/ssl_error_logRewriteEngine On RewriteRule ^/index\.html$ http://mail.yourdomain.com/cgi-bin/sqwebmailScriptAlias /cgi-bin/ "/var/www/mail/cgi-bin/"<Directory "/var/www/mail/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory>SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown downgrade-1.0 force-response-1.0CustomLog /var/www/mail/logs/ssl_request_log "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"</VirtualHost>
Add some more directory structure to allow us to serve user homepages
mkdir -p /var/www/users/html mkdir /var/www/users/cgi-bin mkdir /var/www/users/logs
Add these commands so Apache can serve user pages. I would suggest you put in 1 VirtualHost entry per domain
vi /etc/httpd/conf/httpd.conf<VirtualHost *:80>ServerAdmin webmaster@yourdomain.com DocumentRoot /var/www/users/html ServerName users.yourdomain.com ServerAlias home.yourdomain.comErrorLog /var/www/users/logs/error_log CustomLog /var/www/users/logs/access_log combined_vhostDirectoryIndex index.html index.htm default.html default.htm RewriteEngine on RewriteRule ^/~([\w-_\.])([\w-_\.]*)/?(.*)$ /var/vmail/yourdomain.com/$1/$1$2/public_html/$3 [L] RewriteRule ^/index.html$ http://www.yourdomain.comphp_flag Engine Off<Directory /var/vmail/yourdomain.com/*/*/public_html> AllowOverride FileInfo AuthConfig Indexes Limit Options MultiViews Indexes IncludesNoExec Order allow,deny Allow from all </Directory>ScriptAlias /cgi-bin/ "/var/www/users/cgi-bin/" <Directory "/var/www/users/cgi-bin"> AllowOverride None Options None Order allow,deny Allow from all </Directory></VirtualHost>
Remove the default welcome page
vi /etc/httpd/conf.d/welcome.conf
#<LocationMatch "^/+$"> #Options -Indexes #ErrorDocument 403 /error/noindex.html #</LocationMatch>
Setup favicons
cd /var/www/mail/html wget http://www.yourdomain.com/favicon.icocd /var/www/users/html wget http://www.yourdomain.com/favicon.ico
Restart your apache :
/etc/rc.d/init.d/httpd restart
Setup log rotation for your httpd logs
vi /etc/logrotate.d/httpd# change line from this /var/log/httpd/*log { # to this /var/log/httpd/*log /var/www/mail/logs/*log /var/www/users/logs/*log {
http://www.courier-mta.org/sqwebmail/
Create the directory structure which will receive the sqwebmail png images, binary, and logs
mkdir -p /var/www/mail/html/images/sqwebmail mkdir -p /var/www/mail/cgi-bin mkdir -p /var/www/mail/logs
Create an advertising banner type script that will be used by the sqwebmail binary. The banner is displayed at the bottom of every page.
echo '#!/bin/sh' > /usr/local/bin/sqwebmail-banner.sh echo '##' >> /usr/local/bin/sqwebmail-banner.sh echo '## This progam is called by sqwebmail for each [#B#] tag in the html templates' >> /usr/local/bin/sqwebmail-banner.sh echo '## The ARGV[0] will be the name of the html template that launched the call' >> /usr/local/bin/sqwebmail-banner.sh echo '##' >> /usr/local/bin/sqwebmail-banner.sh echo 'echo "<center>";' >> /usr/local/bin/sqwebmail-banner.sh echo 'echo "<hr>";' >> /usr/local/bin/sqwebmail-banner.sh echo 'echo "<b>SomeISP support - call 1300 xxx xxx</b>";' >> /usr/local/bin/sqwebmail-banner.sh echo 'echo "</center>";' >> /usr/local/bin/sqwebmail-banner.sh chmod 755 /usr/local/bin/sqwebmail-banner.sh
Download and extract the sources
cd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/courier/sqwebmail-5.1.6.tar.bz2tar xjf sqwebmail-5.1.6.tar.bz2 chown -R root.root sqwebmail-5.1.6 cd sqwebmail-5.1.6
Configure and compile
COURIERAUTHCONFIG=/usr/local/courier-authlib/bin/courierauthconfig \ CPPFLAGS=-I/usr/local/courier-authlib/include \ ./configure \ --prefix=/usr/local/sqwebmail \ --disable-autorenamesent \ --enable-cgibindir=/var/www/mail/cgi-bin/ \ --enable-imagedir=/var/www/mail/html/images/sqwebmail/ \ --enable-imageurl=/images/sqwebmail \ --with-maxformargsize=17500000 \ --with-maxmsgsize=18000000 \ --enable-bannerprog=/usr/local/bin/sqwebmail-banner.shmake make install make install-configure
Allow sqwebmail users to use (maildrop) message filtering rules
vi /usr/local/sqwebmail/etc/maildirfilterconfigMAILDIRFILTER=../.mailfilter MAILDIR=$HOME/$DEFAULT
Configure sqwebmail to start at bootup (NEED TO WRITE AN PROPER SYSV-STYLE INIT SCRIPT)
vi /etc/rc.d/rc.local/usr/local/sqwebmail/libexec/sqwebmaild.rc start
Start the sqwebmail
/usr/local/sqwebmail/libexec/sqwebmaild.rc startIf all goes well, ps axf should give something like this
29727 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger -pid=/usr/local/sqwebmail/var/run/sqwebmaild.pid -start /us 29728 ? S 0:00 \_ /usr/local/sqwebmail/libexec/sqwebmail/sqwebmaild 29730 ? S 0:00 /usr/local/sqwebmail/libexec/sqwebmail/sqwebmaild 29732 ? S 0:00 /usr/local/sqwebmail/libexec/sqwebmail/sqwebmaild 29734 ? S 0:00 /usr/local/sqwebmail/libexec/sqwebmail/sqwebmaild 29736 ? S 0:00 /usr/local/sqwebmail/libexec/sqwebmail/sqwebmaild 29738 ? S 0:00 /usr/local/sqwebmail/libexec/sqwebmail/sqwebmaild
Sqwebmail has a cache, that requires old files to be zapped regularly
crontab -e# Purge sqwebmail cache files once per hour 0 * * * * /usr/local/sqwebmail/share/sqwebmail/cleancache.pl
Test access :
http://mail.yourdomain.com/
or
https://mail.yourdomain.com/
Customise the sqwebmail templates ( apply your own branding )
The ones I tweak are :
/usr/local/sqwebmail/share/sqwebmail/html/en/loginform.inc.html /var/www/mail/html/images/sqwebmail/sqwebmail.css
Install prerequisite modules
yum install bzip2-devel
Create the user/group for clamd to run under
groupadd -r clamav useradd -r -g clamav -d /var/amavis -m -s /bin/false -c "Clam AntiVirus" clamav
Download and extract the sources
cd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/clamav/clamav-0.90.2.tar.gztar xzf clamav-0.90.2.tar.gz chown -R root.root clamav-0.90.2 cd clamav-0.90.2
Configure and compile
./configure# TIP: on some platforms (Incl CentOS) you may have to use # ./configure --disable-zlib-vcheckmake make install# This next step is recommended by ClamAV authors after installing 0.90.1 ldconfig
Tweak the config files as shown below
ln -s /usr/local/etc/clamd.conf /etc/clamd.conf vi /etc/clamd.conf# Example LogSyslog yes LocalSocket /var/amavis/clamd.sock FixStaleSocket yes MaxThreads 10 User clamavln -s /usr/local/etc/freshclam.conf /etc/freshclam.conf vi /etc/freshclam.conf# Example LogSyslog yes DatabaseMirror db.au.clamav.net NotifyClamd /etc/clamd.conf
Setup the init scripts
cp contrib/init/RedHat/clamd /etc/rc.d/init.d/clamd chmod 744 /etc/rc.d/init.d/clamd chkconfig --add clamdvi /etc/rc.d/rc.local/usr/local/bin/freshclam -d
Start the daemons
/etc/rc.d/init.d/clamd start /usr/local/bin/freshclam -dps axf should give something like this :
11139 ? Ss 0:00 /usr/local/sbin/clamd 11142 ? Ss 0:00 /usr/local/bin/freshclam -d
http://spamassassin.apache.org/
Install the prerequisite perl modules
perl -MCPAN -e shello conf prerequisites_policy follow install LWP MD5 install Digest::SHA1 HTML::Parser Net::DNS MD5 HTTP::Date IO::Zlib Archive::Tar install MIME::Base64 DB_File Net::SMTP Mail::SPF Time::HiResquit
Download and unpack the sources
cd /usr/local/src wget http://apache.mirror.pacific.net.au/spamassassin/source/Mail-SpamAssassin-3.2.0.tar.gztar xzf Mail-SpamAssassin-3.2.0.tar.gz chown -R root.root Mail-SpamAssassin-3.2.0 cd Mail-SpamAssassin-3.2.0
Compile and install
perl Makefile.PL #[answer the questions] make make install
Setup the SpamAssassin config file. ( Note, this is a complete config file that can replace the default supplied one )
vi /etc/mail/spamassassin/local.cf## Enable auto-whitelisting use_auto_whitelist 1#### # WILL HAVE NO EFFECT. THE EQUIVALENT SETTINGS IN AMAVISD ARE THE ONES YOU NEED TO SET # # ## Required point score before considered spam # required_score 5 # # # ## What to tag the subject line with # rewrite_header Subject [SPAM] # # ## Put the report in the headers. Dont touch the body of the message at all # report_safe 0# Enable the Bayes system use_bayes 1 bayes_auto_learn 1 bayes_auto_learn_threshold_spam 10## Set headers which may provide inappropriate cues to the Bayesian ## classifier bayes_ignore_header X-Bogosity bayes_ignore_header X-Spam-Flag bayes_ignore_header X-Spam-Status## Enable or disable network checks skip_rbl_checks 0## File locking method. We dont need to worry about being NFS-safe lock_method flock## Give spamassassin some hints as to what IPs are under our control. ## Generally this will be a similar list to what you have put in the postfix mynetworks file trusted_networks 127.0.0.1 # needed so amavisd headers don't trip up spamassassin trusted_networks 192.168.1.0/24 # you need to include all the IPs your mail server, and local LAN workstation
http://www.ijs.si/software/amavisd/
Install some optional rpm's that will help amavisd inspect different types of attachments
# These are available via yum on Fedora, but not on CentOS yum install arc cabextract zoo lzop freeze
Install the prerequisite perl modules
perl -MCPAN -e shello conf prerequisites_policy follow install Archive::Zip Compress::Zlib Convert::TNEF Convert::UUlib MIME::Base64 MIME::Parser install Mail::Internet Net::Server Digest::MD5 IO::Stringy Time::HiRes Unix::Syslog BerkeleyDB install DBI DBD::mysqlquit
Download and unpack the sources
cd /usr/local/src wget http://www.ijs.si/software/amavisd/amavisd-new-2.5.0.tar.gztar xzf amavisd-new-2.5.0.tar.gz chown -R root.root amavisd-new-2.5.0 cd amavisd-new-2.5.0
Install the program
mkdir /var/amavis/tmp /var/amavis/var /var/amavis/db chown -R clamav.clamav /var/amavis chmod -R 750 /var/amaviscp amavisd /usr/local/sbin/ chown root /usr/local/sbin/amavisd chmod 755 /usr/local/sbin/amavisdcp amavisd.conf-sample /etc/amavisd.conf chown root /etc/amavisd.conf chmod 600 /etc/amavisd.conf
Make the following changes to the config file
vi /etc/amavisd.conf$mydomain = 'yourdomain.com'; $daemon_user = 'clamav'; $daemon_group = 'clamav';$TEMPBASE = "$MYHOME/tmp";$forward_method = 'smtp:[127.0.0.1]:10025'; $notify_method = $forward_method; $max_servers = 10; @local_domains_maps = ( [".$mydomain"] ); # # Normally we would want a list of local domains set here, # but when using SQL-based recipient lookups this isn't necessary. # Doco says : # A special shorthand is provided when SQL lookups are used: when a match # for recipient address (or domain) is found in SQL tables (regardless of # field values), the recipient is considered local, regardless of static # @local_comains_acl or %local_domains lookup tables. This simplifies # life when a large number of dynamically changing domains is hosted. # To overrule this behaviour, add an explicit boolean field 'local' # to table 'users' (missing field defaults to true, meaning record match # implies the recipient is local; a NULL field 'local' is not special, # it is interpreted as undef like other NULL fields, causing search # to continue into other lookup tables). # # On other (non-mysql) servers that I have built as antivirus/antispam front-ends # (which then onforward mail to server that has the mailboxes), I have used a setting like this : # @local_domains_maps = ("."); # consider all domains to be local$log_level = 1;$final_virus_destiny = D_DISCARD; $final_banned_destiny = D_BOUNCE; $final_spam_destiny = D_DISCARD;$virus_admin = undef; $spam_admin = undef;#$QUARANTINEDIR = '/var/virusmails';$virus_quarantine_to = undef; $bad_header_quarantine_to = undef; $banned_quarantine_to = undef; $spam_quarantine_to = undef;# qr'^\.(exe-ms|dll)$',# qr'^application/x-msdownload$'i, # qr'^application/x-msdos-program$'i,# qr'.\.(exe|vbs|pif|scr|cpl)$'i, # banned extension - basic qr'.\.(vbs|pif|scr|cpl)$'i, # banned extension - basic@spam_lovers_maps = ( ['postmaster@', 'abuse@'] );@lookup_sql_dsn = ( ['DBI:mysql:database=postfix;host=localhost', 'postfixuser', 'postfixpass'] ); $sql_select_policy = 'SELECT virus_lover, spam_lover, banned_files_lover, bad_header_lover, '. 'bypass_virus_checks, bypass_spam_checks, bypass_banned_checks, bypass_header_checks, '. 'spam_tag2_level, spam_kill_level FROM mailbox WHERE email IN (%k)'; $sql_select_white_black_list = undef; ## STILL NEED TO WORK OUT HOW TO IMPLEMENT THIS FEATURE
@whitelist_sender_maps = ( ['MAILER-DAEMON@', 'postmaster@'] );$sa_local_tests_only = 0; $sa_tag_level_deflt = undef; $sa_tag2_level_deflt = 5; $sa_kill_level_deflt = 10; $sa_dsn_cutoff_level = undef;$sa_spam_subject_tag = '[SPAM] '; $sa_spam_modifies_subj = 1;### http://www.clamav.net/ ['ClamAV-clamd', \&ask_daemon, ["CONTSCAN {}\n", "/var/amavis/clamd.sock"], qr/\bOK$/, qr/\bFOUND$/, qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],# invoke custom hooks #my($custom_config) = '/etc/amavisd-custom.conf'; #$! = 0; #if (!defined($custom_config)) {} #elsif (defined(do $custom_config)) {} # good, code successfully loaded #elsif ($@ ne '') { die "Error in config file \"$custom_config\": $@" } #elsif ($! != 0) { die "Error reading config file \"$custom_config\": $!" }
Install init scripts, and start the daemon
cp amavisd_init.sh /etc/rc.d/init.d/amavisd chown root.root /etc/rc.d/init.d/amavisd chmod 744 /etc/rc.d/init.d/amavisd chkconfig --add amavisdvi /etc/rc.d/init.d/amavisdprog="/usr/local/sbin/amavisd"/etc/rc.d/init.d/amavisd start
If all goes well, ps axf should show you something like this :
16534 ? Ss 0:00 amavisd (master) 16537 ? S 0:00 \_ amavisd (virgin child) 16538 ? S 0:00 \_ amavisd (virgin child) 16539 ? S 0:00 \_ amavisd (virgin child) 16540 ? S 0:00 \_ amavisd (virgin child) 16541 ? S 0:00 \_ amavisd (virgin child) 16542 ? S 0:00 \_ amavisd (virgin child) 16543 ? S 0:00 \_ amavisd (virgin child) 16544 ? S 0:00 \_ amavisd (virgin child) 16545 ? S 0:00 \_ amavisd (virgin child) 16546 ? S 0:00 \_ amavisd (virgin child)
Add these commands to tell Postfix to use Amavis for scanning
vi /etc/postfix/main.cfcontent_filter=smtp-amavis:[127.0.0.1]:10024 smtp-amavis_destination_concurrency_limit=10vi /etc/postfix/master.cfsmtp-amavis unix - - n - - lmtp -o lmtp_data_done_timeout=1200 -o lmtp_send_xforward_command=yes -o lmtp_connection_timeout=2 -o disable_dns_lookups=yes -o max_use=20127.0.0.1:10025 inet n - n - - smtpd-av -o content_filter= -o smtpd_restriction_classes= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o mynetworks=127.0.0.0/8 -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o smtpd_milters= -o local_header_rewrite_clients= -o local_recipient_maps= -o relay_recipient_maps= -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_address_mappingscd /usr/libexec/postfix ln -s smtpd smtpd-avpostfix reload
Disable logwatch script from reporting on amavisd logs
The logwatch script runs nightly, and emails a report to the root user Unless your server is very low volume, I would recommend you tell logwatch not to report amavisd stats, otherwise the report gets much too big
vi /etc/log.d/conf/logwatch.conf# Look for where it says "Service = All" and underneath that add this line : Service = -amavis
Pureftpd has been chosen because it supports MySQL and softquotas. The softquotas work in a similar way to the maildir++ quota system. But instead of the quotas being stored in a maildirsize file, they are stored in a file called ".ftpquota"
Download and unpack
cd /usr/local/src wget http://download.pureftpd.org/pub/pure-ftpd/releases/pure-ftpd-1.0.21.tar.gz tar xzf pure-ftpd-1.0.21.tar.gz chown -R root.root pure-ftpd-1.0.21 cd pure-ftpd-1.0.21
configure, compile, install
./configure \ --without-inetd \ --without-shadow \ --without-humor \ --without-usernames \ --with-boring \ --with-extauth \ --with-mysql \ --with-quotas \ --with-virtualchroot \ --with-cookie \ --with-tls \ --with-certfile=/usr/local/ssl/mail.yourdomain.com.pem# Note, the configure script will emit this warning :
# "configure: WARNING: No certificate is installed in /usr/local/ssl/mail.yourdomain.com.pem yet".
# However apon inspecting the source code it can be seen this is a bug. If the file exists it reports that warning,
# when it should actually report that warning if the file is missing. I have reported that bug to the pureftpd authors.
# They have acknowledged the bug and the fix will be included in v1.0.22
TIP : If you are using x86_64 platform ( eg Opteron ), you will have to modify your configure command to be : LDFLAGS=-L/usr/lib64/mysql \ ./configure \ --without-inetd \ ......etcmake make install-strip
Setup the config file by making these changes
cp pureftpd-mysql.conf /etcvi /etc/pureftpd-mysql.conf#MYSQLServer 127.0.0.1 #MYSQLPort 3306 MYSQLSocket /var/lib/mysql/mysql.sock MYSQLUser postfixuser MYSQLPassword postfixpass MYSQLDatabase postfix MYSQLCrypt cleartext MYSQLGetPW SELECT clear_password FROM mailbox WHERE email="\L" AND disableftp=0 #MYSQLGetUID SELECT Uid FROM mailbox WHERE email="\L" MYSQLDefaultUID 1001 #MYSQLGetGID SELECT Gid FROM mailbox WHERE email="\L" MYSQLDefaultGID 1001 MYSQLGetDir SELECT CONCAT('/var/vmail/',maildir,'public_html') FROM mailbox WHERE email="\L" AND disableftp=0 MySQLGetQTASZ SELECT ftpquota*1024 FROM mailbox WHERE email="\L" and disableftp=0chmod 600 /etc/pureftpd-mysql.conf
Setup a welcome banner
echo "##-------------------------------------------" > /etc/pureftpd-banner.txt echo "## yourdomain.com users FTP" >> /etc/pureftpd-banner.txt echo "##-------------------------------------------" >> /etc/pureftpd-banner.txt echo "##" >> /etc/pureftpd-banner.txt echo "## IMPORTANT" >> /etc/pureftpd-banner.txt echo "## Please login using your full email address" >> /etc/pureftpd-banner.txt echo "## eg username@yourdomain.com" >> /etc/pureftpd-banner.txt echo "##" >> /etc/pureftpd-banner.txt echo "##-------------------------------------------" >> /etc/pureftpd-banner.txtchmod 644 /etc/pureftpd-banner.txt
Configure pureftpd to start at boot time
vi /etc/rc.d/rc.local/usr/local/sbin/pure-ftpd -l mysql:/etc/pureftpd-mysql.conf --noanonymous --ipv4only --fortunesfile=/etc/pureftpd-banner.txt --createhomedir --customerproof --tls=1 --daemonize
Start pureftpd
/usr/local/sbin/pure-ftpd -l mysql:/etc/pureftpd-mysql.conf --noanonymous --ipv4only --fortunesfile=/etc/pureftpd-banner.txt --createhomedir --customerproof --tls=1 --daemonizeIf all goes well, ps axf should show something like this :
11204 ? Ss 0:00 pure-ftpd (SERVER)
Allow your IPTables to handle ftp connections at least semi-gracefully
vi /etc/rc.d/rc.local/sbin/modprobe ip_conntrack_ftp
Setup a crontab to ensure virtual quotas are always kept correct. Especially important after you have copied any content into the public_html dirs using a method other than pureftpd
vi /usr/local/sbin/rebuild-ftp-softquotas.pl#!/usr/bin/perl -w ## ## Loop through SQL and extract a list of userdirs ## For each user, recalc their ftp softquota file ## use strict; use DBI; my $dbh = DBI->connect('DBI:mysql:postfix', 'postfixuser', 'postfixpass') || die "Database connection failed: $DBI::errstr"; my $sql = "SELECT CONCAT('/var/vmail/',maildir) AS homedir FROM mailbox WHERE active=1 ORDER BY maildir"; my $sth = $dbh->prepare($sql); $sth->execute() || die "Could not execute SQL statement"; while (my($homedir)=$sth->fetchrow_array) { my $ftpdir = $homedir . "public_html"; if (-d "$ftpdir") { my $escaped_ftpdir = $ftpdir; $escaped_ftpdir =~ s/\&/\\&/g; $escaped_ftpdir =~ s/\ /\\ /g; my $cmd = sprintf ("/usr/local/sbin/pure-quotacheck -u 1001 -g 1001 -d $escaped_ftpdir"); system ($cmd); } else { print ("WARNING: dir does not exist : $ftpdir\n"); } } $sth->finish(); $dbh->disconnect();chmod 700 /usr/local/sbin/rebuild-ftp-softquotas.plcrontab -e### Periodically recalc all the ftp softquotas ( just in case ) 0 2 * * Sun /bin/nice /usr/local/sbin/rebuild-ftp-softquotas.pl
Remove some unneeded stuff from MySQL, and set some passwords
mysql-- MySQL comes with a "test" database and an anonymous user which has access to the test database -- We don't want either of these so lets get rid of them now DROP DATABASE test;DELETE FROM mysql.user WHERE User=''; DELETE FROM mysql.db WHERE User='';
-- Set a root password ( by default there is no password set, -- which means anyone with shell access could type "mysql -u root" and login to MySQL as root user )UPDATE mysql.user SET Password = PASSWORD('newpwd') WHERE User = 'root';
-- Tell MySQL to pickup our username/password changes FLUSH PRIVILEGES;
Setup a config file that stores the MySQL root password, so the system root user doesn't have to type the MySQL root password when logging into MySQL
vi /root/.my.cnf[client] password=newpwdchmod 600 /root/.my.cnf
Create a local user for yourself, and disable root SSH logins
By default the SSH daemon will permit root logins. Its a security risk to leave this enabled. I would recommend you create a local account which you can use when connecting via SSH. Once connected you can then type "su -" to switch to the root user if required.
useradd someuser passwd someuservi /etc/ssh/sshd_configPermitRootLogin no/etc/rc.d/init.d/sshd restart
Here's a script which I use to periodically create any missing softquota files. I run this weekly from crontab. Note the script tests for chmod 0 on the user's public_html : this is done because when I suspend a user for non-payment etc I go and set their disableftp/imap/pop3/webmail=1 in the mailbox table ( but leave active=1 so incoming mail doesn't get bounced), and I also chmod 0 their public_html dir to stop their webpages from being served.
vi /usr/local/sbin/create-missing-softquotas.pl#!/usr/bin/perl -w### Wonder if it would be worth while enhancing the script further to autocreate missing dirs? ### Might be bad news though if the db contains some sort of shonky home dir info ### Maybe just sending an email alert to admin is the best bet, get someone to investigate manually. ###use strict; use DBI; my $dbh = DBI->connect('DBI:mysql:postfix', 'postfixuser', 'postfixpass'); my $sql = "SELECT CONCAT('/var/vmail/',maildir) as homedir, CONCAT(mailquota*1024*1024,'S') AS mailquota, ftpquota*1024 as ftpquota FROM mailbox WHERE active=1 ORDER BY maildir"; my $sth = $dbh->prepare($sql); $sth->execute() || die "Could not execute SQL statement"; my $cmd; while (my($homedir, $mailquota, $ftpquota)=$sth->fetchrow_array) {# chop the trailing slash off the homedir $homedir =~ s/\/$//; #print "checking $homedir ($mailquota, $ftpquota) ..\n"; unless (-e "$homedir/Maildir/maildirsize") {if (-d "$homedir/Maildir") {print "maildirsize missing from $homedir/Maildir, creating it now\n"; my $escaped_maildir = $homedir . "/Maildir"; $escaped_maildir =~ s/\&/\\&/g; $escaped_maildir =~ s/\ /\\ /g; #### Create the quota file $cmd = sprintf ("/usr/local/courier-imap/bin/maildirmake -q $mailquota $escaped_maildir"); system ($cmd); #### Fix up permissions $cmd = sprintf ("chown vmail.vmail $escaped_maildir/maildirsize"); system ($cmd); $cmd = sprintf ("chmod 600 $escaped_maildir/maildirsize"); system ($cmd);} else {print "Error, $homedir/Maildir doesnt exist, this needs to be rectified\n";}}unless (-e "$homedir/public_html/.ftpquota") {if (-d "$homedir/public_html") {# bypass any dirs that have been chmod to 0 ( suspended ) my $mode = (stat $homedir."/public_html")[2]; unless ($mode == 0x4000) {print ".ftpquota missing from $homedir/public_html, creating it now\n"; my $escaped_ftpdir = $homedir . "/public_html"; $escaped_ftpdir =~ s/\&/\\&/g; $escaped_ftpdir =~ s/\ /\\ /g; $cmd = sprintf ("/usr/local/sbin/pure-quotacheck -u 1001 -g 1001 -d $escaped_ftpdir"); system ($cmd);}} else {print "Error, $homedir/public_html doesnt even exist, this needs to be rectified\n";}}}$sth->finish(); $dbh->disconnect();chmod 700 /usr/local/sbin/create-missing-softquotas.plcrontab -e0 3 * * * /bin/nice /usr/local/sbin/create-missing-softquotas.pl
Notes :
For every new virtual mailbox domain, insert a new row into the 'mailbox_domains' table
For every new virtual mailbox user, insert a new row into the 'mailbox' table, and create their maildir on the disk. Note: In our example we are going to "hash" the path to the user's dir, by taking the first letter of the username and putting that into the path eg domain/<1stletter>/username. This is done to the system from slowing down when it has to working with a directory that contains a huge number of entries. If you only plan to have a few hundred users you could probably go without any hashing. If you have thousands of users then 1 level of hashing is a good idea. If you have many tens of thousands of users then you might want to increase the level of hashing eg domain/<1stletter>/<1stletter><2ndletter>/username, or domain/<firstletter><2ndletter>/username)
For every new virtual alias domain, insert a new row into the 'alias_domains' table
For every every new alias/forward (doesn't matter if they are for a mailbox_domain or alias_domain), insert a row into the 'alias' table
Here is some examples of data :
use postfix;---------------------------------------------------------------------------------------------------- -- Tell postfix which domains we host this as virtual mailbox domains -- INSERT INTO mailbox_domains ( domain, description, created, modified ) VALUES ('testdomain.com', 'Postfix virtual mailbox domain', NOW(), NOW());INSERT INTO mailbox_domains ( domain, description, created, modified ) VALUES ('testdomain2.com', 'Postfix virtual mailbox domain', NOW(), NOW());---------------------------------------------------------------------------------------------------- -- Tell postfix about the virtual mailboxes that we host -- -- Note that when generating the crypted password, you can't use the MySQL CRYPT function. -- If you are migrating users out of an /etc/passwd type file, you can just copy the crypted password -- from there. -- If you need to generate a crypted password, you can use some code this like : -- perl -e "print crypt('testpass', join '', ('.', '/', 0..9,'A'..'Z', 'a'..'z')[rand 64, rand 64]);" -- -- If you don't enter the clear password, password auth will still work, except for auth methods -- that require the clear password to be available eg CRAM or DIGEST. More info on this subject here -- -- We haven't defined any of the spam_lover columns etc. If you don't specify a value there, amavisd -- will just apply its default settings from amavisd.conf ( virusscanning on, antispam scanning on, tag at 5 drop at 10 etc ) -- INSERT INTO mailbox (email, password, clear_password, maildir, created, modified) VALUES ('user1@testdomain.com', 'dzOCCGgyq3TVo', 'testpass', 'testdomain.com/u/user1/', NOW(), NOW());INSERT INTO mailbox (email, password, clear_password, maildir, created, modified) VALUES ('someuser2@testdomain.com', 'dzOCCGgyq3TVo', 'testpass', 'testdomain.com/s/someuser2/', NOW(), NOW());INSERT INTO mailbox (email, password, clear_password, maildir, created, modified) VALUES ('user1@testdomain2.com', 'dzOCCGgyq3TVo', 'testpass', 'testdomain2.com/u/user1/', NOW(), NOW());INSERT INTO mailbox (email, password, clear_password, maildir, created, modified) VALUES ('thisuser2@testdomain2.com', 'dzOCCGgyq3TVo', 'testpass', 'testdomain2.com/t/thisuser2/', qNOW(), NOW());---------------------------------------------------------------------------------------------------- -- Add in some alias address mappings -- INSERT INTO alias (address, goto, created, modified) VALUES ('user3@testdomain.com', 'user2@hotmail.com', NOW(), NOW());INSERT INTO alias (address, goto, created, modified) VALUES ('sales@testdomain.com', 'someuser2@testdomain.com', NOW(), NOW());-- "Catchall" entry INSERT INTO alias (address, goto, created, modified) VALUES ('@testdomain.com', 'user1@testdomain.com', NOW(), NOW());
To create the Maildirs on the disk you will need some commands like :
# create the full directory tree through to the users dir mkdir -p /var/vmail/testdomain.com/u/user1/public_html # create the maildir structure maildirmake /var/vmail/testdomain.com/u/user1/Maildir # create the softquota "maildirsize" file in the maildir. # ( If this file isn't present, no quotas will be enforced ) maildirmake -q 20971520S /var/vmail/testdomain.com/u/user1/Maildir chmod g-r,o-r /var/vmail/testdomain.com/u/user1/Maildir/maildirsize chown -R vmail.vmail /var/vmail/testdomain.com/u/user1
You can also host non-mailbox domains, where all addresses are forwarding on
to other locations :
Note that postfix will use any user@domain mappings before any @domain mappings
are matched
---------------------------------------------------------------------------------------------------- INSERT INTO alias_domains ( domain, description, created, modified ) VALUES ('testdomain3.com', 'Postfix virtual alias domain', NOW(), NOW());-- map xxx@testdomain3.com to xxx@testdomain.com INSERT INTO alias (address, goto, created, modified) VALUES ('@testdomain3.com', '@testdomain.com', NOW(), NOW());---------------------------------------------------------------------------------------------------- INSERT INTO alias_domains ( domain, description, created, modified ) VALUES ('testdomain4.com', 'Postfix virtual alias domain', NOW(), NOW());INSERT INTO alias (address, goto, created, modified) VALUES ('user1@testdomain4.com', 'jim@blah.com', NOW(), NOW());INSERT INTO alias (address, goto, created, modified) VALUES ('user2@testdomain4.com', 'john@something.com', NOW(), NOW());INSERT INTO alias (address, goto, created, modified) VALUES ('@testdomain4.com', 'fred@somewhere.com', NOW(), NOW());
Here are some examples of data for the "access" files :
-- Always permit mail to our abuse and postmaster addresses. -- Don't do RBL checking etc for such mail INSERT INTO recipient_access ( recipient, response, note, created, modified ) VALUES ('abuse', 'OK', 'Dont do RBL checking etc for mail to our abuse address', NOW(), NOW()); INSERT INTO recipient_access ( recipient, response, note, created, modified ) VALUES ('postmaster', 'OK', 'Dont do RBL checking etc for mail to our postmaster address', NOW(), NOW());-- match incoming smtp connections based on senders IP INSERT INTO client_access ( client, response, created, modified ) VALUES ('66.6.223.100','REJECT Sorry, you are sending spam', NOW(), NOW());-- match incoming smtp connections based on senders address INSERT INTO sender_access ( sender, response, created, modified ) VALUES ('support@westpac.com.au', 'REJECT Sober VIRUS', NOW(), NOW());-- recipient access can be handy if you have a customer who has configured -- a wildcard mapping enabled for their domain, but wants to reject one -- particular address from matching the wildcard INSERT INTO recipient_access ( recipient, response, note, created, modified ) VALUES ('example@testdomain2.com', 'REJECT Mailbox closed', NOW(), NOW());
http://people.ee.ethz.ch/~oetiker/webtools/mrtg/
You want to be able to keep an eye on your mail server using MRTG
Install the SNMP applications
yum install net-snmp net-snmp-utils
Add some basic scripts for snmpd to make use of
echo '#!/bin/sh' > /usr/local/bin/mrtg-incoming-count.sh echo 'find /var/spool/postfix/incoming -type f | wc -l' >> /usr/local/bin/mrtg-incoming-count.sh chmod 744 /usr/local/bin/mrtg-incoming-count.shecho '#!/bin/sh' > /usr/local/bin/mrtg-active-count.sh echo 'find /var/spool/postfix/active -type f | wc -l' >> /usr/local/bin/mrtg-active-count.sh chmod 744 /usr/local/bin/mrtg-active-count.shecho '#!/bin/sh' > /usr/local/bin/mrtg-deferred-count.sh echo 'find /var/spool/postfix/deferred -type f | wc -l' >> /usr/local/bin/mrtg-deferred-count.sh chmod 744 /usr/local/bin/mrtg-deferred-count.sh
Configure the snmpd
echo 'com2sec local localhost yourstring' > /etc/snmp/snmpd.conf echo 'com2sec mynetwork xxx.xxx.xxx.xxx/32 yourstring' >>/etc/snmp/snmpd.conf echo 'group MyROGroup v1 local' >>/etc/snmp/snmpd.conf echo 'group MyROGroup v1 mynetwork' >>/etc/snmp/snmpd.conf echo 'view all included .1 80' >>/etc/snmp/snmpd.conf echo 'access MyROGroup "" any noauth exact all none none' >>/etc/snmp/snmpd.conf echo 'syslocation Some Location' >>/etc/snmp/snmpd.conf echo 'syscontact Some Name <some@emailaddress>' >>/etc/snmp/snmpd.confecho 'proc pipe' >>/etc/snmp/snmpd.conf echo 'proc smtp' >>/etc/snmp/snmpd.conf echo 'proc lmtp' >>/etc/snmp/snmpd.conf echo 'proc smtpd-mx' >>/etc/snmp/snmpd.conf echo 'proc pop3d' >>/etc/snmp/snmpd.conf echo 'proc imapd' >>/etc/snmp/snmpd.confecho 'exec active-count /bin/sh /usr/local/bin/mrtg-active-count.sh' >>/etc/snmp/snmpd.conf echo 'exec incoming-count /bin/sh /usr/local/bin/mrtg-incoming-count.sh' >>/etc/snmp/snmpd.conf echo 'exec deferred-count /bin/sh /usr/local/bin/mrtg-deferred-count.sh' >>/etc/snmp/snmpd.conf
Protect your SNMP password from prying eyes
chmod 600 /etc/snmp/snmpd.conf
Configure snmpd to launch at boot time
chkconfig snmpd on
Start snmpd
/etc/rc.d/init.d/snmpd startps axf should give something like this :
9918 ? S 0:00 /usr/sbin/snmpd -Lsd -Lf /dev/null -p /var/run/snmpd -a
Here is an example mrtg cfg file for polling your server
Workdir: /home/httpd/stats/html/mail-servers/data IconDir: /images Options[^]: growright, unknaszero WithPeak[^]: ymw XSize[^]: 180 ##Remarked out this next line out, as it means you are only alerted when threshold is crossed ##Rather than nagged repeatedly that you are over threshold ##For us, being nagged is better I reckon ;-) ##ThreshDir: /home/httpd/stats/thresh ThreshProgI[_]: /home/httpd/stats/mrtg-threshwarn.pl ThreshProgOKI[_]: /home/httpd/stats/mrtg-threshwarn.pl ThreshProgO[_]: /home/httpd/stats/mrtg-threshwarn.pl ThreshProgOKO[_]: /home/httpd/stats/mrtg-threshwarn.pl#---------------------------------------------------------------------- #---------------------------------------------------------------------- Target[mail.yourdomain.com.eth]: 2:yourstring@mail.yourdomain.com: MaxBytes[mail.yourdomain.com.eth]: 1250000 AbsMax[mail.yourdomain.com.eth]: 12500000 Title[mail.yourdomain.com.eth]: Traffic Analysis for eth0 -- mail.yourdomain.com PageTop[mail.yourdomain.com.eth]: <H1>Traffic Analysis for eth0 -- mail.yourdomain.com</H1> Options[mail.yourdomain.com.eth]: bits, unknaszero #---------------------------------------------------------------------- Target[mail.yourdomain.com.cpu]: .1.3.6.1.4.1.2021.10.1.3.2&.1.3.6.1.4.1.2021.10.1.3.3:yourstring@mail.yourdomain.com * 100 MaxBytes[mail.yourdomain.com.cpu]: 1000 AbsMax[mail.yourdomain.com.cpu]: 50000 Title[mail.yourdomain.com.cpu]: System Load Average for mail.yourdomain.com PageTop[mail.yourdomain.com.cpu]: <H1> System Load Average for mail.yourdomain.com (*100) </H1> Options[mail.yourdomain.com.cpu]: gauge, unknaszero YLegend[mail.yourdomain.com.cpu]: Load Average ShortLegend[mail.yourdomain.com.cpu]: load Legend1[mail.yourdomain.com.cpu]: Load Average over 5 Minutes LegendI[mail.yourdomain.com.cpu]: 5 min: LegendO[mail.yourdomain.com.cpu]: 15 min: ThreshMaxI[mail.yourdomain.com.cpu]: 8000 #---------------------------------------------------------------------- Target[mail.yourdomain.com.realmem]: .1.3.6.1.2.1.25.2.3.1.6.2&.1.3.6.1.2.1.25.2.3.1.6.2:yourstring@mail.yourdomain.com MaxBytes[mail.yourdomain.com.realmem]: 2075988 Title[mail.yourdomain.com.realmem]: Real Memory PageTop[mail.yourdomain.com.realmem]: <h1>Real memory on mail.yourdomain.com</h1> Unscaled[mail.yourdomain.com.realmem]: dwmy YLegend[mail.yourdomain.com.realmem]: Real Memory Options[mail.yourdomain.com.realmem]: Gauge, Integer, unknaszero #Kilo[mail.yourdomain.com.realmem]: 1024 kMG[mail.yourdomain.com.realmem]: Kb,Mb,Gb,Tb,Pb ShortLegend[mail.yourdomain.com.realmem]: #---------------------------------------------------------------------- Target[mail.yourdomain.com.swapmem]: .1.3.6.1.2.1.25.2.3.1.6.3&.1.3.6.1.2.1.25.2.3.1.6.3:yourstring@mail.yourdomain.com MaxBytes[mail.yourdomain.com.swapmem]: 4096532 Title[mail.yourdomain.com.swapmem]: Swap Memory PageTop[mail.yourdomain.com.swapmem]: <h1>Swap memory on mail.yourdomain.com</h1> Unscaled[mail.yourdomain.com.swapmem]: dwmy YLegend[mail.yourdomain.com.swapmem]: Swap Memory Options[mail.yourdomain.com.swapmem]: Gauge, Integer, unknaszero #Kilo[mail.yourdomain.com.swapmem]: 1024 kMG[mail.yourdomain.com.swapmem]: Kb,Mb,Gb,Tb,Pb ShortLegend[mail.yourdomain.com.swapmem]: ThreshMaxI[mail.yourdomain.com.swapmem]: 20% #---------------------------------------------------------------------- #---------------------------------------------------------------------- Target[mail.yourdomain.com.postfix.virtual]: .1.3.6.1.4.1.2021.2.1.5.1&.1.3.6.1.4.1.2021.2.1.5.1:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.postfix.virtual]: 100 AbsMax[mail.yourdomain.com.postfix.virtual]: 1000 Title[mail.yourdomain.com.postfix.virtual]: mail.yourdomain.com : Postfix virtual-mailbox delivery processes PageTop[mail.yourdomain.com.postfix.virtual]: <H1>mail.yourdomain.com : Postfix virtual-mailbox delivery processes</H1> Options[mail.yourdomain.com.postfix.virtual]: gauge, integer YLegend[mail.yourdomain.com.postfix.virtual]: processes #---------------------------------------------------------------------- Target[mail.yourdomain.com.postfix.smtp]: .1.3.6.1.4.1.2021.2.1.5.2&.1.3.6.1.4.1.2021.2.1.5.2:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.postfix.smtp]: 100 AbsMax[mail.yourdomain.com.postfix.smtp]: 1000 Title[mail.yourdomain.com.postfix.smtp]: mail.yourdomain.com : Postfix outbound smtp processes PageTop[mail.yourdomain.com.postfix.smtp]: <H1>mail.yourdomain.com : Postfix outbound smtp processes</H1> Options[mail.yourdomain.com.postfix.smtp]: gauge, integer YLegend[mail.yourdomain.com.postfix.smtp]: processes #---------------------------------------------------------------------- Target[mail.yourdomain.com.postfix.lmtp]: .1.3.6.1.4.1.2021.2.1.5.3&.1.3.6.1.4.1.2021.2.1.5.3:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.postfix.lmtp]: 100 AbsMax[mail.yourdomain.com.postfix.lmtp]: 1000 Title[mail.yourdomain.com.postfix.lmtp]: mail.yourdomain.com : Postfix smtp-amavis processes PageTop[mail.yourdomain.com.postfix.lmtp]: <H1>mail.yourdomain.com : Postfix smtp-amavis processes</H1> Options[mail.yourdomain.com.postfix.lmtp]: gauge, integer YLegend[mail.yourdomain.com.postfix.lmtp]: processes #---------------------------------------------------------------------- Target[mail.yourdomain.com.postfix.smtpd-mx]: .1.3.6.1.4.1.2021.2.1.5.4&.1.3.6.1.4.1.2021.2.1.5.4:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.postfix.smtpd-mx]: 100 AbsMax[mail.yourdomain.com.postfix.smtpd-mx]: 1000 Title[mail.yourdomain.com.postfix.smtpd-mx]: mail.yourdomain.com : Postfix smtpd-mx processes PageTop[mail.yourdomain.com.postfix.smtpd-mx]: <H1>mail.yourdomain.com : Postfix smtpd-mx processes</H1> Options[mail.yourdomain.com.postfix.smtpd-mx]: gauge, integer YLegend[mail.yourdomain.com.postfix.smtpd-mx]: processes #---------------------------------------------------------------------- Target[mail.yourdomain.com.pop3d]: .1.3.6.1.4.1.2021.2.1.5.5&.1.3.6.1.4.1.2021.2.1.5.5:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.pop3d]: 100 AbsMax[mail.yourdomain.com.pop3d]: 1000 Title[mail.yourdomain.com.pop3d]: mail.yourdomain.com : pop3d processes PageTop[mail.yourdomain.com.pop3d]: <H1>mail.yourdomain.com : pop3d processes</H1> Options[mail.yourdomain.com.pop3d]: gauge, integer YLegend[mail.yourdomain.com.pop3d]: processes ThreshMaxI[mail.yourdomain.com.pop3d]: 150 #---------------------------------------------------------------------- Target[mail.yourdomain.com.imapd]: .1.3.6.1.4.1.2021.2.1.5.6&.1.3.6.1.4.1.2021.2.1.5.6:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.imapd]: 100 AbsMax[mail.yourdomain.com.imapd]: 1000 Title[mail.yourdomain.com.imapd]: mail.yourdomain.com : imapd processes PageTop[mail.yourdomain.com.imapd]: <H1>mail.yourdomain.com : imapd processes</H1> Options[mail.yourdomain.com.imapd]: gauge, integer YLegend[mail.yourdomain.com.imapd]: processes ThreshMaxI[mail.yourdomain.com.imapd]: 150 #---------------------------------------------------------------------- #---------------------------------------------------------------------- Target[mail.yourdomain.com.postfix.active-count]: .1.3.6.1.4.1.2021.8.1.101.1&.1.3.6.1.4.1.2021.8.1.101.1:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.postfix.active-count]: 1000 AbsMax[mail.yourdomain.com.postfix.active-count]: 1000000 Title[mail.yourdomain.com.postfix.active-count]: mail.yourdomain.com : Postfix active queue PageTop[mail.yourdomain.com.postfix.active-count]: <H1>mail.yourdomain.com : Postfix active queue</H1> Options[mail.yourdomain.com.postfix.active-count]: gauge, integer YLegend[mail.yourdomain.com.postfix.active-count]: Messages ThreshMaxI[mail.yourdomain.com.postfix.active-count]: 2000 #---------------------------------------------------------------------- Target[mail.yourdomain.com.postfix.incoming-count]: .1.3.6.1.4.1.2021.8.1.101.2&.1.3.6.1.4.1.2021.8.1.101.2:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.postfix.incoming-count]: 1000 AbsMax[mail.yourdomain.com.postfix.incoming-count]: 1000000 Title[mail.yourdomain.com.postfix.incoming-count]: mail.yourdomain.com : Postfix incoming queue PageTop[mail.yourdomain.com.postfix.incoming-count]: <H1>mail.yourdomain.com : Postfix incoming queue</H1> Options[mail.yourdomain.com.postfix.incoming-count]: gauge, integer YLegend[mail.yourdomain.com.postfix.incoming-count]: Messages ThreshMaxI[mail.yourdomain.com.postfix.incoming-count]: 2000 #---------------------------------------------------------------------- Target[mail.yourdomain.com.postfix.deferred-count]: .1.3.6.1.4.1.2021.8.1.101.3&.1.3.6.1.4.1.2021.8.1.101.3:yourstring@mail.yourdomain.com::10 MaxBytes[mail.yourdomain.com.postfix.deferred-count]: 1000 AbsMax[mail.yourdomain.com.postfix.deferred-count]: 1000000 Title[mail.yourdomain.com.postfix.deferred-count]: mail.yourdomain.com : Postfix deferred queue PageTop[mail.yourdomain.com.postfix.deferred-count]: <H1>mail.yourdomain.com : Postfix deferred queue</H1> Options[mail.yourdomain.com.postfix.deferred-count]: gauge, integer YLegend[mail.yourdomain.com.postfix.deferred-count]: Messages
The mrtg-threshwarn.pl script looks like this :
#!/usr/bin/perl -w # # Called when MRTG detects a threshold problem for a variable. # ARGV[0] = Parameter name, such as 'wanrouter.cpu'. # ARGV[1] = Threshold value which was breached, such as "99". # ARGV[2] = Actual current value of the parameter, such as "100". # # Command line looks like: # thisprogram wanrouter 99[%] 100 description 100 # my($timestr, $param, $thresh, $raw, $description, $value, $message, $logfile); $timestr = localtime(time); $param = $ARGV[0]; $thresh = $ARGV[1]; $raw = $ARGV[2]; $description = $ARGV[3]; $value = $ARGV[4];$emailprog = "/usr/sbin/sendmail"; $emailuser = "admin\@yourdomain.com";$percent = ""; $bracket = ""; if ($thresh =~ /%$/) { $thresh = substr($thresh, 0, length($thresh)-1); $percent = "%"; $raw = "$raw ("; $bracket = ")"; }else{ $raw = "";if ($thresh > $value) { $abovebelow = "below"; } else { $abovebelow = "above"; }$message = "Notice ! $param is $abovebelow threshold $thresh$percent. Current value is $raw$value$percent$bracket"; #$message .= "Notice ! $param ($value) has passed threshold ($thresh)"; system("echo 'Subject: $message' | $emailprog $emailuser"); exit(0);
It is possible to put the amavisd/clamav/spamassassin on a different box to the Postfix. This can be advantageous as although the clamav software doesn't consume many resources, the SpamAssassin software can create quite a heavy load.
ON THE POSTFIX MACHINE :
Add an entry in the firewall that permits your amavisd machine to connect on port TCP 10025 ( Amavisd )
Add an entry in the firewall that permits your amavisd machine to connect on port TCP 3306 ( MySQL )
Allow MySQL to serve lookups to the 2nd machine
GRANT SELECT ON postfix.* TO postfixuser@offload-machines-address-here IDENTIFIED BY 'postfixpass';Modify the MySQL so it listens for TCP connections
vi /etc/my.cnf#skip-networkingIn the /etc/postfix/main.cf, reconfigure Postfix to send the amavisd traffic to the amavisd machine
content_filter=smtp-amavis:[offload-machines-fdqn-hostname-here]:10024# Note you could have multiple machines setup eg avs1/2/3/4.yourdomain.com,
# and a round-robin DNS name of avs.yourdomain.com that points to these boxes,
# and you could use that avs.yourdomain.com hostname in that command above.
# This will loadshare the amavisd traffic amongst your multiple serversIn the /etc/postfix/main.cf, reconfigure Postfix to listen for amavisd traffic from the amavisd machine
192.168.1.10:10025 inet n - n - - smtpd-av -o content_filter= -o smtpd_restriction_classes= -o smtpd_delay_reject=no -o smtpd_client_restrictions=permit_mynetworks,reject -o smtpd_helo_restrictions= -o smtpd_sender_restrictions= -o smtpd_recipient_restrictions=permit_mynetworks,reject -o smtpd_data_restrictions=reject_unauth_pipelining -o smtpd_end_of_data_restrictions= -o mynetworks=offload-machines-ip-or-subnet-here -o smtpd_error_sleep_time=0 -o smtpd_soft_error_limit=1001 -o smtpd_hard_error_limit=1000 -o smtpd_client_connection_count_limit=0 -o smtpd_client_connection_rate_limit=0 -o smtpd_milters= -o local_header_rewrite_clients= -o local_recipient_maps= -o relay_recipient_maps= -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks,no_address_mappings
ON THE AMAVISD MACHINE :
Follow these steps from the top of the guide
Add an entry in the firewall that permits mail.yourdomain.com to connect on port 10024
Run these commands
# Not running MySQL server on this box ( but still want the libraries ). # Also not running apache. chkconfig mysqld off chkconfig httpd off# Load postfix from RPM to allow this box to send mail ( nightly reports etc ) yum install postfix system-switch-mail # Run this next command and choose postfix system-switch-mail# Ensure that you have got prerequisite libraries installed yum install mysql-devel db4-devel db4-utils zlib zlib-develFollow the installation steps at the top of the guide for these applications :
Now follow the amavisd installation steps as shown above except for some tweaks shown below
In cpan, you might need to "force install DBD::mysql", otherwise it wont work because the installer tries to test a connection to the local MySQL server ( which may not succeed since our design wont need MySQL running on the amavisd machine )
In the /etc/amavisd.conf, you will need to alter these settings :
$forward_method = 'smtp:*:*';@inet_acl = qw(127.0.0.0/8 [::1] 192.168.1.10); # adjust list as needed $inet_socket_bind = undef; # bind to all IP interfaces if undef@lookup_sql_dsn = ( ['DBI:mysql:database=postfix;host=mail.yourdomain.com', 'postfixuser', 'postfixpass'] );Next is an optional tweak, which doesn't affect the operation of the server, but does fix a problem seen when people are reporting spam to SpamCop. By default amavisd calls itself localhost in the headers, which is OK when the software is running on same box as Postfix. But when you have split the two applications apart onto separate boxes, we need to use the proper hostname rather than localhost. Unless you make this change SpamCop will trip up on this header and can incorrectly identify your mail server as the source of the SPAM.
In the /etc/amavisd.conf, add this line
$localhost_name = $myhostname;Probably the best place to put it, is below this line :
# $myhostname = 'host.example.com'; # fqdn of this host, default by uname(3)
SOME OTHER AMAVISD TIPS :
If you have a really busy server, then a single amavisd box might not be enough, you might need to run two or more. Just build them with same config, and setup a round-robin DNS entry that points to both boxes. Tweak the content_filter line in Postfix's main.cf to use the RR name. Also increase the smtp-amavis_destination_concurrency_limit setting in main.cf to a suitable amount ( eg if you have 2 dedicated amavisd machines each configured for 10 clients, then set the smtp-amavis_destination_concurrency_limit=20)
If you have gone down the road of splitting the amavisd onto a dedicated box, you are probably on the lookout for other performance enhancement tips. One suggestion is to put the amavisd tmp folder into a ram drive. Instructions available here : http://www.stahl.bau.tu-bs.de/~hildeb/postfix/amavisd_tmpfs.shtml
If you use the content_filter command in postfix's main.cf, you will be scanning all inbound + outbound mail. If you don't want to bother scanning outbound mail, you remove that content filter line and instead populate your recipient_access table with a list of locally hosted domains you want to do filtering for eg :
recipient response hosteddomain1.com FILTER smtp-avavis:[amavis-hostname]:10024 hosteddomain2.com FILTER smtp-avavis:[amavis-hostname]:10024 hosteddomain3.com FILTER smtp-avavis:[amavis-hostname]:10024
We already have a webmail package installed ( sqwebmail ). However sqwebmail only has a very functionality. Many times you will have users who want something more powerful. This is where the Horde suite can help. Its takes a bit of work to get it installed, but the results are worth the effort.
Install the prerequisite modules
yum install php php-devel php-mysql php-imap php-xml php-mbstring php-gd php-mycrypt enscriptpear install -o Log Mail Mail_Mime DB Date File Net_URL Net_Sieve Net_Socket HTTP_Request Fileinfo
# Gotcha with above! The Fileinfo tries to compile in /tmp, which our tweaked fstab disallows. # Workaround is to remove the nosuid,noexec from fstab, and to mount -o remount /tmp before install, # and then put it back again afterwards. # Would be good if we could come up with something more graceful # eg, can we perhaps export TEMP variable or similar to point other than /TMP for this install
# Then I would recommend you run the following to bring all your pear modules up to date
pear upgrade Archive_Tar pear upgrade PEAR # If the above command fails saying it requires PEAR-1.3.3, then type "pear upgrade PEAR-1.3.3" and then run above command again pear channel-update pear.php.net pear upgrade-all
Install the optional wvHhtml tool, so IMP can render MS Word docs as HTML :
On Fedora you can just do this :
yum install wvOn CentOS its a bit more work involved, you need to do this :
yum install zlib zlib-devel libpng libpng-develcd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/wvware/wv-1.0.3.tar.gz tar xzf wv-1.0.3.tar.gz chown -R root.root wv-1.0.3 cd wv-1.0.3 ./configure make make install
Suitably tweak the PHP configuration
vi /etc/php.ini
# in the "Dynamic Extensions" part, enter this : extension=fileinfo.so
# find and tweak these values to allow for large webmail uploads max_execution_time = 3600 memory_limit = 64M post_max_size = 18M file_uploads = On upload_max_filesize = 17M
killall -HUP httpd
HORDE APPLICATION FRAMEWORK
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/horde/horde/horde-3.1.1.tar.gzcd /var/www/mail/html tar xzf /usr/local/src/horde-3.1.1.tar.gzchown -R root.apache horde-3.1.1 chmod -R o-rwx horde-3.1.1mv horde-3.1.1 horde cd hordecd scripts/sql vi create.mysql.sql# change this line : PASSWORD('hordepass')mysql -u root < create.mysql.sql cd ../..cd config for f in *.dist; do cp $f `basename $f .dist`; done cd ..chown -R root.apache config chmod -R g+rw configcd /var/www/mail/html/images # grab a copy of your logo file needs to be max 140px wide and 40px high wget http://somewhere/images/yourdomain.com-smalllogo.gif # grab a copy of your larger logo file wget http://somewhere/images/yourdomain.com-largelogo.gifhttp://mail.yourdomain.com/horde/test.phphttp://mail.yourdomain.com/horde/click on Administration->SetupIn the Application screen, click on HordeDatabase ->What database backend : MySQL Request persistent connections : ticked Database server/host : localhost Username to connect to the database as : horde password to connect with : hordepass database name to use : hordePreference system ->Preference driver : SQL DatabaseDataTree System ->Backend : SQL DatabaseMailer ->The location of sendmail binary : /usr/sbin/sendmailVirtual File Storage ->Backend : SQL DatabaseCustom sessions handler ->Sessionhandler : MySQL based sessionsRequest persistent connections : ticked Row level locking : ticked Database server/host : localhost Username to connect to the database as : horde password to connect with : hordepass database name to use : hordeMIME Detection ->location : /usr/share/misc/magicProblem Reporting ->whre should problem reports be sent : support@yourdomain.comMenu Settings ->Select applications to be linked to Hordes menu : imp, ingo, kronolith, turba Display problem reporting link : Never URL of an image for top of horde menu : /images/yourdomain.com-smalllogo.gif If logo is displayed, what URL should it link to : www.yourdomain.comClick on generate horde configIf you installed the wvHtml package from source ( CentOS ) rather than RPM ( Fedora), then you need to fix the path Horde uses for this tool :
vi /var/www/mail/html/horde/config/mime_drivers.php$mime_drivers['horde']['msword']['location'] = '/usr/local/bin/wvHtml';Now, regardless of whether you are using CentOS or Fedora, there are two other Horde helper tools "xlhtml" and "ppthtml" that need to be disabled. Although these two tools sound useful ( convert Excel and Powerpoint files to HTML for viewing), you cant get them via Yum and the source fails to compile on most boxes I have tried. Also there are two other drivers "webcpp" and "srchighlite" which are only for fairly obscure use and these tools dont exist on our machine so we want to disable them as well :
vi /var/www/mail/html/horde/config/mime_drivers.php# up towards the top of the file there is a section that looks like this : $mime_drivers_map['horde']['registered'] = array( # need to remove the msexcel, mspowerpoint, srchighlite and webcpp entries from this array
IMP WEBMAIL
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/horde/imp/imp-h3-4.1.1.tar.gzcd /var/www/mail/html/horde tar xzf /usr/local/src/imp-h3-4.1.1.tar.gzchown -R root.apache imp-h3-4.1.1 chmod -R o-rwx imp-h3-4.1.1mv imp-h3-4.1.1 imp cd impcd config/ for foo in *.dist; do cp $foo `basename $foo .dist`; donevi servers.php# update the IMAP server info. Replace all existing samples with this :$servers['imap'] = array( 'name' => 'Courier IMAP Server', 'server' => 'localhost', 'hordeauth' => false, 'protocol' => 'imap/notls', 'port' => 143, 'smtphost' => 'localhost', 'realm' => '', 'preferred' => '', 'dotfiles' => false, 'quota' => array ( 'driver' => 'courier', 'params' => array() ), 'hierarchies' => array() );vi prefs.php$_prefs['sent_mail_folder'] = array( 'value' => 'Sent',$_prefs['drafts_folder'] = array( 'value' => 'Drafts',$_prefs['trash_folder'] = array( 'value' => 'Trash',vi header.php// Add the IP of the remote browser $_header['X-Originating-IP'] = $_SERVER['REMOTE_ADDR'];cd ..chown -R root.apache config chmod -R g+rw configvi templates/login/login.increplaceecho _("Username")withecho _("Email address")http://mail.yourdomain.com/horde/imp/test.phphttp://mail.yourdomain.com/horde/click on Administration->SetupIn the Application menu, click on Mail (imp)External Utilities and MenuLocation of aspell : /usr/bin/aspellApplications that should be linked to IMPs menu : imp, ingo, koronlith, turbaComposeShould we append the contents of imp/config/trailer.txt : untickedCan the user request a return receipt : untickedsend attachments as links : nomaximum size of attachments : 17000000Click on Generate Mail Configuration
TURBA ADDRESS BOOK
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/horde/turba/turba-h3-2.1.tar.gzcd /var/www/mail/html/horde tar xzf /usr/local/src/turba-h3-2.1.tar.gzchown -R root.apache turba-h3-2.1 chmod -R o-rwx turba-h3-2.1mv turba-h3-2.1 turba cd turbacd config/ for foo in *.dist; do cp $foo `basename $foo .dist`; donevi sources.phpremove all sources except the localsql onecd ..chown -R root.apache config chmod -R g+rw configcd scripts/sql mysql horde < turba_objects.mysql.sql cd ../..http://mail.yourdomain.com/horde/turba/test.phphttp://mail.yourdomain.com/horde/click on Administration->SetupIn the Application menu click on Address Book ( turba)Select any applications that should be linked to turbas menu : imp, ingo, kronolith, turbaName of source for creating new shares : localsqlClick on Generate Address book configuration
KRONOLITH CALENDER
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/horde/kronolith/kronolith-h3-2.1.1.tar.gzcd /var/www/mail/html/horde tar xzf /usr/local/src/kronolith-h3-2.1.1.tar.gzchown -R root.apache kronolith-h3-2.1.1 chmod -R o-rwx kronolith-h3-2.1.1mv kronolith-h3-2.1.1 kronolith cd kronolithcd config/ for foo in *.dist; do cp $foo `basename $foo .dist`; done cd ..chown -R root.apache config chmod -R g+rw configcd scripts/sql mysql horde < kronolith.mysql.sql cd ../..http://mail.yourdomain.com/horde/click on Administration->SetupIn the Application menu, click on Calendar (Kronolith)Server name from which reminders are sent : mail.yourdomain.comEmail address from which reminders are send : reminder@mail.yourdomain.comApplications that should be linked to the Konolith menu : imp, ingo, kronolith, turbaClick on Generate Calender Configuration
INGO FILTERS
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/horde/ingo/ingo-h3-1.1.tar.gzcd /var/www/mail/html/horde tar xzf /usr/local/src/ingo-h3-1.1.tar.gzchown -R root.apache ingo-h3-1.1 chmod -R o-rwx ingo-h3-1.1mv ingo-h3-1.1 ingo cd ingocd config/ for foo in *.dist; do cp $foo `basename $foo .dist`; done cd ..chown -R root.apache config chmod -R g+rw confighttp://mail.yourdomain.com/horde/ingo/test.phphttp://mail.yourdomain.com/ingo/click on Administration->SetupIn the Application menu, click on Filters (Ingo)Select applictions that should be linked to ingo's menu : imp, ingo, kronolith, turbaClick on Generate Filters configuration
You can optionally add a couple more modules, but on the servers I build, I don't use these extra modules :
NAG REMINDERS
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/horde/nag/nag-h3-2.1.tar.gzcd /var/www/mail/html/horde tar xzf /usr/local/src/nag-h3-2.1.tar.gzchown -R root.apache nag-h3-2.1 chmod -R o-rwx nag-h3-2.1mv nag-h3-2.1 nag cd nagcd config/ for foo in *.dist; do cp $foo `basename $foo .dist`; done cd ..chown -R root.apache config chmod -R g+rw configcd scripts/sql mysql -p horde < nag.sql cd ../..http://mail.yourdomain.com/horde/nag/test.phphttp://mail.yourdomain.com/horde/click on Administration->SetupIn the Application menu, click on Tasks (Nag)Click on Generate Reminders configuration
MNEMO NOTES
cd /usr/local/src wget ftp://ftp.planetmirror.com/pub/horde/mnemo/mnemo-h3-2.1.tar.gzcd /var/www/mail/html/horde tar xzf /usr/local/src/mnemo-h3-2.1.tar.gzchown -R root.apache mnemo-h3-2.1 chmod -R o-rwx mnemo-h3-2.1mv mnemo-h3-2.1 mnemo cd mnemocd config/ for foo in *.dist; do cp $foo `basename $foo .dist`; done cd ..chown -R root.apache config chmod -R g+rw configcd scripts/sql mysql -p horde < mnemo.sql cd ../..http://mail.yourdomain.com/horde/mnemo/test.phphttp://mail.yourdomain.com/horde/click on Administration->SetupIn the Application menu, click on Notes (Mnemo)Click on Generate Notes configuration
Now that all the modules are installed and setup, lets reconfigure the Horde module to authenticate users via IMP
http://mail.yourdomain.com/hordeClock on Administration -> SetupIn the Application menu, click on HordeAuthentication ->Which users should be treated as administrators : someadminemail@yourdomain.com # NOTE, the address above should be a valid email account that will be hosted on this box. # When you login into webmail as this user, you will be given access to all the admin # menus which lets you change the config of the horde suite.What backend for authenticating : let a horde application handle authenticationThe application that is providing authentication : impClick on Generate Horde Configurationyou get a nasty forbidden message at this point, because you have just killed off the previous administrator user admin rights
And lets tweak the interface defaults a bit
vi /var/www/mail/html/horde/templates/common-footer.inc# Add this to the top of the file<!-- CUSTOM BRANDING TWEAKS --> <p><center><b>yourdomain.com support - call 1300 xxx xxx</b></center></p> <!-- CUSTOM BRANDING TWEAKS -->vi /var/www/mail/html/horde/config/prefs.php$_prefs['language'] = array( 'value' => 'en_GB',$_prefs['timezone'] = array( 'value' => 'Australia/Melbourne',$_prefs['date-format'] = array ( 'value' => '%Y-%m-%d',$_prefs['show_sidebar'] = array ( 'value' => false,$_prefs['initial_application'] = array( 'value' => 'imp',vi /var/www/mail/html/horde/imp/login.php#Replace this line// $title = sprintf(_("Welcome to %s"), $registry->get('name', ($imp_auth) ? 'horde' : null));#With this line$title = sprintf(_("%s Webmail"), _(preg_replace('/^mail\.|^webmail\./', '', $GLOBALS['_SERVER']['SERVER_NAME'])) );vi /var/www/mail/html/horde/imp/config/motd.php# replace the existing table with<table width="100%"><tr><td align="center"><img src="/images/yourdomain.com-largelogo.gif" alt="yourdomain.com" /></td></tr></table>vi /var/www/mail/html/horde/imp/config/prefs.php$_prefs['purge_trash'] = array( 'value' => 1,$_prefs['purge_trash_interval'] = array( 'value' => '3',$_prefs['purge_trash_keep'] = array( 'value' => 7,$_prefs['fetchmail_menu'] = array( 'value' => 0,$_prefs['mailbox_start'] = array( 'value' => IMP_MAILBOXSTART_LASTUNSEEN,$_prefs['sortby'] = array( 'value' => SORTDATE,$_prefs['sortdir'] = array( 'value' => 1,$_prefs['filter_on_display'] = array( 'value' => 1,# This next one you can choose whether you do it or not... # If you add this tweak, then HTML mails will display inline, rather than requiring the user # to click on the attachment link. # Displaying inline can be a security issue, however you have to juggle this against # helpdesk load that you will suffer from users who complain about not being able to read # their html mail. vi /var/www/mail/html/horde/imp/config/mime_drivers.php$mime_drivers['imp']['html']['inline'] = true;vi /var/www/mail/html/horde/imp/templates/login/login.inc#Search for input box name="imapuser" add size=32 as property of input box. #Since the default box is a bit too small and can cause users confusion #when they arent able to spot typos that have scrolled off the screen
You can bind multiple IPs to your server (one per domain) and set "default" POP3/IMAP domain for each IP :
Probably you first should remove any DEFAULT_DOMAIN entry from the /usr/local/courier-authlib/etc/authdaemonrc
vi /usr/local/courier-imap/etc/imapdTCPDOPTS="-nodnslookup -noidentlookup -access=/usr/local/courier-imap/etc/default-domains.db -accesslocal"vi /usr/local/courier-imap/etc/pop3dTCPDOPTS="-nodnslookup -noidentlookup -access=/usr/local/courier-imap/etc/default-domains.db -accesslocal"vi /usr/local/courier-imap/etc/default-domains# A set of mappings for ip addresses to default domains # These mappings are used by courier-imap, and courier-pop3d## ## YOU MUST USE A TAB BETWEEN THE IP AND THE RESULT ## SPACES WILL NOT WORK! AUTH WILL FAIL WITH A TEMP ERROR ##192.168.1.101<TAB>allow,DEFDOMAIN=@domain1.com 192.168.1.102<TAB>allow,DEFDOMAIN=@domain2.com 192.168.1.103<TAB>allow,DEFDOMAIN=@domain3.com
( cat /usr/local/courier-imap/etc/default-domains; echo "." ) \ | /usr/local/courier-imap/libexec/makedatprog - /usr/local/courier-imap/etc/default-domains.tmp /usr/local/courier-imap/etc/default-domains.db
And from my experience, you have to restart courier-imap for the changes to take effect after making any changes to this file
/etc/rc.d/init.d/courier-imap restart
You can bind multiple IPs to your server (one per domain) and set a "default" sqwebmail domain for each IP
The config below would look to see what IP the client connected to, and would pre-populate the domain name part of the login box
vi /usr/local/sqwebmail/etc/logindomainlist# A set of mappings for ip addresses to default domains domain1.com:192.168.1.101:@ domain2.com:192.168.1.102:@ domain3.com:192.168.1.103:@
When you configure the SASL ( SMTP-AUTH) settings in postfix's main.cf, you can nominate a default domain to use should the SMTP user not supply one (smtpd_sasl_local_domain = yourdomain.com ). However when you are hosting multiple virtual domains on the one box, unless the vast bulk of your users are from a single domain, you really need a way to append the correct domain.
You can bind multiple IPs to your server (one per domain), and then set the smtpd_sasl_local_domain inside the master.cf on a per-smtpd instance basis.
eg Change your master.cf from this ( as described earlier in doc )
127.0.0.1:smtp inet n - n - 10 smtpd 192.168.1.11:smtp inet n - n - 50 smtpd-mx -o smtpd_sasl_auth_enable=no 192.168.1.10:smtp inet n - n - 100 smtpd
To something like this :
127.0.0.1:smtp inet n - n - 10 smtpd 192.168.1.11:smtp inet n - n - 50 smtpd-mx -o smtpd_sasl_auth_enable=no 192.168.1.101:smtp inet n - n - 30 smtpd-domain1 -o smtpd_sasl_local_domain=domain1.com 192.168.1.102:smtp inet n - n - 30 smtpd-domain2 -o smtpd_sasl_local_domain=domain2.com 192.168.1.103:smtp inet n - n - 30 smtpd-domain3 -o smtpd_sasl_local_domain=domain3.com
And don't forget to setup your symlinks
cd /usr/libexec/postfix ln -s smtpd smtpd-domain1 ln -s smtpd smtpd-domain2 ln -s smtpd smtpd-domain3
Update your reverse DNS entries
$ORIGIN 1.168.192.in-addr.arpa. 11 PTR mail-mx.yourdomain.com. 101 PTR mail.domain1.com. 102 PTR mail.domain2.com. 103 PTR mail.domain3.com.
You can set a default login doman domain based on the IP address the user has connected to
Create a IP <-> Domain mapping table :
mysqlUSE postfix;CREATE TABLE domain_ips (ip varchar(15) not NULL, domain varchar(255) NOT NULL, PRIMARY KEY (ip)) TYPE=MyISAM COMMENT='IP to Domain mappings for Pure-ftpd';INSERT INTO domain_ips (ip, domain) VALUES ('192.168.1.101', 'domain1.com'); INSERT INTO domain_ips (ip, domain) VALUES ('192.168.1.102', 'domain2.com'); INSERT INTO domain_ips (ip, domain) VALUES ('192.168.1.103', 'domain3.com');quit
Tweak the pure-ftpd config :
vi /etc/pureftpd-mysql.confMYSQLGetPW SELECT clear_password FROM mailbox WHERE (("\L" LIKE '%@%' AND email = "\L") OR ("\L" NOT LIKE '%@%' AND email = CONCAT("\L",'@',(select domain from domain_ips where ip = "\I")))) AND disableftp=0MYSQLGetDir SELECT CONCAT('/var/vmail/',maildir,'public_html') FROM mailbox WHERE (("\L" LIKE '%@%' AND email = "\L") OR ("\L" NOT LIKE '%@%' AND email = CONCAT("\L",'@',(SELECT domain FROM domain_ips WHERE ip = "\I")))) and disableftp=0MySQLGetQTASZ SELECT ftpquota FROM mailbox WHERE (("\L" LIKE '%@%' AND email = "\L") OR ("\L" NOT LIKE '%@%' AND email = CONCAT("\L",'@',(SELECT domain FROM domain_ips WHERE ip = "\I")))) AND disableftp=0
If you don't have clear passwords ( eg you are migrating a server where you only have /etc/passwd to work with) you have a couple of choices.
First would be to try cracking the passwords. If you get lucky you can crack a very good percentage of them using a tool like "John the Ripper password cracker".
If you have no luck cracking the passwords then you might need to tweak your mailserver config as follows :
Mod your SASL config to use courier-authlib (rather than talking to the MySQL database directly), and to remove CRAM AUTH options ( which require clear password to be available )
vi /usr/lib/sasl2/postfix.conf# replace all the existing commands with this new block : pwcheck_method: authdaemond authdaemond_path: /usr/local/courier-authlib/var/spool/authdaemon/socket mech_list: plain login
TIP : If you are using x86_64 platform ( eg Opteron ), this file will be found in a different place: /usr/lib64/sasl2/postfix.conf
Add postfix to the daemon group, and tweak the directory permissions slightly, so that postfix applications can gain access to the courier-authlib socket
usermod -G daemon postfix chown root.daemon /usr/local/courier-authlib/var/spool
Mod your courier-authlib config, so that it doesn't try to access the clear passwords column:
vi /usr/local/courier-authlib/etc/authlib/authmysqlrc#MYSQL_CLEAR_PWFIELD clear_password/etc/rc.d/init.d/courier-authlib restart
Mod your courier-imap/pop3d config to remove any of the CRAM auth options (which require any clear passwords to be available )
vi /usr/local/courier-imap/etc/imapdIMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA AUTH=PLAIN AUTH=LOGIN IDLE"vi /usr/local/courier-imap/etc/pop3dPOP3AUTH="PLAIN LOGIN"/etc/rc.d/init.d/courier-imap restart
Mod your pure-ftpd config to look at your crypted password data, rather than clear password data:
vi /etc/pureftpd-mysql.confMYSQLCrypt any# and then go to the MYSQLGetPW line and change any reference of clear_password to password
Each hostname must have a dedicated IP address
Create a PEM file per hostname.
Save each of them to /usr/local/ssl as
$CERTFILE.192.168.1.101 $CERTFILE.192.168.1.102 $CERTFILE.192.168.1.103
Where $CERTFILE is the name you used for the $CERTFILE setting in imapd-ssl and pop3d-ssl conf files
Courier will look for a certfile with matching ip. If it doesn't find one, it will fallback to trying to use "somecert"
We have found that spammers will often forge the SMTP HELO address when they make a connection to Postfix. It seems fairly common for them to use the hostname or IP address of your server.
To block such spam, first create a list of hostnames and IPs used by your server :
vi /etc/postfix/helo.access## Deny connections from people forging our hostnames mail.yourdomain.com REJECT You are not me mail-mx.yourdomain.com REJECT You are not memail.domain1.com REJECT You are not me mail.domain2.com REJECT You are not me mail.domain3.com REJECT You are not medomain1.com REJECT Use of that helo name is not permitted domain2.com REJECT Use of that helo name is not permitted domain3.com REJECT Use of that helo name is not permitted## Deny connections from people forging our IP 192.168.1.10 REJECT You are not me 192.168.1.11 REJECT You are not me 192.168.1.101 REJECT You are not me 192.168.1.102 REJECT You are not me 192.168.1.103 REJECT You are not mepostmap /etc/postfix/helo.access
Then tell Postfix to do helo filtering (if you uncomment the warn_if_reject line, hits will be logged but not actually rejected - which can be good for initial testing ) :
vi /etc/postfix/main.cfsmtpd_helo_required = yes smtpd_helo_restrictions = permit_mynetworks, check_helo_access hash:/etc/postfix/helo.access, # warn_if_reject, reject_invalid_helo_hostname, permitpostfix reload
To check for hits, try
tail -f /var/log/maillog | grep "Helo command rejected"
The RFC's state that you aren't meant to reject mail based on the data presented in the helo command, however after much analysis of our logs we have found that all the hits we are getting are SPAM. I have yet to see any legit users be affected by this piece of config, so I am satisfied that it is a safe and worthwhile mod. If you are unsure, then uncomment the warn_if_reject line and inspect the results before going live.
In one of the sections above, I show how to set multiple smtp-auth domains for Postfix. The same technique can be used to set multiple SSL domains.
Don't set a default global SSL domain in in main.cf
smtpd_tls_key_file = smtpd_tls_cert_file =
Set use them as -o entries instead in master.cf eg
192.168.1.101:smtp inet n - n - 30 smtpd-domain1 -o smtpd_tls_key_file=/usr/local/ssl/mail.domain1.com.key -o smtpd_tls_cert_file=/usr/local/ssl/mail.domain1.com.crt 192.168.1.102:smtp inet n - n - 30 smtpd-domain2 -o smtpd_tls_key_file=/usr/local/ssl/mail.domain2.com.key -o smtpd_tls_cert_file=/usr/local/ssl/mail.domain2.com.crt 192.168.1.103:smtp inet n - n - 30 smtpd-domain3 -o smtpd_tls_key_file=/usr/local/ssl/mail.domain3.com.key -o smtpd_tls_cert_file=/usr/local/ssl/mail.domain3.com.crt
HAVE TO TEST THIS STILL
Some mail servers will not need SSL functionality enabled. Usually due cost savings that can be made particularly if you are hosting a large number of domains. You can self-sign certs, but that is usually only suitable for testing. In production your users will complain about the security warnings generated by their mail client / web browser.
Disable SSL in Postfix
vi /etc/postfix/master.cfremark out the smtps service (and any associated -o arguments)
vi /etc/postfix/main.cfsmtpd_use_tls = nopostfix reload
Disable SSL in courier-imap / courier-pop3d
vi /usr/local/courier-imap/etc/imapd-sslIMAPDSSLSTART=NO IMAPDSTARTTLS=NO
vi /usr/local/courier-imap/etc/imapd-sslPOP3DSSLSTART=NO POP3_STARTTLS=NO/etc/rc.d/init.d/courier-imap restart
Disable SSL in Apache
INSTRUCTIONS TO BE ADDED
http://fuzzyocr.own-hero.net/wiki/Downloads
This is a plugin for SpamAssassin that uses OCR tools to grab the words from inside those annoying image-based spams
NOTE : I have been tinkering with this on a few different machines. It seems to run OK on machines that have only light load, but when I try to run it on some of our busier equipment, I am seeing problems with crashed spamd or amavisd processes. Have tried tinkering with different package versions, patches, source vs RPM install without much success. So it seems the concept is a good one, but maybe we wont be able to use it in busy production environment until some new builds of the software are available.
Install gifsicle application ( a tool which we will use to get info about GIFs )
cd /usr/local/src wget http://www.lcdf.org/gifsicle/gifsicle-1.44.tar.gz tar xzf gifsicle-1.44.tar.gz chown -R root.root gifsicle-1.44 cd gifsicle-1.44 ./configure --disable-gifview make make install
Install gOCR prerequisite modules, which do things like convert gif/jpg/png/tiff to pbm format
# Tools to convert gif/jpg/png/tiff files to pnm "portable anymaps" format yum install netpbm netpbm-progs netpbm-devel# Now we need to install some more tools : # * giffix tool which allows us to intentionally corrupted GIFs # * giftext tool which dumps text info about a GIF file ( which has a bug and needs to be patched ) # Although these are available as RPM's, we cant use them as the giftext program contains # a bug which can cause segfaults. So instead we need to grab the source, patch it and then # compile/installyum remove libungif libungif-progscd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/libungif/giflib-4.1.4.tar.gz tar xzf giflib-4.1.4.tar.gz chown -R root.root giflib-4.1.4 cd giflib-4.1.4cd util wget http://users.own-hero.net/~decoder/fuzzyocr/giftext-segfault.patch patch < giftext-segfault.patch cd .../configure make make install
Install the gOCR application (which reads pnm archives)
# grab the gOCR source ( FuzzyOcr author recommends 0.40, not 0.41) cd /usr/local/src wget http://optusnet.dl.sourceforge.net/sourceforge/jocr/gocr-0.40.tar.gz tar xzf gocr-0.40.tar.gz chown -R root.root gocr-0.40 cd gocr-0.40# Apply patch for a bug thats been identified wget http://users.own-hero.net/~decoder/fuzzyocr/gocr-segfault.patch patch -p0 < gocr-segfault.patch./configure# TIP: On CentOS, but not Fedora, the configure script experiences a failed dependency on the maths library, # which causes the netpbm libraries to be rejected : # checking for library containing pnm_readpnminit... no # * * * try option --with-netpbm=PATH # The workaround is to use this command instead : ./configure LIBS=-lmmake make install
Install the ocradd application ( which reads pbm formats, and outputs text. Its similar to gOCR, and can be used to give "2nd opinion")
# Some of the boxes I was experimenting with needed this # (although I assume it should already been installed if you ticked development tools as per my doco) yum install gcc-c++cd /usr/local/src wget ftp://gnu.mirror.pacific.net.au/gnu/gnu/ocrad/ocrad-0.16.tar.bz2 tar xjf ocrad-0.16.tar.bz2 chown -R root.root ocrad-0.16 cd ocrad-0.16 ./configure make make install
Install some perl modules used by the FuzzyOcr SpamAssassin plugin
perl -MCPAN -e shell o conf prerequisites_policy follow install String::Approx MLDBM quit
Install the FuzzyOcr plugin for SpamAssassin
# grab the source cd /usr/local/src wget http://users.own-hero.net/~decoder/fuzzyocr/fuzzyocr-3.4.2-devel.tar.gz tar xzf fuzzyocr-3.4.2-devel.tar.gz chown -R root.root FuzzyOcr-3.4.2cd FuzzyOcr-3.4.2cp FuzzyOcr.pm /etc/mail/spamassassin cp FuzzyOcr.cf /etc/mail/spamassassinecho "### MAKE SURE YOU DONT PUT ANY BLANK LINES IN HERE ###" > /etc/mail/spamassassin/FuzzyOcr.words echo "###" >> /etc/mail/spamassassin/FuzzyOcr.words echo "### * Matches are case insentive" >> /etc/mail/spamassassin/FuzzyOcr.words echo "### * All special chars, spaces or numbers are stripped before any matching is done" >> /etc/mail/spamassassin/FuzzyOcr.words echo "### * Your wordlist word will be found even if its inside another word ( submatching )" >> /etc/mail/spamassassin/FuzzyOcr.words cat FuzzyOcr.words.sample >> /etc/mail/spamassassin/FuzzyOcr.words echo "goldmark" >> /etc/mail/spamassassin/FuzzyOcr.words echo "gdki" >> /etc/mail/spamassassin/FuzzyOcr.words echo "l intl computers inc" >> /etc/mail/spamassassin/FuzzyOcr.words echo "metropolis technologies" >> /etc/mail/spamassassin/FuzzyOcr.words echo "### MAKE SURE YOU DONT PUT ANY BLANK LINES IN HERE ###" >> /etc/mail/spamassassin/FuzzyOcr.wordstouch /etc/mail/spamassassin/FuzzyOcr.log chown clamav.clamav /etc/mail/spamassassin/FuzzyOcr.logtouch /etc/mail/spamassassin/FuzzyOcr.db chown clamav.clamav /etc/mail/spamassassin/FuzzyOcr.dbtouch /etc/mail/spamassassin/FuzzyOcr.safe.db chown clamav.clamav /etc/mail/spamassassin/FuzzyOcr.safe.dbvi /etc/mail/spamassassin/FuzzyOcr.cffocr_logfile /etc/mail/spamassassin/FuzzyOcr.logfocr_bin_gifsicle /usr/local/bin/gifsicle focr_bin_giffix /usr/local/bin/giffix focr_bin_giftext /usr/local/bin/giftext focr_bin_gifinter /usr/local/bin/gifinter focr_bin_gocr /usr/local/bin/gocr focr_bin_ocrad /usr/local/bin/ocradfocr_scansets $gocr -i $pfile, $gocr -l 180 -d 2 -i $pfile, $ocrad -s5 -T 0.5 $pfilefocr_threshold 0.2focr_add_score 0.25 focr_counts_required 3focr_enable_image_hashing 2 focr_db_hash /etc/mail/spamassassin/FuzzyOcr.db focr_db_safe /etc/mail/spamassassin/FuzzyOcr.safe.db
Test to see if your installation is working properly :
cd samples spamassassin -t < png.eml spamassassin -t < jpeg.eml spamassassin -t < animated-gif.eml spamassassin -t < corrupted-gif.eml
If you have been running Amavisd/Spamassassin for a while before installing this plugin, I think its a good idea to zap your existing auto-whitelist and bayes database files so that they will be rebuilt more accurately now we have OCR capabilities :
/etc/rc.d/init.d/amavisd stop cd ~clamav/.spamassassin rm * /etc/rc.d/init.d/amavisd start
Back to Michael's ISP Links page
Last updated
03-May-2007
Please send me your feedback!
3rd May :
Upgrade to SpamAssassin 3.2.0
2nd May :
Upgrade to Postfix 2.4.1
Upgrade to Courier-Authlib 0.59.3
Upgrade to Maildrop 2.0.4
Upgrade to Courier-IMAP 4.1.3
Upgrade to SqWebMail 5.1.6
24th April :
Upgraded to Amavisd v2.5.0
13th April :
Upgraded to ClamAV 0.90.2
2nd April :
Show how to disable imap service reporting from logwatch scripts
Upgraded to Postfix 2.4.0
19th March :
Updated to Postfix 2.3.8
Changed CentOS 4.3 to 4.4
15th March :
Added "parent_domain_matches_subdomains =" to the postfix main.cf to allow for less confusion in access maps : "somedomain.com" will match only that domain and ".somedomain.com" will match subdomains.
Added modified_by and server columns to Postfix MySQL tables. On my installs modified_by will contain persons name etc, or scripts name that modified the entry last. The server column is going to be used by me for some MySQL replication testing for clusters of mailservers
5th March :
Update to ClamAV 0.90.1
19th February :
Added webnodsn=1 to courier-authlib config.
14th February :
Upgraded to ClamAV 0.90
Upgraded to SpamAssassin 3.1.8
9th February :
Added a tip about reducing the logging levels for sqlgrey on busy servers
7th February :
Moved the no_address_mappings setting from Postfix main.cf to master.cf, so that amavisd sees the after-virtual-alias-expansion address rather than the before-virtual-alias-expansion address. This is important because amavisd is doing lookups against the mailbox table to extract per-user antispam/antivirus settings. The email addresses stored in the mailbox table will only match correctly once virtual-alias-expansion has been done. Eg if you had a virtual alias of fred@some-virtual-alias-domain.com which forwards to user1@some-virtual-mailbox-domain.com, then you need amavisd to see the user1@some-virtual-mailbox-domain.com address, because that is the one that is stored in the mailbox table.
Removed the smtp-amavis process limit from master.cf and replaced it with smtp-amavis_destination_concurrency_limit in main.cf. This is important only if you need to exceed a concurrency of 20. Without making this change postfix's default destination concurrency limit of 20 would cap the number of smtp-amavis processes at 20 even if you were setting a higher process limit in master.cf. Also added -o lmtp_connection_timeout=2 to the smtp-avamis process in master.cf. Note these changes are really important for large installations where multiple dedicated amavisd servers are in use.
5th February :
Added at create-missing-softquotas.pl script to allow auto-creation of any missing softquota files.
2nd February :
Changes the SNMP / MRTG to monitor LMTP (Postfix -> Amavis) rather than smtpd-av (Amavis -> Postfix) processes. The Postfix -> Amavis direction is where bottlenecks will show up, not the other direction.
29th January :
Added some notes about setting the Maildrop concurrency in Postfix master.cf
Added some notes about setting the SMTP-MX concurrency in Postfix master.cf
Provided some example hardware configs for larger servers
Remind people not to forget about adding reverse DNS entries
Show how to create a local account for SSH use, and how to disable root SSH logins
Upgrade Amavis to v2.4.4
Upgrade to Postfix v2.3.6
Upgrade to ClamAV v0.88.7
25th January 2007 :
Added a note showing how to use /root/.my.cnf
Added info showing how to disable Postfix and amavis services from being included in the nightly logwatch reports
Added Postfix HELO filtering example
Disable SMTP-AUTH for Postfix smtpd-mx service
Added some preliminary info showing how to host one SSL cert per domain in Postfix
Added some preliminary info showing how to turn off SSL if its not required
15th December :
Added a note about creating a link for /usr/lib/sendmail
6th December :
Added notes to dedicated amavisd server section regarding $localhost_name setting
Slightly tweaked the rebuild-ftp-softquotas.pl script
27th November :
added spam_lovers_maps and whitelist_sender_maps to /etc/amavisd.conf
7th November :
Update to Postfix-2.3.4
Update to ClamAV-0.88.6
30th October :
Update to ClamAV-0.88.5
Update to SpamAssassin-3.1.7
27th October :
Tweak the postfix/amavisd content-filter docs to use improved -o options in the smtpd-av section, and also to specify receive_override_options=no_address_mappings in main.cf
Added some FuzzyOCR notes. Still trialling this on some live servers, but it looks pretty good!
26th October :
Added fix error when trying to create new Turba addressbook. (Have to set shares to be localsql in the Turba config screen)
19th September :
Added info about the CentOS fastestmirror plugin for yum
13th September :
Relocated site to new URL
Added note column to recipient_access, sender_access, client_access MySQL tables, to allow optional freeform note to be attached to entry.
8th September :
Remove "--without-db" configure switch from maildrop. This flag was preventing some of maildrop's autoresponder functionality.
4th September :
Increased the php.ini max_execution_time and memory_limit values, as the previous ones seemed too small to handle larger attachment uploads
Upgrade to sqwebmail-5.1.3
Tweaked the pear commands showing how to upgrade all the modules
Added installation instructions for the wvHtml package which is used by IMP Webmail. Also show how to disable two other IMP helpers xlhtml and ppthtml
31st August 2006 :
Added tips to YUM, SASL, Postfix, and PureFTPd for getting x86_64 platform to work smoothly
Upgraded to SpamAssassin 3.1.5, and Postfix 2.3.3
18th August 2006 :
Added the authtest and authenumerate troubleshooting tips for courier-authlib
8th August 2006 :
Update to SpamAsssassin-3.1.4, ClamAV-0.88.4
Showed how you can combine catchall alias entries and virtual mailbox domains. Requires tweak of Postfix virtual_alias_maps , and addition of mysql-virtual-mailbox-to-alias-maps.cf file.
4th August 2006 :
Tidied up the Horde logo examples
Added some more notes about the admin email address that you nominate when setting up Horde
1st August 2006 :
Upgraded to Postfix 2.3.2
Moved the "yum install pcre-devel" back to an earlier position in the guide, since Postfix can make use of this library when its present
28th July 2006
Upgraded to Postfix 2.3.1. Changes involve adding -DUSE_CYRUS_SASL to the Postfix make, and then in main.cf :
change smtpd_sasl_application_name to smtpd_sasl_path
change reject_invalid_hostname to reject_invalid_helo_hostname
adding smtpd_sasl_authenticated_header = yes
Upgraded to amavisd 2.4.2
Added the wbusexsender=1 option to courier-authlib DEFAULTOPTIONS, so that sqwebmail will add an X-Sender header to each outgoing message
Added cyrus-sasl-devel to the list of packages to install during SASL setup. These libraries are needed to allow Postfix to compile
19th July 2006
Fixed error in Courier-Authlib MYSQL_QUOTA_FIELD. ( Need to concatenate an "S" to the quota string )
Removed bat and cmd files from the amavisd banned list
14th July 2006
Tweaked the SpamAssassin local.cf to add some info on trusted_networks setting
Cleaned up the example 192.168 IPs to make then consistent throughout document
Added some more explanation of the /etc/maildroprc file
Tweaked the httpd logrotate.conf
Added examples showing how to add abuse and postmaster to postfix recipient_access
3rd July 2006
Tweaked the proxy_read_maps so we can can "proxy:" the check_client|sender|recipient_access entries in smtpd_recipient_restrictions
Did a bit of tweaking to the apache config, still could do with a bit more work. Eg demonstrate how to have 1 SSL cert per domain
Added some notes explaining how in the example data we are "hashing" the path to the user dirs
29th June 2006
Switched wording to recommend using CentOS. Left notes in saying that Fedora will also work.
Added some debugging notes for Maildrop
22nd June 2006
Added "AND disableftp=0" clauses to the Pureftp MySQL select commands.
15th June 2006 :
Added description of how to set an smtp-auth default domain per hostname
14th June 2006 :
Exclude MySQL from crontabbed yum updates. On on of my production serves I saw mysql-4.1.19 shutdown and 4.1.20 not start automatically after the update. Needless to say, the server doesnt work too well if MySQL is down!
Tweaked some of the wording in the maildrop section. Also increased the smallmsg size there, to reduce disk I/O at the expense of higher RAM consumption.
Move the "yum install pcre-devel gamin-devel" into the courier-authlib section. Authlib doesnt need these libraries, but others like maildrop do.
Added tips about using RR DNS entry for multiple Amavisd boxes. Also added the tip about using a RAM disk for the amavisd tmp folder. Also the tip about only content scanning inbound mail
9th June 2006 :
Added notes about removing non-necessary apache modules from httpd.conf.
Tweaked the Horde customisations to show how to display HTML attachments inline
26th May 2006 :
Update to Amavisd 2.4.1, SpamAssassin 3.1.2
25th May 2006
Update to Courier-IMAP 4.1.1 and SqWebMail 5.1.2
19th May 2006
Initial linking and announcement of the page