August 24, 2007 by duynam

The Installation and Configuration of a Cisco PIX Firewall

Xem file đính kèm. Một số nội dung cụ thể như sau:

Mô hình:

Internet
|
External Router
|192.168.1.2
|
|E0utside2 192.168.1.1 security0
——-
| PIX |—–E2MZ 172.17.1.1 security50
——-
|E1:inside 172.16.0.1 security 100
|
|172.16.0.2
Internal Router
172.16.0.0/24 network

Cấu hình như sau:
pixfirewall(config)# hostname PIX1
PIX1(config)#enable password cisco
PIX1(config)#nameif ethernet2 DMZ sec50
PIX1(config)#ip address dmz 172.17.1.1 255.255.255.0
PIX1(config)#ip address inside 172.16.0.1 255.255.255.0
PIX1(config)#ip address outside 192.168.1.1 255.255.255.0
PIX1(config)#interface ethernet0 auto
PIX1(config)#interface ethernet1 auto
PIX1(config)#interface ethernet2 auto

Có 4 kỹ thuật nat dùng trên PIX:
- Static nat: thực hiện map 1 ip – 1 registered ip
- Dynamic nat: map 1 ip – 1 pool registered ip
- Overloading: map multi-ip – 1 registered ip
- Overlapping: is when IP addresses on your network are registered IP address and used by another network.

Nhưng thông thường sẽ cấu hình như sau:
Dynamic nat:
PIX1(config)#global (outside) 1 192.168.1.254 netmask 255.255.255.0
PIX1(config)#nat (inside) 1 172.16.0.0 255.255.255.0 0 0
PIX1(config)#nat (dmz) 1 172.17.1.0 255.255.255.0 0 0
Nghĩa là:
1. Create a global address 192.168.1.254 with a tag ID of 1.
2. Assign the network 172.16.0.0/24 behind the inside interface the NAT tag ID 1.
3. Assign the network 172.17.1.0/24 behind the dmz interface the NAT tag ID 1.

Static nat:
PIX1(config)#static (inside,dmz) 172.17.1.0 172.17.1.0 netmask 255.255.255.0 0 0
PIX1(config)#static (dmz,outside) 192.168.1.10 172.17.1.10 netmask
255.255.255.0 0 0
PIX1(config)#static (dmz,outside) 192.168.1.20 172.17.1.20 netmask
Nghĩa là
1. Khi traffic đến từ inside network thì sẽ giữ nguyên ip
2.Trafic từ outside khi đến IP 192.168.1.10 sẽ được gửi đến server có ip là 172.17.1.10
3.Trafic từ outside khi đến IP 192.168.1.20 sẽ được gửi đến server có ip là 172.17.1.20

- Để tăng cường security dùng ACL để cho phép 1 số traffic thông dụng:
PIX1(config)#access-list acl_inside permit tcp 172.16.0.0 255.255.255.0 any eq www
PIX1(config)#access-list acl_inside permit tcp 172.16.0.0 255.255.255.0 any eq ftp
PIX1(config)#access-list acl_inside permit tcp 172.16.0.0 255.255.255.0 any eq 443
PIX1(config)# access-list acl_inside permit tcp 172.16.0.0 255.255.255.0 host
172.17.1.20 eq smtp
PIX1(config)#access-list acl_dmz permit tcp 172.17.1.0 255.255.255.0 any eq www
PIX1(config)#access-list acl_dmz permit tcp host 172.17.1.20 any eq smtp
PIX1(config)#access-list acl_outside permit tcp any host 192.168.1.20 eq smtp
PIX1(config)#access-list acl_outside permit tcp any host 192.168.1.10 eq www
PIX1(config)#access-list acl_outside permit tcp any host 192.168.1.10 eq 443
PIX1(config)#access-group acl_inside in interface inside
PIX1(config)#access-group acl_dmz in interface dmz
PIX1(config)#access-group acl_outside in interface outside

Cuối cùng cấu hình định tuyến:
PIX1(config)#route inside 172.16.0.0 255.255.255.0 172.16.0.2 1
PIX1(config)#route outside 0 0 192.168.1.2 1
PIX1(config)#wr mem

Chú ý:
- Nhớ lưu lại cấu hình: PIX1(config)#wr mem
- Xóa bảng translation: PIX1(config)#clear xlate
- Cú pháp static (internal_if_name,external_if_name) global_ip local_ip netmask mask có cách dễ nhớ hơn là: static (high.low) low high
- Các lệnh trong PIX là case-sensitive

Postfix + MySQL

August 13, 2007 by duynam

CentOS + Postfix + MySQL + TLS + SASL + Maildrop + SQLgrey + Amavisd + SpamAssassin + ClamAV + Courier-IMAP + Courier-POP3d + SqWebMail + Horde IMP

Original of this document available at http://www.bowe.id.au/michael/isp/postfix-server.htm


NAVIGATION LINKS

MAIN CHAPTERS :

OPTIONAL CHAPTERS ( FOR LARGER / MORE-COMPLEX SERVERS )

“UNDER CONSTRUCTION” CHAPTERS

OTHER


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 :

  • Use at least Fedora Core 4, as this gives you MySQL v4. FC3 and earlier has MySQL v3. You want at least MySQL v4 as so you have access to some important performance improvements such as query caching.
  • Each Fedora Core release only includes a very short period of update maintenance. Typically updates are only available for the previous-to-current version of Fedora. So for example if the current version is FC5, you will soon not be able to get any more mainstream RPM updates for FC3. This is a large contrast to CentOS which is based on RHEL where you have updates available for years. Availability of updates is a very important security consideration.

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 :

  • 60K mailboxes, Dual Xeon 2.8Ghz, 2Gb RAM, 2 x SCSI disk RAID1 for O/S, 4 x SCSI disk RAID5 for mailboxes, 2 x P4 Amavisd offload machines
  • 45K mailboxes, Dual Opteron 248, 2Gb RAM, 2 x Raptor SATA RAID1 for O/S, 6 x Raptor RAID5 for mailboxes, 2 x P4 Amavisd offload machines
  • 45K mailboxes, Dual Xeon 2.8Ghz, 1.5Gb RAM, 2 x SCSI disk RAID1 for O/S, 4 x SCSI disk RAID5 for mailboxes, 2 x P4 Amavisd offload machines

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.


INSTALL CENTOS

http://www.centos.org

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 :

  • Choose eth0, edit
    • Configure using DHCP : unticked
    • Activate on boot : ticked
    • IP address : eg 192.168.1.10
    • Netmask : eg 255.255.255.0
  • Set hostname manually : ticked
  • Gateway : eg 192.168.1.1
  • Primary DNS : eg 192.168.1.2
  • Secondary DNS : eg 192.168.1.3

Firewall Configuration :

  • Enable Firewall
  • Tick : SSH, HTTP, FTP, SMTP
  • Enable Selinux : Disabled

Additional Language Support :

  • Tick : English ( Australia )
  • Choose English (Australia) from the dropdown box at the top

Timezone Selection :

  • Choose your city on the map
  • System clock uses UTC : Unticked

Set root Password : ChooseSomethingGood!

Package Group Selection :

  • Leave default selections as-is, except for :
  • Editors : tick
  • Windows file server : untick
  • MySQL database : tick, Click on details, mysql-server : tick
  • Development tools : tick
  • Printing support : untick

TWEAK THE CENTOS INSTALL

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 : snmp
vi /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/fstab
LABEL=/tmp /tmp ext3 defaults,nosuid,noexec 1 2
LABEL=/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.tmp
vi /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-fastestmirror
vi /etc/yum.conf
plugins=1

Then give the server a reboot

shutdown -r now

UPDATE ALL THE RPMS

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 libraries

vi /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

CREATE THE SSL CERTIFICATES

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 1024
Generating 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.csr
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]: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 1024
Generating 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.crt
Enter 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.crt
Signature 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 -al
total 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

http://www.mysql.com

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.

mysql
GRANT 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

SASL ( FOR SMTP-AUTH )

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.conf
pwcheck_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

POSTFIX

http://www.postfix.org/

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 postfix
groupadd -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.gz
tar 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'
make
make 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.com

mydestination	= $myhostname, localhost.$mydomain, localhost
local_recipient_maps = unix:passwd.byname $alias_maps

mynetworks	= $config_directory/mynetworks
relayhost	= [smarthost.yourdomain.com]  #<-- if you have a smarthost server

alias_maps	= hash:/etc/aliases

home_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 server

smtpd_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 = no

smtp_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 file

virtual_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	= 20480000

virtual_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.cf
echo "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.cf
echo "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.cf
echo "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.cf
echo "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.cf
echo "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.cf
echo "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/postfix
chmod 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/aliases
root:    someone@yourdomain.com
newaliases

Try starting Postfix

/etc/rc.d/init.d/postfix start

If 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 -u

Also, 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

INSTALL A 2ND ETHERNET IP

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=no
cd /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.

SQLGREY GREYLISTING

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 mirrors
o conf prerequisites_policy follow
install MD5 LWP Net::Server IO::Multiplex DBD::mysql
quit

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

mysql
CREATE 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.conf
reconnect_delay = 1
awl_age = 32
group_domain_level = 10
db_type = mysql
optmethod = optout
admin_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/sqlgrey
vi /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 -k
chkconfig --add sqlgrey
chkconfig sqlgrey on

Start the program

/etc/rc.d/init.d/sqlgrey start

If 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.cf
reject_rbl_client list.dsbl.org,
reject_rbl_client sbl-xbl.spamhaus.org,
check_policy_service inet:127.0.0.1:2501,
permit
postfix 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 :

mysql
USE 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

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.bz2
tar 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-redhat
make
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/authmysqlrc
MYSQL_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 start

ps 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

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.bz2
tar 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-maildirquota
make
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/etc
vi /usr/local/etc/quotawarnmsg
# tweak wording to suit your needs
vi /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>

COURIER-IMAP / COURIER-POP3D

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.bz2
tar 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-redhat
make
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=0
IMAP_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=YES
vi /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.pem
vi /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=YES
vi /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 start

ps 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

APACHE

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.conf
LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_vhost
NameVirtualHost *: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.com
    ErrorLog /var/www/mail/logs/error_log
    CustomLog /var/www/mail/logs/access_log combined_vhost
    RewriteEngine on
    RewriteRule ^/index\.html$ http://%{HTTP_HOST}/cgi-bin/sqwebmail
    ScriptAlias /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/html
    SSLCertificateFile /usr/local/ssl/mail.yourdomain.com.crt
    SSLCertificateKeyFile /usr/local/ssl/mail.yourdomain.com.key
    ErrorLog /var/www/mail/logs/ssl_error_log
    RewriteEngine On
    RewriteRule ^/index\.html$ http://mail.yourdomain.com/cgi-bin/sqwebmail
    ScriptAlias /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.0
    CustomLog /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.com
    ErrorLog /var/www/users/logs/error_log
    CustomLog /var/www/users/logs/access_log combined_vhost
    DirectoryIndex 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.com
    php_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.ico
cd /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 {

SQWEBMAIL

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.bz2
tar 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.sh
make
make install
make install-configure

Allow sqwebmail users to use (maildrop) message filtering rules

vi /usr/local/sqwebmail/etc/maildirfilterconfig
MAILDIRFILTER=../.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 start

If 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

CLAM ANTIVIRUS

http://www.clamav.net/

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.gz
tar 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-vcheck
make
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 clamav
ln -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 clamd
vi /etc/rc.d/rc.local
/usr/local/bin/freshclam -d

Start the daemons

/etc/rc.d/init.d/clamd start
/usr/local/bin/freshclam -d

ps axf should give something like this :

11139 ? Ss 0:00 /usr/local/sbin/clamd
11142 ? Ss 0:00 /usr/local/bin/freshclam -d

SPAMASSASSIN

http://spamassassin.apache.org/

Install the prerequisite perl modules

perl -MCPAN -e shell
o 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::HiRes
quit

Download and unpack the sources

cd /usr/local/src
wget http://apache.mirror.pacific.net.au/spamassassin/source/Mail-SpamAssassin-3.2.0.tar.gz
tar 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

AMAVISD

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 shell
o 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::mysql
quit

Download and unpack the sources

cd /usr/local/src
wget http://www.ijs.si/software/amavisd/amavisd-new-2.5.0.tar.gz
tar 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/amavis
cp amavisd /usr/local/sbin/
chown root /usr/local/sbin/amavisd
chmod 755 /usr/local/sbin/amavisd
cp 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 amavisd
vi /etc/rc.d/init.d/amavisd
prog="/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.cf

content_filter=smtp-amavis:[127.0.0.1]:10024
smtp-amavis_destination_concurrency_limit=10

vi /etc/postfix/master.cf

smtp-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=20
127.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_mappings
cd /usr/libexec/postfix
ln -s smtpd smtpd-av
postfix 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

http://www.pureftpd.org

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 \
  ......etc

make
make install-strip

Setup the config file by making these changes

cp pureftpd-mysql.conf /etc
vi /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=0
chmod 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.txt
chmod 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 --daemonize

If 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.pl
crontab -e
### Periodically recalc all the ftp softquotas ( just in case )
0 2 * * Sun /bin/nice /usr/local/sbin/rebuild-ftp-softquotas.pl

LAST BITS OF CLEANUP

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=newpwd
chmod 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 someuser
vi /etc/ssh/sshd_config
PermitRootLogin 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.pl
crontab -e
0 3 * * * /bin/nice /usr/local/sbin/create-missing-softquotas.pl

SAMPLE / TEST DATA

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());

MRTG / SNMP

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.sh
echo '#!/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.sh
echo '#!/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.conf
echo '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.conf
echo '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 start

ps 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);

OPTIONAL CHAPTERS FROM HERE ON DOWN!
THIS STUFF WILL LIKELY APPLY IF YOU ARE BUILDING A LARGER / MORE COMPLEX SERVER :-)


DEDICATED AMAVISD SERVER

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-networking

In 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 servers

In 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-devel

Follow 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

HORDE SUITE

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 enscript
pear 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 wv

On CentOS its a bit more work involved, you need to do this :

yum install zlib zlib-devel libpng libpng-devel
cd /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.gz
cd /var/www/mail/html
tar xzf /usr/local/src/horde-3.1.1.tar.gz
chown -R root.apache horde-3.1.1
chmod -R o-rwx horde-3.1.1
mv horde-3.1.1 horde
cd horde
cd 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 config
cd /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.gif
http://mail.yourdomain.com/horde/test.php
http://mail.yourdomain.com/horde/
click on Administration->Setup
In the Application screen, click on Horde
Database ->
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 : horde
Preference system ->
Preference driver : SQL Database
DataTree System ->
Backend : SQL Database
Mailer ->
The location of sendmail binary : /usr/sbin/sendmail
Virtual File Storage ->
Backend : SQL Database
Custom sessions handler ->
Sessionhandler : MySQL based sessions
Request 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 : horde
MIME Detection ->
location : /usr/share/misc/magic
Problem Reporting ->
whre should problem reports be sent : support@yourdomain.com
Menu 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.com
Click on generate horde config

If 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

http://www.horde.org/imp/

cd /usr/local/src
wget ftp://ftp.planetmirror.com/pub/horde/imp/imp-h3-4.1.1.tar.gz
cd /var/www/mail/html/horde
tar xzf /usr/local/src/imp-h3-4.1.1.tar.gz
chown -R root.apache imp-h3-4.1.1
chmod -R o-rwx imp-h3-4.1.1
mv imp-h3-4.1.1 imp
cd imp
cd config/
for foo in *.dist; do cp $foo `basename $foo .dist`; done
vi 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 config
vi templates/login/login.inc
replace
  echo _("Username")
with
  echo _("Email address")
http://mail.yourdomain.com/horde/imp/test.php
http://mail.yourdomain.com/horde/
click on Administration->Setup
In the Application menu, click on Mail (imp)
External Utilities and Menu
Location of aspell : /usr/bin/aspell
Applications that should be linked to IMPs menu : imp, ingo, koronlith, turba
Compose
Should we append the contents of imp/config/trailer.txt : unticked
Can the user request a return receipt : unticked
send attachments as links : no
maximum size of attachments : 17000000
Click on Generate Mail Configuration

TURBA ADDRESS BOOK

cd /usr/local/src
wget ftp://ftp.planetmirror.com/pub/horde/turba/turba-h3-2.1.tar.gz
cd /var/www/mail/html/horde
tar xzf /usr/local/src/turba-h3-2.1.tar.gz
chown -R root.apache turba-h3-2.1
chmod -R o-rwx turba-h3-2.1
mv turba-h3-2.1 turba
cd turba
cd config/
for foo in *.dist; do cp $foo `basename $foo .dist`; done
vi sources.php
remove all sources except the localsql one
cd ..
chown -R root.apache config
chmod -R g+rw config
cd scripts/sql
mysql horde < turba_objects.mysql.sql
cd ../..
http://mail.yourdomain.com/horde/turba/test.php
http://mail.yourdomain.com/horde/
click on Administration->Setup
In the Application menu click on Address Book ( turba)
Select any applications that should be linked to turbas menu : imp, ingo, kronolith, turba
Name of source for creating new shares : localsql
Click 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.gz
cd /var/www/mail/html/horde
tar xzf /usr/local/src/kronolith-h3-2.1.1.tar.gz
chown -R root.apache kronolith-h3-2.1.1
chmod -R o-rwx kronolith-h3-2.1.1
mv kronolith-h3-2.1.1 kronolith
cd kronolith
cd config/
for foo in *.dist; do cp $foo `basename $foo .dist`; done
cd ..
chown -R root.apache config
chmod -R g+rw config
cd scripts/sql
mysql horde < kronolith.mysql.sql
cd ../..
http://mail.yourdomain.com/horde/
click on Administration->Setup
In the Application menu, click on Calendar (Kronolith)
Server name from which reminders are sent : mail.yourdomain.com
Email address from which reminders are send : reminder@mail.yourdomain.com
Applications that should be linked to the Konolith menu : imp, ingo, kronolith, turba
Click on Generate Calender Configuration

INGO FILTERS

cd /usr/local/src
wget ftp://ftp.planetmirror.com/pub/horde/ingo/ingo-h3-1.1.tar.gz
cd /var/www/mail/html/horde
tar xzf /usr/local/src/ingo-h3-1.1.tar.gz
chown -R root.apache ingo-h3-1.1
chmod -R o-rwx ingo-h3-1.1
mv ingo-h3-1.1 ingo
cd ingo
cd config/
for foo in *.dist; do cp $foo `basename $foo .dist`; done
cd ..
chown -R root.apache config
chmod -R g+rw config
http://mail.yourdomain.com/horde/ingo/test.php
http://mail.yourdomain.com/ingo/
click on Administration->Setup
In the Application menu, click on Filters (Ingo)
Select applictions that should be linked to ingo's menu : imp, ingo, kronolith, turba
Click 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.gz
cd /var/www/mail/html/horde
tar xzf /usr/local/src/nag-h3-2.1.tar.gz
chown -R root.apache nag-h3-2.1
chmod -R o-rwx nag-h3-2.1
mv nag-h3-2.1 nag
cd nag
cd config/
for foo in *.dist; do cp $foo `basename $foo .dist`; done
cd ..
chown -R root.apache config
chmod -R g+rw config
cd scripts/sql
mysql -p horde < nag.sql
cd ../..
http://mail.yourdomain.com/horde/nag/test.php
http://mail.yourdomain.com/horde/
click on Administration->Setup
In 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.gz
cd /var/www/mail/html/horde
tar xzf /usr/local/src/mnemo-h3-2.1.tar.gz
chown -R root.apache mnemo-h3-2.1
chmod -R o-rwx mnemo-h3-2.1
mv mnemo-h3-2.1 mnemo
cd mnemo
cd config/
for foo in *.dist; do cp $foo `basename $foo .dist`; done
cd ..
chown -R root.apache config
chmod -R g+rw config
cd scripts/sql
mysql -p horde < mnemo.sql
cd ../..
http://mail.yourdomain.com/horde/mnemo/test.php
http://mail.yourdomain.com/horde/
click on Administration->Setup
In 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/horde
Clock on Administration -> Setup
In the Application menu, click on Horde
Authentication ->
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 authentication
The application that is providing authentication : imp
Click on Generate Horde Configuration
you 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

SETTING A DEFAULT IMAP/POP3 DOMAIN PER HOSTNAME

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/imapd
TCPDOPTS="-nodnslookup -noidentlookup -access=/usr/local/courier-imap/etc/default-domains.db -accesslocal"
vi /usr/local/courier-imap/etc/pop3d
TCPDOPTS="-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

SETTING A DEFAULT SQWEBMAIL DOMAIN PER HOSTNAME

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:@

SETTING A DEFAULT SMTP-AUTH DOMAIN PER HOSTNAME

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.

SETTING A DEFAULT PURE-FTPD DOMAIN PER HOSTNAME

You can set a default login doman domain based on the IP address the user has connected to

Create a IP <-> Domain mapping table :

mysql
USE 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.conf
MYSQLGetPW 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=0
MYSQLGetDir 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=0
MySQLGetQTASZ 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

WHAT TO DO IF YOU DONT HAVE CLEAR PASSWORDS AVAILABLE

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/imapd
IMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA AUTH=PLAIN AUTH=LOGIN IDLE"
vi /usr/local/courier-imap/etc/pop3d
POP3AUTH="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.conf
MYSQLCrypt any
# and then go to the MYSQLGetPW line and change any reference of clear_password to password

HOSTING MULTIPLE SSL DOMAINS FOR COURIER-IMAP/POP3D

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”


HELO FILTERING FOR POSTFIX

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 me
mail.domain1.com		REJECT You are not me
mail.domain2.com		REJECT You are not me
mail.domain3.com		REJECT You are not me
domain1.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 me
postmap /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.cf
smtpd_helo_required = yes
smtpd_helo_restrictions =
	permit_mynetworks,
	check_helo_access hash:/etc/postfix/helo.access,
	# warn_if_reject,
	reject_invalid_helo_hostname,
	permit
postfix 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.


HOSTING MULTIPLE SSL DOMAINS FOR APACHE / SQWEBMAIL


HOSTING MULTIPLE SSL DOMAINS FOR POSTFIX

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


WHAT TO DO IF YOU DONT WANT TO USE SSL

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.cf

remark out the smtps service (and any associated -o arguments)

vi /etc/postfix/main.cf
smtpd_use_tls = no
postfix reload

Disable SSL in courier-imap / courier-pop3d

vi /usr/local/courier-imap/etc/imapd-ssl
IMAPDSSLSTART=NO
IMAPDSTARTTLS=NO
vi /usr/local/courier-imap/etc/imapd-ssl
POP3DSSLSTART=NO
POP3_STARTTLS=NO
/etc/rc.d/init.d/courier-imap restart

Disable SSL in Apache

INSTRUCTIONS TO BE ADDED


FUZZYOCR

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/install
yum remove libungif libungif-progs
cd /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.4
cd 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=-lm
make
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.2
cd FuzzyOcr-3.4.2
cp FuzzyOcr.pm /etc/mail/spamassassin
cp FuzzyOcr.cf /etc/mail/spamassassin
echo "### 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.words
touch /etc/mail/spamassassin/FuzzyOcr.log
chown clamav.clamav /etc/mail/spamassassin/FuzzyOcr.log
touch /etc/mail/spamassassin/FuzzyOcr.db
chown clamav.clamav /etc/mail/spamassassin/FuzzyOcr.db
touch /etc/mail/spamassassin/FuzzyOcr.safe.db
chown clamav.clamav /etc/mail/spamassassin/FuzzyOcr.safe.db
vi /etc/mail/spamassassin/FuzzyOcr.cf
focr_logfile /etc/mail/spamassassin/FuzzyOcr.log
focr_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/ocrad
focr_scansets $gocr -i $pfile, $gocr -l 180 -d 2 -i $pfile, $ocrad -s5 -T 0.5 $pfile
focr_threshold 0.2
focr_add_score 0.25
focr_counts_required 3
focr_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

MISC NOTES :

  • There is no fancy GUI interface available for managing accounts. With my Qmail guide there was a handy program called QmailAdmin. In the Postfix world it seems that Postfix.Admin is popular. ( Note : my database design isn’t exactly the same as the one for PostfixAdmin ). At my workplace we have written our own perl-based CGI scripts for adding/removing/modifying mailboxes.

TODO :

  • Describe how to build a secondary MX machine which uses the mysql data to be able to validate all recipient addresses
  • Maybe set smtpd_sasl_auth_enable=no in main.cf, and enable only on the required customer-smtpd services in master.cf  ?
  • Provide more explanation about what each database table / column is used for. Include some examples showing how to make use of the amavisd-related columns.
  • Describe these log entries : lookup_sql_field(id) (WARN: no such field in the SQL table), “admin@mydomain.com” result=undef
  • Can add rebuilt ‘Fedora – Extras’ repo to CentOS http://centos.karan.org/, which would allow RPM versons of wv, arc, cabextract, zoo,  freeze, pure-ftpd
  • Add some Postfix examples for smtpd_client_connection_count|rate_limit, smtpd_client_message|recipient_rate_limit
  • Create a sysv script with chkconfig support for sqwebmail
  • Implement the amavisd black/whitelist functionality
  • Find a solution to the “pear install” where it wants to exec programs on the /tmp
  • When you have a virtual alias domain mapping @domain1.com a virtual mailbox domain @domain2.com, it appears postfix is accepting any address on domain1, but it doesn’t then immediately bounce the mail if it doesn’t exist on domain2. It first sends the mail via the content_filter and the message only gets bounced once maildrop tries to lookup the destination maildir. Need to see if we can optimise this a bit.

Back to Michael’s ISP Links page

Last updated 03-May-2007
Please send me your feedback!



ChangeLog :

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

_uacct = “UAtable align=”center” bgcolor=”#cccccc” border=”1″ bordercolor=”#000000″ cellpadding=”2″ cellspacing=”0″ width=”90%”pt> ’s ISP Links pagee

Qmail

August 13, 2007 by duynam

REDHAT + QMAIL + OPENSSL + APACHE + PHP + MYSQL + VPOPMAIL (with MySQL accounts) + COURIER-IMAP + SQUIRRELMAIL (with MySQL prefs/addrbook), QMAIL-SCANNER + CLAM ANTIVIRUS + SPAMASSASSIN

Original of this document is available at http://www.bowe.id.au/michael/isp/webmail-server.htm


MAY 2007 – THIS DOCUMENT IS NO LONGER MAINTAINED.

For the last few years I haven’t done much vpopmail work, because the ISP where I work uses Postfix rather than qmail. I have recently accepted a job offer from a different ISP and they use Postfix there as well. When I switch to this new company it will cut the remaining ties I had with customers using my original qmail/vpopmail design. I haven’t really done many updates to this guide over the last couple of years, and now I have decided that no further updates will be done at all. I thank everyone who has used the guide and sent me feedback over the years. I have recently published a Postfix+MySQL guide, and maybe I will do a Postfix+LDAP guide soon, since this is the combo used at my new place of employment.

I would recommend people consider Bill Shupp’s vpopmail toaster ( Linux ), or perhaps Matt Simerson’s toaster ( FreeBSD )


NAVIGATION LINKS

Jump straight to :


BEFORE YOU START

I would recommend you first learn qmail via www.lifewithqmail.org.

Next do a bit of reading about vpopmail servers : Bill Shupp’s Linux Qmail Toaster, and also  http://www.qmailrocks.org/

Once you have a good grip on all those concepts, come back and read this doc to learn how you can add MySQL back-ends to vpopmail and SquirrelMail  :-)


WHY USE MYSQL FOR THE VPOPMAIL AND SQUIRRELMAIL BACK-ENDS?

By having all the vpopmail account data stored it MySQL, it allows you to easily write web based tools (eg in ASP or PHP) that can talk to the database and then present easy-to-use interface for your support staff to manage the user accounts.  I have included some more info and examples on this subject at the bottom of this doc

You can easily add additional columns to the vpopmail tables to store other “per-user” information without affecting the operation of vpopmail

For a server with many user accounts, you would expect that MySQL would give faster performance than disk based accounts. Particularly when you have a large number of users in a given domain. (I haven’t personally done any benchmarks on this, and I also have never seen anyone else run such a test, but you would have to expect that a SQL based backend would scale better than the file-based cdb backend that qmail/vpopmail uses by default)

If you have a very large number of accounts, vpopmail can be configured to use MySQL replication and NFS to share the load over over multiple servers


ABOUT THESE NOTES

Follow these notes at your own risk…!

All the commands shown below have been run as root.

I have successfully used these notes to build many Redhat 7.2, 7.3 and 8.0 based servers. People have told me that Redhat 9.0 & Fedora will also work, but you have to be aware of a few issues :

  • Most of the qmail software and associated utilities will not compile under RH9 or Fedora, due to conflicts with its new version of glibc. You can get patches to solve these problems from www.qmail.org. (Do a search for “errno”). The actual link for the patches is http://www.qmail.org/moni.csi.hu/pub/glibc-2.3.1/
  • For packages using perl (eg Razor, SpamAssassin), you may need to add an “export LANG=en_US” to your scripts, or alternatively modify the “/etc/sysconfig/i18n” file.

REDHAT 7.2 / 7.3 / 8.0 NOTES

FIREWALL :

The ipchains or iptables firewalling software will usually be installed during Redhat’s installation process.

For this server you will need to make sure you have opened access on at least the following ports :

  • SMTP:TCP
  • HTTP.TCP
  • HTTPS:TCP
  • POP3:TCP
  • NTP:UDP

Note that we arent going to open the IMAP:TCP port, as we are not offering IMAP services directly to our clients. We will be running an IMAP server, but the only program talking to it will be the SquirrelMail software which is also running on this same box.

On Redhat 7.2 / 7.3 (which uses ipchains by default)

You can examine/modify the ipchains config by working on the file :

	/etc/sysconfig/ipchains

If you make any changes to this file, you will need to restart the ipchains software :

	/etc/rc.d/init.d/ipchains restart

On Redhat 8.0 (which uses iptables by default)

You can examine/modify the iptables config by working on the file :

	/etc/sysconfig/iptables

If you make any changes to this file, you will need to restart the iptables software :

	/etc/rc.d/init.d/iptables restart

SETUP TIME SYNCHRONISATION :

Mail servers need to have their clocks set correctly. If you don’t have their time sync’ed, you can experience strange problems.

Redhat comes with the ntpd package which is easy to setup

vi /etc/ntp.conf

look for the “# — OUR TIMESERVERS —–” section
and then put in the following lines :

restrict xxx.xxx.xxx.xxx mask 255.255.255.255 nomodify notrap noquery
server xxx.xxx.xxx.xxx

where xxx.xxx.xxx.xxx is the IP address of your (or your upstream’s) NTP server

After making the changes, you will need to restart the ntpd service :

	/etc/rc.d/init.d/ntpd restart

Use the ntsysv program and make sure the ntpd service is enabled at bootup time

SETUP DNS :

For our example, we setup an A record for hostname.yourdomain.com.  Any domains that we are hosting mail for should have their primary MX pointing to this host. We also created the following CNAME aliases for this host : pop3, smtp, webmail

This allows our users to :

  • access SquirrelMail and qmailadmin via http://webmail.yourdomain.com
  • set their POP3 clients to pop3.yourdomain.com for their incoming mail, and smtp.yourdomain.com for their outgoing mail

IMPORTANT : Never configure a end-user’s software to reference the hostname directly. Even though you might start out with just a single box doing all your email functions, later on you might add other boxes to split the load onto different machines (eg one to handle all the SMTP mail, the other doing POP3/IMAP and another again doing WebMail). By setting your client to use the aliased names, you can add extra boxes and then just update the DNS as appropriate. No changes will be required on the client’s computer. Make sure you take my advice now on this matter. You will thank me for this later!! :-)

CHECK YOUR SYSLOG CONFIG :

You may find that your mail server logs a lot of entries to the syslog. On linux you need to be careful of this as there can be a big performance impact. In particular you should check your /etc/syslog.conf and make sure there is a “-” symbol in front of any files that will be busy eg “-/var/log/maillog”. If you have to add the file, then dont forget to “killall -HUP syslogd” so the changes are picked up. Some more info on this subject here

(OPTIONAL) UPDATE YOUR KERNEL :

RedHat regularly publishes updated versions of the Linux kernel to suit their various RedHat distributions. To ensure that your server has best performance and reliability, it is a good idea to regularly upgrade to the latest available kernel.

RedHat have got some easy-to-follow instructions online :


MYSQL

www.mysql.com

We will be using MySQL to store all the domain and mailbox account information for vpopmail. We are also going to use MySQL to store the SquirrelMail user preferences and address books

Setup an account for the MySQL server to run under :

groupadd mysql
useradd -g mysql mysql

Go to their website and download the latest binaries to /usr/local/src.   In this example I have used the file:

mysql-max-3.23.57-pc-linux-i686.tar.gz

(Note, MySQL v4 has recently been released as “stable”, however I am yet to personally do any vpopmail testing under this new version. I have used MySQL v4 for other jobs, and have had reports from other people that it works fine with vpopmail, so if you are keen you should be safe to give MySQL v4 a go rather than v3)

Unzip / configure the binaries so they get installed to /usr/local/mysql

cd /usr/local
tar xzf /usr/local/src/mysql-max-3.23.57-pc-linux-i686.tar.gz
ln -s mysql-max-3.23.57-pc-linux-i686 mysql

Run the installation script that creates/verifies all the various system-use tables etc

cd mysql
scripts/mysql_install_db
cd ..

Setup permissions on the MySQL dirs

chown -R root.mysql mysql-max-3.23.57-pc-linux-i686
chmod -R 640 mysql
chmod -R u+X,g+X mysql
chmod -R ug+x mysql/bin
chmod -R g+w mysql/data
chmod -R u+x mysql/scripts

Let the MySQL server know what amount of resources it is allowed to use

# choose an appropriate config file from the samples provided
cp /usr/local/mysql/support-files/my-medium.cnf /usr/local/mysql/data/my.cnf
# adjust the permissions on the file so that mysql daemon can read the contents
chgrp mysql /usr/local/mysql/data/my.cnf

Fire up the server

cd /usr/local/mysql
bin/safe_mysqld --user=mysql &

At this point the mysql daemons should be running. A good way to verify this is to use this command :

ps axf

If all is well, you should be able to see something like this :

1073 ? S 0:00 /bin/sh ./bin/safe_mysqld --datadir=/usr/local/mysql/data --pid-file=/usr/local/mysql/data/.pid
1117 ? S 0:00  \_ /usr/local/mysql/bin/mysqld --defaults-extra-file=/usr/local/mysql/data/my.cnf --basedir=/usr/local/m
1125 ? S 0:00      \_ /usr/local/mysql/bin/mysqld --defaults-extra-file=/usr/local/mysql/data/my.cnf --basedir=/usr/loc
1126 ? S 0:00          \_ /usr/local/mysql/bin/mysqld --defaults-extra-file=/usr/local/mysql/data/my.cnf --basedir=/usr
1143 ? S 0:00          \_ /usr/local/mysql/bin/mysqld --defaults-extra-file=/usr/local/mysql/data/my.cnf --basedir=/usr
1419 ? S 0:00          \_ /usr/local/mysql/bin/mysqld --defaults-extra-file=/usr/local/mysql/data/my.cnf --basedir=/usr
1449 ? S 0:00          \_ /usr/local/mysql/bin/mysqld --defaults-extra-file=/usr/local/mysql/data/my.cnf --basedir=/usr
1471 ? S 0:00          \_ /usr/local/mysql/bin/mysqld --defaults-extra-file=/usr/local/mysql/data/my.cnf --basedir=/usr

(If you received errors, look in the file /usr/local/mysql/data/hostname.err for debugging info)

Next setup a password for the MySQL root user

/usr/local/mysql/bin/mysqladmin -u root password 'mysql-root-pwd'

Configure MySQL so it is running all the time from bootup onwards

cp /usr/local/mysql/support-files/mysql.server /etc/rc.d/init.d/mysql
chmod 744 /etc/rc.d/init.d/mysql
chkconfig --add mysql

Then I like to use the ntsysv program to double-check that mysql is set to launch at boot time


OPENSSL

www.openssl.org

This package is optional. It is required if you want your Apache software to have SSL support. We have used it because we want our WebMail interface to have SSL functionality for the login screens. If you don’t want/need SSL support, you could skip this section

Go to their website and download the latest source to /usr/local/src.   In this example I have used the file:

openssl-0.9.7b.tar.gz

Compile source (installs to /usr/local/ssl)

cd /usr/local/src
tar xzf openssl-0.9.7b.tar.gz
chown -R root.root openssl-0.9.7b.tar.gz
cd openssl-0.9.7b
./config no-threads -fPIC
make
make install

Generate a private key (make a KEY file)

cd /usr/local/ssl
# generate an 1024-bit RSA private key
bin/openssl genrsa -out private/webmail.yourdomain.com.key 1024
# make sure the permissions on the private dir are tight
chown -R root.root private
chmod -R 600 private
chmod u+X private

Generate a certificate signing request (make a CSR file)

# fill in the X.509 prompts when they appear on the screen
# make sure you put the web site's name into the common name box eg webmail.yourdomain.com
bin/openssl req -new -key private/webmail.yourdomain.com.key -out certs/webmail.yourdomain.com.csr
Country Name (2 letter code) [AU]:AU
State or Province Name (full name) [Some-State]:Your State
Locality Name (eg, city) []:Your City
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Your Company Pty Ltd
Organizational Unit Name (eg, section) []:Internet Services
Common Name (eg, your name or your server's hostname) []:webmail.yourdomain.com
Email Address []:postmaster@yourdomain.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:yoursecretpasswd
An optional company name []:

Get the certificate signed (make a CRT file)

Get the certificate signed by one of the official signing authorities (eg Thawte) :

Send the webmail.yourdomain.com.csr file to a signing authority for processing…
When they have signed it, copy the signed certificate to /usr/local/ssl/certs/webmail.yourdomain.com.crt

Or alternately, here is how you can sign it yourself so you can do a bit of testing! :

openssl x509 -req -days 30 -in certs/webmail.yourdomain.com.csr -out certs/webmail.yourdomain.com.crt -signkey private/webmail.yourdomain.com.key

A note for the future…. Eventually you will need to renew your certificate :

If you get your certificate signed by eg Thawte, then after the certificate period expires (typically 1 year), you will need to renew the certificate

If all the details for your server are still the same as on your original signing request, then you do not have to submit them a new CSR file. They can just ask them to “re-sign” your existing certificate with an updated expiry date. Before proceeding with your renewal request, make sure you still have a copy of your original private key, as the new certificate will require this file.

Alternatively, if any of the details for your server have changed, then you will need to apply for a new certificate. To do this just follow the original steps above that show how to create a certificate from scratch. (Thawte will still only bill you the cheaper renewal rates..)

Thawte will then send you an updated CRT, and all you do is save this over the top of your original CRT file (/usr/local/ssl/certs/webmail.yourdomain.com.crt), and then restart the apache server


APACHE WEB SERVER (WITH MOD_SSL & PHP4 AS DSO MODULES)

http://httpd.apache.org

Text with green background is only required if you are building in support for mod_ssl

Uninstall apache if it is installed already

rpm -e --nodeps apache

Go to their website and download the latest source to /usr/local/src.   In this example I have used the file:

apache_1.3.27.tar.gz

(Note, Apache v2 has recently been released as “stable”, however I am yet to do any testing under this new version. I would recommend that you stay with v1.3 until the v2 series is more mature)

Extract the apache source

cd /usr/local/src
tar xzf apache_1.3.27.tar.gz
chown -R root.root apache_1.3.27

Create an account  and group for the web server to run under

groupadd www
useradd -g www www

Merge in the mod_ssl source

www.modssl.org

mod_ssl provides SSL cryptography functionality for the Apache webserver

Go to their website and download the version of mod_ssl that matches your version of apache. Put the file into /usr/local/src. In this example I have used the file :

mod_ssl-2.8.14-1.3.27.tar.gz

Extract the source :

cd /usr/local/src
tar xzf mod_ssl-2.8.14-1.3.27.tar.gz
chown -R root.root mod_ssl-2.8.14-1.3.27.tar.gz
cd mod_ssl-2.8.14-1.3.27

And now use the configure script to patch the apache source tree

./configure \
  --with-apache=../apache_1.3.27 \
  --with-crt=/usr/local/ssl/certs/webmail.yourdomain.com.crt \
  --with-key=/usr/local/ssl/private/webmail.yourdomain.com.key

Compile the apache source

cd /usr/local/src
cd apache_1.3.27
SSL_BASE=../openssl-0.9.7b \
./configure \
  --prefix=/usr/local/apache \
  --enable-module=so \
  --enable-module=rewrite \
  --enable-shared=rewrite \
  --enable-module=ssl \
  --enable-shared=ssl \
  --disable-rule=SSL_COMPAT \
  --server-uid=www \
  --server-gid=www
make
make install

Now add  PHP scripting support

www.php.net

Go to their website and download the latest source to /usr/local/src. In this example I have used :

php-4.3.11.tar.gz

Extract the source

cd /usr/local/src
tar xzf php-4.3.11.tar.gz
chown -R root.root php-4.3.11
cd php-4.3.11

And now use the configure script to patch the Apache source tree

./configure \
  --with-mysql=/usr/local/mysql \
  --with-apxs=/usr/local/apache/bin/apxs
make
make install

Put the sample php.ini file into the required location

cp php.ini-dist /usr/local/lib/php.ini

Modify the /usr/local/lib/php.ini file and make sure it contains the following commands

max_execution_time=60
memory_limit=10M
post_max_size=8M
upload_max_filesize=8M
file_uploads=On
log_errors=On
error_log=/usr/local/apache/logs/php_error_log

Tighten the security on PHP dir

# Since we have installed PHP as a module, it will run in our chosen "www" context.
# We will now tighten up the permissions on the php directory to allow only root and www users access
chown -R root.www /usr/local/lib/php
chmod -R g-w,o-rwx /usr/local/lib/php

Edit the /usr/local/apache/conf/httpd.conf file

User www
Group www
ServerAdmin postmaster@yourdomain.com
ServerName  webmail.yourdomain.com
# Following line should be present already as it would be inserted by the PHP make
# Make sure you move it outside of the IfDefineSSL section if the make (incorrectly) put it there
LoadModule php4_module libexec/libphp4.so
# uncomment (or add) the following line
AddType application/x-httpd-php .php
# Add the index.php into this line so apache will use this file as a default in addition to index.html
DirectoryIndex index.php index.html
# Go towards the end of the httpd.conf and look for the "SSL Virtual Host Context"
ServerName webmail.yourdomain.com
ServerAdmin postmaster@yourdomain.com

Tidy up the default Apache contents dir

rm -Rf /usr/local/apache/htdocs/*
rm -f /usr/local/apache/index.html.*

Tidy up the default Apache cgi-bin dir

rm -Rf /usr/local/apache/cgi-bin/*

Setup permissions on the Apache dirs

cd /usr/local

# make root.root own the entire Apache tree
chown -R root.root apache

# setup permissions on the apachedir.
# Because it is owned by root.root, we need to make sure the world permissions bits
# allow rx so that the www group in particular can get access to the apacheroot
chmod 755 apache

# now set the rest of the apacheroot to only allow root to rw. Everything else blocked
# we will selectively go and open permissions as needed
chmod -R 600 apache/*

# give owner (root) search/access permissions on all directories in the apacheroot
chmod -R u+X apache

cd apache

# bin dir contains binaries, so grant execute permissions to owner (root)
chmod -R u+x bin

# cgi-bin contains binaries. Allow either owner (root), or group (web server (www)) to execute these
chgrp -R www cgi-bin
chmod -R u+x,g+x cgi-bin

# the web server needs read access the icons dir
chgrp -R www icons
chmod -R g+rX icons

# Web server log files can be written by the service processes
# but the log files cannot be read or served as web content.
# Web server log files can be read only by administration processes
chgrp -R www logs
chmod g+wX logs

# public web files needs to be able to be read, but not written to by the web service processes
# Also the directories where public web content is stored must not be writable by web services processes
# Also public web content files can be written only by processes authorised for web server admin (only root in our case)
chgrp -R www htdocs
chmod -R g+rX htdocs

OPTIONAL : ADD MOD_GZIP SUPPORT

http://sourceforge.net/projects/mod-gzip/

mod_gzip is a module for Apache that allows you to compress outgoing content from an Apache web server on-the-fly. It uses the same compression as gzip and no plugins or extra software is needed by your browser to take advantage of this product. Reduction in size of up to 90% or more is possible.

Go to their website and download the latest source to /usr/local/src. In this example I have used :

mod_gzip-1.3.26.1a.tar

Unpack the sources

cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/mod-gzip/mod_gzip-1.3.26.1a.tgz
tar xzf mod_gzip-1.3.26.1a.tgz
chown -R root.root mod_gzip-1.3.26.1a
cd mod_gzip-1.3.26.1a

Compile

APXS=/usr/local/apache/bin/apxs make
APXS=/usr/local/apache/bin/apxs make install

Setup the mod_gzip config in the Apache’s httpd.conf file

vi /usr/local/apache/conf/httpd.conf
# Add the following commands to the httpd.conf file.
# ( Insert them before all the SSL config options )

LoadModule gzip_module libexec/mod_gzip.so
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_temp_dir /tmp
mod_gzip_keep_workfiles No
mod_gzip_minimum_file_size 500
mod_gzip_maximum_file_size 5000000
mod_gzip_maximum_inmem_size 60000
mod_gzip_handle_methods GET
mod_gzip_item_include file "\.htm$"
mod_gzip_item_include file "\.html$"
mod_gzip_item_include file "\.txt$"
mod_gzip_item_include file "\.php$"

mod_gzip_item_include mime "text/*"
mod_gzip_item_include mime "httpd/unix-directory"
mod_gzip_item_include mime "application/x-httpd-php"

mod_gzip_item_exclude file "\.css$"
mod_gzip_item_exclude file "\.js$"
mod_gzip_item_exclude file "\.wml$"

mod_gzip_dechunk Yes

LogFormat "%h %l %u %t \"%r\" %>s %b mod_gzip: %{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info1
# CustomLog /usr/local/apache/logs/mod_gzip common_with_mod_gzip_info1
LogFormat "%h %l %u %t \"%V %r\" %>s %b mod_gzip: %{mod_gzip_result}n In:%{mod_gzip_input_size}n Out:%{mod_gzip_output_size}n:%{mod_gzip_compression_ratio}npct." common_with_mod_gzip_info2
CustomLog /usr/local/apache/logs/mod_gzip common_with_mod_gzip_info2
mod_gzip_add_header_count Yes
</IfModule>
# and then put this command inside the <VirtualHost _default_:443> section
# since it isnt possible to successfully gzip SSL pages
mod_gzip_on No

CRANK IT UP!

Test your httpd.conf for valid syntax

/usr/local/apache/bin/apachectl configtest

Try starting the Apache server

# if you are using SSL :

/usr/local/apache/bin/apachectl startssl

# if you aren't using SSL

/usr/local/apache/bin/apachectl start

At this point the apache daemon should be running. A good way to verify this is to use this command :

ps axf

If all is well, you should be able to see something like this :

1210 ? S 0:00 /usr/local/apache/bin/httpd -DSSL
1274 ? S 0:03  \_ /usr/local/apache/bin/httpd -DSSL
1275 ? S 0:00  \_ /usr/local/apache/bin/httpd -DSSL
1276 ? S 0:02  \_ /usr/local/apache/bin/httpd -DSSL
1277 ? S 0:03  \_ /usr/local/apache/bin/httpd -DSSL
1278 ? S 0:01  \_ /usr/local/apache/bin/httpd -DSSL

If that all looks good, then now we need to configure a startup script for apache, so it launches every time at bootup

vi /etc/rc.d/init.d/httpd

#!/bin/sh
#
# Startup script for the Apache Web Server
#
# chkconfig: 345 85 15
# description: Apache is a World Wide Web server. It is used to serve \
# HTML files and CGI.
# processname: httpd
# pidfile: /var/run/httpd.pid

# Source function library.
. /etc/rc.d/init.d/functions

# See how we were called.
case "$1" in
  start)
	echo -n "Starting httpd: "
	daemon /usr/local/apache/bin/httpd -DSSL
	echo
	touch /var/lock/subsys/httpd
  ;;
  stop)
	echo -n "Shutting down http: "
	killproc httpd
	echo
	rm -f /var/lock/subsys/httpd
	rm -f /var/run/httpd.pid
  ;;
  status)
	status httpd
  ;;
  restart)
	$0 stop
	$0 start
  ;;
  reload)
	echo -n "Reloading httpd: "
	killproc httpd -HUP
	echo
  ;;
  *)
	echo "Usage: $0 {start|stop|restart|reload|status}"
	exit 1
esac

exit 0

Setup permissions etc for the startup script

chown root.root /etc/rc.d/init.d/httpd
chmod 744 /etc/rc.d/init.d/httpd
chkconfig --add httpd

Then I like to use the ntsysv program to double-check that httpd is set to launch at boot time


QMAIL

I recommend that you follow the instruction guide at www.lifewithqmail.org

 

However, if you really want to see how we normally do it, here are the steps :

INSTALL UCSPI-TCP

cd /usr/local/src
wget http://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz
wget http://www.qmail.org/ucspi-rss.diff
tar xzf ucspi-tcp-0.88.tar.gz
chown -R root.root ucspi-tcp-0.88
cd ucspi-tcp-0.88
# Patch rblsmtpd so that it can be used with all the newer RBL zones.
# This patch also lets you specify a custom error message to be returned to the sender.
patch -p0 rblsmtpd.c < ../ucspi-rss.diff
# Modify rblsmtpd.c to increase the maximum size of the error text that is allowed
# to be returned to the sender from 200 to 500 chars.
# This allows you to create some nice and descriptive text to send to people who
# are being blocked by your RBL filters
vi rblsmtpd.c

go to line 166 and change it from

if (text.len > 200) text.len = 200;

to

if (text.len > 500) text.len = 500;
make
make setup check

INSTALL DAEMONTOOLS

cd /usr/local/src
wget http://cr.yp.to/daemontools/daemontools-0.76.tar.gz
mkdir -p /package
chmod 1755 /package
cd /package
tar xzfp /usr/local/src/daemontools-0.76.tar.gz
cd admin/daemontools-0.76
package/install

INSTALL QMAIL

Download the required files

cd /usr/local/src
wget http://cr.yp.to/software/qmail-1.03.tar.gz
wget http://www.ckdhr.com/ckd/qmail-103.patch
wget http://www.qmail.org/qmailqueue-patch
wget http://www.shupp.org/patches/qmail-maildir++.patch
wget http://www.bowe.id.au/michael/Sources/Linux/WebMail/qmail-date-localtime.patch.txt
wget http://www.bowe.id.au/michael/sources/linux/WebMail/qmail-limit-bounce-size.patch.txt
wget http://www.bowe.id.au/michael/Sources/Linux/WebMail/qregex.patch-20020129.txt
wget http://www.bowe.id.au/michael/Sources/Linux/WebMail/qmail-smtpd-esmtp-size_qregex-compat.diff.txt
wget http://www.bowe.id.au/michael/sources/linux/WebMail/qmailctl.txt

Create the users and groups required for qmail

groupadd nofiles
useradd -g nofiles -d /var/qmail qmaild
useradd -g nofiles -d /var/qmail qmaill
useradd -g nofiles -d /var/qmail qmailp
useradd -g nofiles -d /var/qmail/alias alias
groupadd qmail
useradd -g qmail -d /var/qmail qmailq
useradd -g qmail -d /var/qmail qmailr
useradd -g qmail -d /var/qmail qmails

Unzip the sources, apply the required patches, compile

tar xzf qmail-1.03.tar.gz
cd qmail-1.03
# Apply patch that allows qmail to work with oversize DNS packets
patch -p1 < ../qmail-103.patch
# Apply the "qmailqueue" patch
# This patch gives you the required support for other popular addons like Qmail-Scanner
patch -p1 < ../qmailqueue-patch
# Apply patch to make qmail-local and qmail-pop3d compatible with the maildir++ quota
# system that is used by vpopmail and courier-imap
patch < ../qmail-maildir++.patch
# Apply patch for local timestamps.
# This will make the emails headers be written in localtime rather than GMT
patch -p1 < ../qmail-date-localtime.patch.txt
# Apply patch to limit the size of bounce messages generated by our server.
# The patch will limit the size of the bounce to be 50K,
# or you can override this by setting a different value in /var/qmail/control/bouncemaxbytes
patch < ../qmail-limit-bounce-size.patch.txt
# Now add the qregex patch, which adds regexp support to qmail's badmailfrom,
# and also implements badmailto checking (again with regexp support)
patch < ../qregex.patch-20020129.txt
# Apply patch to add ESMTP SIZE support to qmail-smtpd
# This helps your server be able to reject excessively large messages "up front",
# rather than waiting for the whole message to arrive and then bouncing it because
# exceeded the /var/qmail/control/databytes setting.
# Nother that particular patch has been modified so it will apply cleanly in
# conjunction with the other patches I have supplied above. The original version
# of this patch would fail because it conflicted with the qregex patch.
patch < ../qmail-smtpd-esmtp-size_qregex-compat.diff.txt

Edit qmail-smtpd.c and change the code on the straynewline function (around line 54) from 451 to 553
Without this you will get nasty loops forming when a remote servers sends you an message with invalid formatting. By default qmail will says something like  “I am not going to accept that message at the moment, you can try again later”. However in my experience the sending server will try sending the same message again a few seconds later, and this will go around and around in a loop for days on end – consuming valuable bandwidth and resources. By changing the error code to 553, it is making the error be permanent ie “I am not going to accept that message, don’t try sending it again”

make setup check
./config
cd ..

Remove the sendmail package, and link in qmail’s replacement utility

# If you are running redhat 8, you may first need to remove the postfix
# package, so that mail to someuser@hostname.yourdomain.com will work correctly :
rpm -e --nodeps postfix
# OK, now go ahead and remove the sendmail package
rpm -e --nodeps sendmail
# Link in qmail's replacement "sendmail-like" tools
ln -s /var/qmail/bin/sendmail /usr/lib
ln -s /var/qmail/bin/sendmail /usr/sbin

The qmailctl script contains all the various commands that will allow us to control our qmail daemons. Put it in with the other qmail binaries. Also link it into /usr/bin so it will be in our “path” for easy access

cp /usr/local/src/qmailctl.txt /var/qmail/bin/qmailctl
chmod 755 /var/qmail/bin/qmailctl
ln -s /var/qmail/bin/qmailctl /usr/bin

Setup the /etc/tcp.smtp file
This file controls who is allowed to send and/or relay mail on this server
An example configuration follows :

#------------------------------------------------------
# DESCRIPTION OF THE RULES TO REMIND ME OF HOW THIS FILE WORKS
#
# If you set 'allow', this means that our mail server will allow
# the specified IP range to make a TCP connection to our server
#
# If you set 'deny', this means that our mail server will not allow
# the specified IP range to make a TCP connection to our server
#
# If you set RELAYCLIENT="", this means that the listed IP range is
# allowed to relay mail through our server
#
# If you dont set RELAYCLIENT="", this means that the listed IP range
# will not be able to relay mail through our server
#
# If you set RBLSMTPD="", this means that the listed IP ranges will
# not be checked against any of the RBL databases
#
# If you set RBLSMTPD="some text here", this means that an RBL lookup
# wont be performed, but the mail will be rejected with the specified
# text as a 4xx temp error message
#
# If you set RBLSMTPD="-some text here", this means that an RBL lookup
# wont be performed, but the mail will be rejected with the specified
# text as a 5xx perm error message
#
# If you do not set RBLSMTPD="" or ="some text", then an RBL lookup
# will be performed. If the lookup is successful, then RBLSMTPD will
# return your custom error message (as specified in the -r parameter
# in smtpd supervise script)
#
#-----------------------------------------------------
# HERE ARE THE RULES! :
#-----------------------------------------------------
# BYPASS OPEN RELAY CHECKING FOR THESE IPS :
#
# These IPs are ones that we have setup so that they arent RBL checked.
# We have done this because these particular servers are RBL listed,
# and for whatever reason they can't/won't fix their open relay problem,
# and we still want to be able to receive mail from them.
#
# reminder text goes here for this entry so we know the story...
111.111.111.111:allow,RBLSMTPD=""
# reminder text goes here for this entry so we know the story...
222.222.222.222:allow,RBLSMTPD=""
#
#-----------------------------------------------------------------
# DONT ALLOW THESE IPS TO SEND MAIL TO US :
#
# mailXX.offermail.net connecting regularly and sending invalid
# format messages causing exit with status 256 (bare linefeed normally)
# entry added 15/12/2001
# after looking at the mail coming from these servers it was found to be spam
216.242.75.100-116:allow,RBLSMTPD="-Connections from this IP have been banned."
#
# heaps of spam from replyto of *@freeamateurhotties.com dec2001
64.228.127.:allow,RBLSMTPD="-Connections refused due to spam from freeamateurhotties.com"
154.20.94.:allow,RBLSMTPD="-Connections refused due to spam from freeamateurhotties.com"
209.151.132.:allow,RBLSMTPD="-Connections refused due to spam from freeamateurhotties.com"
216.18.85.:allow,RBLSMTPD="-Connections refused due to spam from freeamateurhotties.com"
#
#-----------------------------------------------------------------
# ALLOW THESE IPS TO RELAY MAIL THROUGH OUR SERVER
#
# Local class-c's from our LAN are allowed to relay,
# and we wont bother doing any RBL checking.
123.123.123.:allow,RELAYCLIENT="",RBLSMTPD=""
123.111.111.:allow,RELAYCLIENT="",RBLSMTPD=""
#
# Connections from localhost are allowed to relay
# (because the WebMail server runs on localhost),
# and obviously there is no point trying to perform an RBL check.
127.0.0.1:allow,RELAYCLIENT="",RBLSMTPD=""
#
#-----------------------------------------------------------------
# ALLOW EVERYONE ELSE TO SEND US MAIL
#
# Everyone else can make connections to our server,
# but not allowed to relay
# RBL lookups are performed
:allow

Setup the /etc/tcp.pop3  file
This file controls who is allowed to access the POP3 services on this server
An example configuration follows :

# Allow any client to connect to us via POP3
# If people are abusing POP3 such as denial-of-service on POP3,
# you can add their ips here to block them out
:allow

Now we have created our tcp.smtp and tcp.pop3 files, we need to compile them into the cdb database format that the tcpserver program can read

qmailctl cdb

Adjust various aspects of the qmail configuration to suite our tastes :

# use postmaster@hostname.yourdomain.com as sender in bounce messages
# rather than the default MAILER-DAEMON@hostname.yourdomain.com
echo 'postmaster' > /var/qmail/control/bouncefrom
# Define how to handle "double bounces".
# The server admin has two choices here, either to receive double bounces
# or to discard them. If your server doesn't handle a lot of mail then it
# wouldn't hurt to receive all double bounces for the admin's inspection.
# But if your server handles a lot of mail, then it is more likely that you
# are going to want to discard double-bounces, because you will end up with
# potentially thousands of these every day.
#
# If you want to keep double-bounces, use these commands to nominate what
# email address to send them through to (eg doublebounce@yourdomain.com) :
echo 'doublebounce' > /var/qmail/control/doublebounceto
echo 'yourdomain.com' > /var/qmail/control/doublebouncehost
# (dont forget that you will need to make sure you have created a mailbox
# to receive these mails. You could use qmailadmin to create a dedicated
# mailbox, or perhaps setup an alias on an existing mailbox)
#
# Or if you would prefer to silently discard any doublebounces,
# then use these commands instead
echo 'doublebounce' > /var/qmail/control/doublebounceto
echo 'hostname.yourdomain.com' > /var/qmail/control/doublebouncehost
echo '#' > ~alias/.qmail-doublebounce
chmod 644 ~alias/.qmail-doublebounce
# set maximum message size to be 8Mb
echo '8000000' > /var/qmail/control/databytes
# queue mail for up to 4 days
echo '345600' > /var/qmail/control/queuelifetime
# Populate badmailto so that mail with invalid address formatting gets rejected
echo '# reject containing invalid characters, brackets or multiple @' > /var/qmail/control/badmailto
echo '[!%#:\*\^]' >> /var/qmail/control/badmailto
echo '[\(\)]'         >> /var/qmail/control/badmailto
echo '[\{\}]'         >> /var/qmail/control/badmailto
echo '@.*@'           >> /var/qmail/control/badmailto
# setup the default domain for use where an address does not have a domain specified
echo 'yourdomain.com' > /var/qmail/control/defaultdomain
# Note, this following command is optional!
#
# If you want qmail to send all outbound mail via a particular mail server
# rather than to send it direct to the recipient's mail server, then this
# can be achieved with the smtproutes command.
#
# SEND ALL OUTBOUND MAIL VIA SMARTHOST
echo ':yoursmarthost.yourdomain.com' > /var/qmail/control/smtproutes
# redirect any mail sent to root@hostname.yourdomain.com to 'postmaster@yourdomain.com
# redirect any mail sent to postmaster@hostname.yourdomain.com to 'postmaster@yourdomain.com
# redirect any mail sent to mailer-daemon@hostname.yourdomain.com to 'postmaster@yourdomain.com
echo 'postmaster@yourdomain.com' > ~alias/.qmail-root
echo 'postmaster@yourdomain.com' > ~alias/.qmail-postmaster
echo 'postmaster@yourdomain.com' > ~alias/.qmail-mailer-daemon
chmod 644 ~alias/.qmail-*

Create / configure the various qmail run scripts :

cd /etc/rc.d/init.d
ln -s /var/qmail/bin/qmailctl /etc/rc.d/init.d/qmail
ln -s ../init.d/qmail /etc/rc.d/rc0.d/K30qmail
ln -s ../init.d/qmail /etc/rc.d/rc1.d/K30qmail
ln -s ../init.d/qmail /etc/rc.d/rc2.d/S80qmail
ln -s ../init.d/qmail /etc/rc.d/rc3.d/S80qmail
ln -s ../init.d/qmail /etc/rc.d/rc4.d/S80qmail
ln -s ../init.d/qmail /etc/rc.d/rc5.d/S80qmail
ln -s ../init.d/qmail /etc/rc.d/rc6.d/K30qmail
mkdir -p /var/qmail/supervise/qmail-send/log
mkdir -p /var/qmail/supervise/qmail-smtpd/log
mkdir -p /var/qmail/supervise/qmail-pop3d/log
chmod +t /var/qmail/supervise/qmail-send
chmod +t /var/qmail/supervise/qmail-smtpd
chmod +t /var/qmail/supervise/qmail-pop3d
vi /var/qmail/supervise/qmail-send/run
#!/bin/sh
exec env - PATH="/var/qmail/bin:$PATH" qmail-start ./Maildir/
vi /var/qmail/supervise/qmail-send/log/run
#!/bin/sh
# Keep 30 logs of max 10Mb each
#
# They will get rotated when they reach 10Mb in size,
# or at midnight when our crontab script fires (whichever event comes 1st)
exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t s10000000 n30 /var/log/qmail/send
vi /var/qmail/supervise/qmail-smtpd/run
#!/bin/sh
QMAILDUID=`id -u qmaild`
NOFILESGID=`id -g qmaild`

exec /usr/local/bin/softlimit -m 4000000 \
/usr/local/bin/tcpserver \
  -H -l hostname.yourdomain.com \
  -v -x /etc/tcp.smtp.cdb \
  -c 20 -R -u "$QMAILDUID" -g "$NOFILESGID" 0 smtp \
/usr/local/bin/rblsmtpd -b -C \
  -r 'list.dsbl.org:Your message was rejected because the message was sent from a server listed in DSBL - More information regarding this problem is available at http://dsbl.org/listing?%IP% - Please forward this error to your email server support staff for resolution.' \
  -r 'sbl-xbl.spamhaus.org:Your message was rejected because the message was sent from a server listed in the Spamhaus RBL - More information regarding this problems is available at http://www.spamhaus.org/query/bl?ip=%IP% - Please forward this error to your email server support staff for resolution.' \
  -t 5 \
/var/qmail/bin/qmail-smtpd 2>&1
# The line in orange should be used if you are running qmail on a computer
# that is on a LAN that is using fake ips/masquerading.
# It tells tcpserver not to bother trying to resolve ip addresses
# to names when writing the SMTP log files. Usually with fake ips,
# you cant resolve them to names, so it will make the SMTP services run
# really slowly if it is always trying to resolve these addresses.
# Alternatively, if you are eg an ISP and all your SMTP clients are
# connecting from real IPs with resolvable names, then you can omit
# the orange line and then then benefit from more readable logfiles.
vi /var/qmail/supervise/qmail-smtpd/log/run
#!/bin/sh
# Keep 30 logs of max 10Mb each
#
# They will get rotated when they reach 10Mb in size,
# or at midnight when our crontab script fires (whichever event comes 1st)
exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t s10000000 n30 /var/log/qmail/smtpd
vi /var/qmail/supervise/qmail-pop3d/run
#!/bin/sh
exec /usr/local/bin/softlimit -m 6000000 \
/usr/local/bin/tcpserver \
  -H -l hostname.yourdomain.com \
  -v -x /etc/tcp.pop3.cdb -c 30 -R 0 pop3 \
/var/qmail/bin/qmail-popup hostname.yourdomain.com \
/home/vpopmail/bin/vchkpw /var/qmail/bin/qmail-pop3d Maildir 2>&1
# The line in orange should be used if you are running qmail on a computer
# that is on a LAN that is using fake ips/masquerading.
# It tells tcpserver not to bother trying to resolve ip addresses
# to names when writing the POP3 log files. Usually with fake ips,
# you cant resolve them to names, so it will make the POP3 services run
# really slowly if it is always trying to resolve these addresses.
# Alternatively, if you are eg an ISP and all your POP3 clients are
# connecting from real IPs with resolvable names, then you can omit
# the orange line and then then benefit from more readable logfiles.
vi /var/qmail/supervise/qmail-pop3d/log/run
#!/bin/sh
# Keep 30 logs of max 10Mb each
# They will get rotated when they reach 10Mb in size,
# or at midnight when our crontab script fires (whichever event comes 1st)
exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t s10000000 n30 /var/log/qmail/pop3d
chmod 755 /var/qmail/supervise/qmail-send/run
chmod 755 /var/qmail/supervise/qmail-send/log/run
chmod 755 /var/qmail/supervise/qmail-smtpd/run
chmod 755 /var/qmail/supervise/qmail-smtpd/log/run
chmod 755 /var/qmail/supervise/qmail-pop3d/run
chmod 755 /var/qmail/supervise/qmail-pop3d/log/run
mkdir /var/log/qmail
mkdir /var/log/qmail/smtpd
mkdir /var/log/qmail/send
mkdir /var/log/qmail/pop3d
chown -R qmaill /var/log/qmail
crontab -e
# the following 3 lines rotate the qmail log files daily
0 0 * * * /usr/local/bin/svc -a /service/qmail-smtpd/log
0 0 * * * /usr/local/bin/svc -a /service/qmail-send/log
0 0 * * * /usr/local/bin/svc -a /service/qmail-pop3d/log
ln -s /var/qmail/supervise/qmail-send /service
ln -s /var/qmail/supervise/qmail-smtpd /service
ln -s /var/qmail/supervise/qmail-pop3d /service

At this point the qmail daemons should be running. A good way to verify this is to use this command :

ps axf

If all is well, you should be able to see something like this :

1218 ? S 0:00 /bin/sh /command/svscanboot
1222 ? S 0:00  \_ svscan /service
1224 ? S 0:00  |   \_ supervise qmail-send
1230 ? S 0:00  |   |   \_ qmail-send
1236 ? S 0:00  |   |   \_ qmail-lspawn ./Maildir/
1237 ? S 0:00  |   |   \_ qmail-rspawn
1238 ? S 0:00  |   |   \_ qmail-clean
1225 ? S 0:00  |   \_ supervise log
1233 ? S 0:00  |   |   \_ /usr/local/bin/multilog t s10000000 n30 /var/log/qmail/send
1226 ? S 0:00  |   \_ supervise qmail-smtpd
1231 ? S 0:00  |   |   \_ /usr/local/bin/tcpserver -v -x /etc/tcp.smtp.cdb -c 20 -R -u 504 -g 503 0 smtp /var/qmail/bin
1227 ? S 0:00  |   \_ supervise log
1234 ? S 0:00  |   |   \_ /usr/local/bin/multilog t s10000000 n30 /var/log/qmail/smtpd
1228 ? S 0:00  |   \_ supervise qmail-pop3d
1232 ? S 0:00  |   |   \_ /usr/local/bin/tcpserver -v -x /etc/tcp.pop3.cdb -c 30 -H -R 0 110 /var/qmail/bin/qmail-popup
1229 ? S 0:00  |   \_ supervise log
1235 ? S 0:00  |       \_ /usr/local/bin/multilog t s10000000 n30 /var/log/qmail/pop3d
1223 ? S 0:00  \_ readproctitle service errors: .......................................................................

Note the 3 qmail daemons : qmail-send, qmail-smtpd, qmail-pop3d, as well as their associated logging processes. If there is anything wrong with your install, an error message will generally be visible on the “readproctitle” line

You can control the qmail daemons by using the qmailctl program. You can just type that command without any parameters and it will display the available options eg start, stop, status, doqueue


VPOPMAIL

https://sourceforge.net/projects/vpopmail

Make the user accounts

# If you are using RH8.0, you will probably need to run this following command,
# because RH8.0 comes preconfigured with UID/GID 89 allocated to postfix
#
# userdel postfix
groupadd -g 89 vchkpw
useradd -g vchkpw -u 89 -d /home/vpopmail vpopmail
# We recommend you use the user and group id's of 89. The FreeBSD folks
# have reserved 89 for the group and 89 for the user for vpopmail. Feel
# free to have the OS assign the group/user id (for example, Solaris won't
# allow gid 89).

Download and unpack the source

cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/vpopmail/vpopmail-5.4.10.tar.gz
tar xzf vpopmail-5.4.10.tar.gz
chown -R root.root vpopmail-5.4.10
cd vpopmail-5.4.10

Setup the MySQL support in the vpopmail sources

# Create the configuration file that vpopmail will use
# to setup the connection to the mysql database
#
# This example will tell vpopmail :
#   * Log into the server running on localhost
#   * Use the default mysql port
#       (In fact if the server is localhost, and you don't specify a port number, then
#        I believe the that communications are done via unix sockets rather than TCP/IP)
#   * Login with username vpopmailuser
#   * Login with password vpoppasswd
#   * Use the database called vpopmail
#
mkdir ~vpopmail/etc
chown vpopmail.vchkpw ~vpopmail/etc
echo "localhost|0|vpopmailuser|vpoppasswd|vpopmail" > ~vpopmail/etc/vpopmail.mysql
chown vpopmail.vchkpw ~vpopmail/etc/vpopmail.mysql
chmod 640 ~vpopmail/etc/vpopmail.mysql
# log into MySQL as the MySQL root user
# and then create the database for vpopmail to use
# and then setup the appropriate permissions on this database
/usr/local/mysql/bin/mysql --password="mysql-root-pwd"
CREATE DATABASE vpopmail;
GRANT select,insert,update,delete,create,drop ON vpopmail.*
TO vpopmailuser@localhost IDENTIFIED BY 'vpoppasswd';
quit

Now, build the program

./configure \
  --disable-roaming-users \
  --enable-logging=p \
  --disable-passwd \
  --enable-clear-passwd \
  --disable-domain-quotas \
  --enable-auth-module=mysql \
  --enable-auth-logging \
  --enable-sql-logging \
\
  --enable-valias \
  --disable-mysql-limits
<-- We aren't building roaming user support in this example
<-- Log POP3 authentication errors including the failed password (to syslog)
<-- Don't include /etc/passwd support. Our box doesn't have any "real" users, only vpopmail users
<-- Enable storing passwords in clear-text. Makes your support staff's life much easier!
<-- Domain quotas allow you to limit the amount of storage a particular domain can use. This code is buggy though and is not recommended for use.
<-- Store all the user and domain information in MySQL rather than using disk-based "cdb" files
<-- Maintain a lastauth table in MySQL (shows when / how a user last accessed their email)
<-- Maintain the vlog table in MySQL (shows failed authentication requests).
    The verbosity of the logging will mirror what was chosen in the --enable-logging parameter.
<-- Store aliases and autoresponder settings in MySQL rather than .qmail-xxxx files on the disk.
<-- Use disk-based ".qmailadmin-limits" files rather than storing this data in MySQL.
make
make install-strip

Notes :

The   “–enable-mysql-limits” configuration option is fairly new. I plan to update my guide to use this function at some point in the near future once I have done some testing etc of this functionality

I used to recommend the –disable-many-domains switch – which tells vpopmail to create one MySQL table per email domain. When I first started building vpopmail servers, I found this to be the most logical way, having each domain in its own table. However there has been some discussion about this config option on the vpopmail mailing lists, and it sound like this option may be removed at some point in the future.  If you have a lot of domains on your server, having each domain in its own table can hurt performance. I now agree that –enable-many-domains (which is the default) is probably the better choice

Review the contents of the file is used to set the default limits for any domains / mailboxes in the vpopmail system. Make sure it contains reasonable defaults for your system.

vi ~vpopmail/etc/vlimits.default
# in particular set the default mailbox size to be something reasonable eg 20Mb
default_quota 20971520

Optionally, nominate a “default domain”. Users in this domain can login to POP3 etc using just their username. Users from all other domains need to use their full email address as their login name.

echo "yourdomain.com" > /home/vpopmail/etc/defaultdomain

Setup the quota warning message that is sent to users when they are at 90% quota

vi quotawarn.msg
From: SomeCompany Postmaster <postmaster@yourdomain.com>
Reply-To: postmaster@yourdomain.com
To: SomeCompany User:;
Subject: Mail quota warning
Mime-Version: 1.0
Content-Type: text/plain; charset=iso-8859-1
Content-Transfer-Encoding: 7bit

Your mailbox on the server is now more than 90% full.

So that you can continue to receive mail,
you need to remove some messages from your mailbox.

If you require assistance with this,
please contact our support department :

  email : support@yourdomain.com
  Tel   : xx xxxx xxxx
cp quotawarn.msg /home/vpopmail/domains/.quotawarn.msg

If you want, you can alter the standard message that gets sent to the sender in an overquota situation

echo "Message rejected. Not enough storage space in user's mailbox to accept message." > /home/vpopmail/domains/.over-quota.msg

OK, vpopmail is now installed!

Some example vpopmail commands :

To add a domain :

/home/vpopmail/bin/vadddomain yourdomain.com yourpassword
# this creates the domain and makes a mailbox postmaster@yourdomain.com

To add a mailbox:

/home/vpopmail/bin/vadduser someone@yourdomain.com apassword

(Or you can do it via qmailadmin)

To remove a mailbox

/home/vpopmail/bin/vdeluser someone@yourdomain.com

(Or you can do it via qmailadmin)

To remove a domain :

/home/vpopmail/bin/vdeldomain yourdomain.com

To change a user’s password

/home/vpopmail/bin/vpasswd someone@yourdomain.com newpassword

(Or you can do it via qmailadmin)

To lookup info about a user

/home/vpopmail/bin/vuserinfo someone@yourdomain.com

This gives you info such as name, crypted password, cleartext password, dir, quota, usage%, last auth.
It has a number of flags to let you see the individual fields, or you can see them all if you dont use any flags.

It also creates the maildirsize file in the users dir

Logging in via POP3

When your users are setting up their POP3 email clients (eg Outlook Express), they should use settings like this :

My incoming mail server is a POP3 server
Incoming mail server (POP3): pop3.yourdomain.com
Outgoing mail server (SMTP): smtp.yourdomain.com
POP3 account name : theirusername@yourdomain.com
Password: theirpassword

When you configured vpopmail, you had the opportunity to nominate a “default” domain. When users from the default domain authenticate, it is optional for them to add the @yourdomain.com onto the end of their username. If vpopmail sees that no domain has been specified by the user, then it will automatically perform the auth against the nominated default domain. If you are hosting multiple domains, then everyone who is NOT in the default domain MUST add their domain name onto the end of their username. (A small percentage of email programs eg Netscape Mail v4.7 do not permit the use of the @ symbol in account name. In this case you can use the % symbol instead of the @ symbol)

vpopmail roaming users :

With qmail, the typical way to control mail relaying is to put a list of rules into a file called tcp.smtp. The tcprules program is then used to compile this file into cdb database format with the output being stored in a file called tcp.smtp.cdb. The tcpserver program is configured (using the -x parameter) to read this file and thus know which SMTP clients are permitted to relay mail.

This type of configuration works well if there is a known range of IP addresses that are permitted to relay mail. eg the IP’s on the qmail server’s local LAN. However if the qmail server needs to provide outbound SMTP services for clients who may be connecting from any IP, you are going to run into problems. What is needed is some way to automate the process of granting users the ability to relay mail, without opening up access to all and sundry on the Internet.

vpopmail includes a solution for this problem. The solution is known as “roaming users” and is typically implemented with a technique known as “POP-before-SMTP”. Once a client has successfully authenticated via POP3, vpopmail will add the client’s IP to a list. vpopmail then merges this list with the contents of the tcp.smtp file and runs the tcprules program to compile a new version of the tcp.smtp.cdb file. Thus the client can now relay mail.

In addition to storing the client’s IP address, vpopmail will also store the time of authentication. The postmaster uses a cronjob on the qmail server to periodically (eg once per hour) run the clearopensmtp program. This program scans through the list of roaming clients and removes any entries that exceed the nominated age (eg 3 hours). This ensures that the list of IPs does not grow out of bounds, and that the roaming IPs are closed within a reasonable timeframe after being opened.

configure options for vpopmail that relate to roaming users :

./configure \
  --enable-roaming-users \              <- enable roaming users functionality
  --enable-tcprules-prog=path \         <- defaults to /usr/local/bin/tcprules
  --enable-tcpserver-file=path \        <- defaults to /home/vpopmail/etc/tcp.smtp
  --enable-relay-clear-minutes=minutes  <- defaults to 180

Example /var/qmail/supervise/qmail-smtpd/run file :

#!/bin/sh
QMAILDUID=`id -u qmaild`
NOFILESGID=`id -g qmaild`
exec /usr/local/bin/softlimit -m 2000000 \
  /usr/local/bin/tcpserver -v -x /home/vpopmail/etc/tcp.smtp.cdb -c 40 -R \
  -u "$QMAILDUID" -g "$NOFILESGID" 0 smtp \
  /usr/local/bin/rblsmtpd -b -C -r list.dsbl.org \
  -t 5 \
  /var/qmail/bin/qmail-smtpd 2>&1

Notes :

qmail servers are typically built with the tcp.smtp files being located in the /etc directory. This is not usually suitable for vpopmail roaming users, since the /etc directory will (should) not have write permissions for the vpopmail user. Therefore it is not going to be possible for vpopmail to write out updated versions of the tcp.smtp.cdb file. For use with roaming users, it is recommended that the tcp.smtp files are stored in ~vpopmail/etc

If a user auths, and their IP already exists in the roaming IP list, the timestamp for the entry is updated, but the tcprules program is not run. There is no need to rebuild the tcp.smtp.cdb file as the IP address is already permitted to relay. Rebuilding the file will only waste disk and CPU time.

If the vpopmail server is using the default cdb authentication backend, then the list of roaming IPs will be stored in a file called ~vpopmail/etc/open-smtp. If the vpopmail server is using the MySQL backend, the roaming IPs will be stored in a database table called relay. The SQL backend will give better performance on a busy server. Either way though, you should be cautious about enabling roaming user functionality on a very busy server, as a large amount of disk and CPU will be used with the continual rebuilding of the tcp.smtp.cdb file. If the server is busy enough you could run into nasty file locking issues which will cause vpopmail password authentication to intermittently fail. If you absolutely must have POP-before-SMTP functionality on your busy server, then there are only two possible solutions that I can think of  : 1) you could try putting the tcp.smtp files onto a RAM disk, or 2) use vpopmail’s MySQL auth backend plus use Matt Simerson’s tcpserver patch that allows all of the tcp.smtp files to be stored in MySQL

For POP-before-SMTP to work, the POP3 daemon will need to run under the tcpserver program. This is because vpopmail uses tcpserver’s TCPREMOTEIP environment variable to work out what IP address the POP3 user is connecting from.

Over time POP-before-SMTP is becoming a less favored way of allowing roaming users to relay mail. SMTP-Auth appears to becoming the more preferred option, as it scales much more easily on a busy server. However for a small to medium sized server, POP-before-SMTP is still quite a workable option. If you would like investigate the use of SMTP-Auth take a look at this patch http://www.fehcom.de/qmail/smtpauth.html#PATCHES

IMAP-before-SMTP is possible when using Courier-IMAP v3.x. However it only works when configured “–with-authvchkpw –without-authdaemon”. When running –without-authdaemon, Courier-IMAP’s authvchkpw code is able to make use of vpopmail’s roaming user functions to allow IMAP-before-SMTP functionality. IMAP-before-SMTP is not possible when Courier-IMAP has been complied –with-authdaemon, because in this mode the user’s IP address is not made available to the authvchkpw code (via the TCPREMOTEIP env var). Also note that in Courier-IMAP v4.x and later, –without-authdaemon functionality is no longer available thus preventing IMAP-before-SMTP from working.


AUTORESPONDER

Current development location : http://www.sourceforge.net/projects/qmailadmin

This package is a prerequisite for qmailadmin.

Download and unpack the source

cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/qmailadmin/autorespond-2.0.4.tar.gz
tar xzf autorespond-2.0.4.tar.gz
chown -R root.root autorespond-2.0.4
cd autorespond-2.0.4

Build the program

make
make install

Notes :

Qmailadmin uses the autorespond program for both autoresponse (“mail robot” in qmailadmin-speak), and vacation response duties. However this is pretty badly FUBAR. Reason being is the autorespond.c is written to do duties as an autoresponse program only. “Out of the box” it doesn’t behave correctly when doing vacation response duties. The code inside the program can be easily tweaked to work correctly as a vacation responder, but this will break the autoresponder functionality. Unfortunately the settings are mutually exclusive. In my opinion the correct solution is to create two variations of this program, autorespond.c and vacation.c, install them both, and then tweak qmailadmin to call the right binary for the right job. I have opened a bug report on the qmailadmin sourceforge site to try and get this problem sorted out. If you read back through the qmailadmin and vpopmail archives, you will see the the autoresponder stuff is an ongoing saga :-(

ps. Inter7 have got a modified version of the autorespond program, which I believe has been coded to work correctly as a vacation responder http://inter7.com/devel/autorespond-2.0.5.tar.gz

EZMLM / EZMLM-IDX

This package is a prerequisite for qmailadmin

ezmlm is mailing list software written by the author of qmail
ezmlm-idx is patch that adds extra features to the standard ezmlm program.

EZMLM : http://cr.yp.to/ezmlm.html

EZMLM-IDX PATCH : http://www.ezmlm.org 
(although I often find this site unresponsive, and so I use one of the mirrors instead like http://www.glasswings.com.au/ezmlm/)

Download and unpack the ezmlm sources

cd /usr/local/src
wget http://cr.yp.to/software/ezmlm-0.53.tar.gz
tar xzf ezmlm-0.53.tar.gz
chown -R root.root ezmlm-0.53
wget http://www.bowe.id.au/michael/Sources/Linux/WebMail/ezmlm-idx-0.40.tar.gz
tar xzf ezmlm-idx-0.40.tar.gz
chown -R root.root ezmlm-idx-0.40

Merge the sources together

cp -R ezmlm-idx-0.40/* ezmlm-0.53/
# (you need to press y quite a few times to allow the patch files to overwrite the original files)
cd ezmlm-0.53
patch < idx.patch

Build the program

make
make man
make setup

QMAILADMIN

Original Authors : http://www.inter7.com/qmailadmin
Current Development location  : https://sourceforge.net/projects/qmailadmin/

Description :

The domain postmaster can use this tool to view all the accounts on the domain as well as add/remove accounts, forwards, auto-responders etc.

Domains users can use this tool to modify their own user settings only. ie mailbox password, real name, forwards, vacations.

This tool does not let you create new domains.

Download and unpack the source

cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/qmailadmin/qmailadmin-1.2.9.tar.gz
tar xzf qmailadmin-1.2.9.tar.gz
chown -R root.root qmailadmin-1.2.9
cd qmailadmin-1.2.9

(Optional) Make a small mod that affects the look of the qmailadmin login page

edit the lang/en file, and change record 112 “Username” rather than “User Account”
(We found our users knew what to type as their “Username”, but didn’t know what to type as a “User Account”)

Build the program

./configure \
  --enable-htmldir=/usr/local/apache/htdocs \
  --enable-cgibindir=/usr/local/apache/cgi-bin \
  --enable-maxusersperpage=12 \
  --enable-maxaliasesperpage=12 \
  --disable-modify-quota \
  --disable-ezmlm-mysql \
  --disable-help
# note, I chose to have 12 accounts per page in the config above,
# because this makes these particular screens fit nicely on my 1024*768 monitor
make
make install-strip

Test to see if it works

http://webmail.yourdomain.com/cgi-bin/qmailadmin

If you login a domain postmaster, then you should get the screens where you can view all and add/remove mailboxes, aliases, mailinglists etc on the domain. etc

If you login as a user, you can only access your own mailbox settings (eg password, forwards, vacation messages)

Setting limits :

You can setup limits on any domains where required by putting a .qmailadmin-limits file into the domain’s virtual dir (/home/vpopmail/domains/yourdomain.com). Make sure vpopmail user has read permissions for this file.

Syntax of .qmailadmin-limits file is as follows :

maxpopaccounts X
maxforwards X
maxmailinglists X
maxautoresponders X

Set X to be the maximum desired number for that feature
Set X to be 0 if you want to disable that feature & menu item

There are also some other settings that can be specified in the .qmailadmin-limits file, refer to section 6 of the qmailadmin installation instructions (http://inter7.com/qmailadmin/install.txt) for more info

A bit of a long-winded misc note to myself :

(If you are setting up your vpopmail server for the first time, then this block of text has no relevance to you. You can skip straight past this waffle and go onto the next section…)

As of qmailadmin-1.0.21, you cant create “aliases” any more. What qmailadmin previously created as aliases, are now created as forwards. Aliases dump incoming mail for that aliased address directly into the recipient user’s Maildir. The problem with this is it bypassed any further “.qmail” processing, meaning that you ran into problems if you were trying to setup some of the more fancy things (like per-user SpamAssassin configurations?). Using forwards bypasses this problem as the message will get re-injected back into the queue for delivery.

However this change does cause some problems for sites that already have existing aliases in use. The problem is that when you go into qmailadmin-1.0.21 and select the forwards screen, all the existing aliases and forwards for that domain are displayed.

Problem # 1 : For mail that is being redirected to a local account, you can’t tell from this screen whether the user is getting alias or forward delivery. If you were trying to setup some tricky per-user stuff, then you are going to get variable results because some users may be configured as alias, and others are configured as forward, but you cant easily tell which is which from this screen

Problem # 2 : Up the top there is a count showing “[Used # / limit]“. This count relates to the number of forwards in use and the maxforwards qmailadmin-limits setting. The count ignores any existing aliases. This could potentially cause confusion for domain postmasters as you will be looking at a screen full of accounts and if some of them have been previously setup as aliases then it is going to be hard to reconcile the reported count against the number of accounts displayed on the screen

What is needed is some sort of utility that will scan and find existing aliases and convert them over to the now-preferred forward syntax…. That would keep the delivery method consistent for all users, and would also eliminate any problems with the qmailadmin-limits code

Note: As of qmailadmin-1.0.25, there is a tool for converting existing aliases to forwards. Look in the contrib dir for the tools called alias2forward.pl

valias processing :

qmailadmin v1.2.1 and later store aliases and autoresponders in valias table if vpopmail was compiled with –enable-valias. If you are upgrading from a previous version of QmailAdmin and used the –enable-valias option when building vpopmail, be sure to download vpopmail 5.4.1 or later and use the dotqmail2valias program to convert .qmail-alias files to valias table entries.


COURIER IMAP

http://www.courier-mta.org/imap/

Courier-IMAP is an IMAP server. Having an IMAP server is a prerequisite to be able run a IMAP-client WebMail system like SquirrelMail. Courier-IMAP is good choice because it has support for vpopmail authentication and maildir mailboxes.

Download and unpack the authentication library

cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/courier/courier-authlib-0.58.tar.bz2
bunzip2 courier-authlib-0.58.tar.bz2
tar xf courier-authlib-0.58.tar
chown -R root.root courier-authlib-0.58
cd courier-authlib-0.58

Build the authentication library

./configure \
  --prefix=/usr/local/courier-authlib \
  --without-authpam \
  --without-authldap \
  --without-authpwd \
  --without-authmysql \
  --without-authpgsql \
  --without-authshadow \
  --without-authuserdb \
  --without-authcustom \
  --without-authcram \
  --without-authpipe \
  --with-authdaemon \
  --with-authvchkpw
# note, if you are running redhat/fedora, you may have to add a
#   --with-redhat
# to the list of configuration settings above
make
make install
make install-configure

Review the settings for the authentication library

vi /usr/local/courier-authlib/etc/authlib/authdaemonrc
authmodulelist="authvchkpw"
<-- Authenticate via vpopmail

Configure the authentication library so it is running all the time from bootup onwards

cp courier-authlib.sysvinit /etc/rc.d/init.d/courier-authlib
chmod 744 /etc/rc.d/init.d/courier-authlib
chkconfig --add courier-authlib

Then I like to use the ntsysv program to double-check that courier-authlib is set to launch at boot time

If you aren’t ready to reboot the server now, you can fire up the authentication libraries in the mean time with this command :

/etc/rc.d/init.d/courier-authlib start

At this point the courier-authlib software should be running. A good way to verify this is to use this command :

ps axf

And if all is well, you should be able to see something like this :

23689 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger -pid=/usr/local/courier-authlib/var/spool/
23690 ? S 0:00  \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond
23702 ? S 0:00      \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond
23703 ? S 0:00      \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond
23704 ? S 0:00      \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond
23705 ? S 0:00      \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond
23706 ? S 0:00      \_ /usr/local/courier-authlib/libexec/courier-authlib/authdaemond

FAM + Courier-IMAP on Redhat 7.3 doesnt seem very stable. On old Linux platforms, I would recommend you remove FAM before trying to install Courier-IMAP ( By the way, the alternative/replacement package GAMIN seems to works OK with Courier-IMAP on newer platforms like FC4/FC5/CentOS43)

rpm -e fam fam-devel

Download and unpack the courier-IMAP source

cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/courier/courier-imap-4.1.1.tar.bz2
bunzip2 courier-imap-4.1.1.tar.bz2
tar xf courier-imap-4.1.1.tar
chown -R root.root courier-imap-4.1.1
cd courier-imap-4.1.1

Build the program

COURIERAUTHCONFIG=/usr/local/courier-authlib/bin/courierauthconfig \
CPPFLAGS=-I/usr/local/courier-authlib/include \
./configure \
  --prefix=/usr/local/courier-imap \
  --disable-root-check \
  --with-ssl
# note, if you are running redhat/fedora, you may have to add a
#   --with-redhat
# to the list of configuration settings above
make
make install
make install-configure

The Courier-IMAP package includes 4 servers that can be individually enabled/disabled : IMAP, IMAP-SSL, POP3, POP3SSL. In this example, we are only using the IMAP server.

vi /usr/local/courier-imap/etc/imapd
MAXDAEMONS=40
MAXPERIP=40
IMAP_EMPTYTRASH=Trash:7,Sent:30
IMAPDSTART=YES
<-- Max number of IMAP daemons
<-- All connections will be coming from single IP (SquirrelMail on localhost)
<-- Enable automatic purging of mail from these folders
<-- allow our init.d script (below) to boot up the imapd

Configure Courier-IMAP so it is running all the time from bootup onwards

cp courier-imap.sysvinit /etc/rc.d/init.d/courier-imap
chmod 744 /etc/rc.d/init.d/courier-imap
chkconfig --add courier-imap

Then I like to use the ntsysv program to double-check that courier-imap is set to launch at boot time

If you aren’t ready to reboot the server now, you can fire up Courier-IMAP in the mean time with this command :

/etc/rc.d/init.d/courier-imap start

At this point the Courier-IMAP software should be running. A good way to verify this is to use this command :

ps axf

And if all is well, you should be able to see something like this :

1030 ? S 0:02 /usr/local/courier-imap/libexec/authlib/authdaemond.plain start
1031 ? S 1:00  \_ /usr/local/courier-imap/libexec/authlib/authdaemond.plain start
1032 ? S 0:59  \_ /usr/local/courier-imap/libexec/authlib/authdaemond.plain start
1033 ? S 1:01  \_ /usr/local/courier-imap/libexec/authlib/authdaemond.plain start
1035 ? S 1:02  \_ /usr/local/courier-imap/libexec/authlib/authdaemond.plain start
1036 ? S 1:02  \_ /usr/local/courier-imap/libexec/authlib/authdaemond.plain start
17566 ? S 0:00 /usr/local/courier-imap/libexec/couriertcpd -address=0 -stderrlogger=/usr/local/courier-
17569 ? S 0:00 /usr/local/courier-authlib/sbin/courierlogger imapd

SQWEBMAIL

SqWebMail is a webmail program written by the authors of Courier-Authlib/Courier-IMAP. Most webmail packages use POP3 or IMAP, but SqWebMail is a bit different – it accesses the Maildirs directly.

I wouldn’t really recommend SqWebMail ( you are better off using the Squirrelmail instructions below). But I regularly see people asking how to install SqWebMail, so I am going to add some notes here to show what the required steps would be if you chose to use this package instead of Courier-IMAP / Squirrelmail. I wont go into a heap of detail, but here are the steps you would need to follow

Note, to run SqWebMail, you still need to have Courer-Authlib installed as per the instructions above, but you don’t have to install Courier-IMAP. You can run Courier-IMAP if you want, it wont interfere with SqWebMail.

mkdir -p /usr/local/apache/htdocs/images/sqwebmail
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>YourISP support - call xxxx xxxx</center>"' >> /usr/local/bin/sqwebmail-banner.sh
chmod 755 /usr/local/bin/sqwebmail-banner.sh
cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/courier/sqwebmail-5.1.1.tar.bz2
tar xjf sqwebmail-5.1.1.tar.bz2
chown -R root.root sqwebmail-5.1.1
cd sqwebmail-5.1.1
COURIERAUTHCONFIG=/usr/local/courier-authlib/bin/courierauthconfig \
CPPFLAGS=-I/usr/local/courier-authlib/include \
./configure \
  --prefix=/usr/local/sqwebmail \
  --disable-autorenamesent \
  --enable-cgibindir=/usr/local/apache/cgi-bin/ \
  --enable-imagedir=/usr/local/apache/htdocs/images/sqwebmail/ \
  --enable-imageurl=/images/sqwebmail \
  --with-maxformargsize=17500000 \
  --with-maxmsgsize=18000000 \
  --enable-bannerprog=/usr/local/bin/sqwebmail-banner.sh
# If you get a pcre error during sqwebmail configure, you will probably need to do this :
# cd /usr/local/src
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-6.4.tar.gz
# tar xzf pcre-6.4.tar.gz
# chown -R root.root pcre-6.4
# cd pcre-6.4
# ./configure
# make
# make install
make
make install
make install-configure
echo "yourdomain.com" > /usr/local/sqwebmail/etc/hostname
# Add a line like this to your httpd.conf, to workaround MSIE bugs
BrowserMatch "MSIE" nokeepalive downgrade-1.0 force-response-1.0
crontab -e
# Purge sqwebmail cache files once per hour
0 * * * * /usr/local/sqwebmail/share/sqwebmail/cleancache.pl
vi /etc/rc.d/rc.local
/usr/local/sqwebmail/libexec/sqwebmaild.rc start

To access SqWebMail, the URL would be http://webmail.yourdomain.com/cgi-bin/sqwebmail

To customise look/feel, you can modify the HTML files in /usr/local/sqwebmail/share/sqwebmail/html/en, and also the css file /usr/local/apache/htdocs/images/sqwebmail


SQUIRRELMAIL

www.squirrelmail.org

the text with yellow background is specific to using MySQL backend. if you don’t want to use MySQL backend, then just skip over these sections….

Go to the SquirrelMail download page, and save the latest source to /usr/local/src. In this example I have used :

squirrelmail-1.4.4.tar.gz

Download and unpack all the sources

cd /usr/local/apache/htdocs
tar xzf /usr/local/src/squirrelmail-1.4.4.tar.gz
chown -R root.www squirrelmail-1.4.4
chmod -R 750 squirrelmail-1.4.4
ln -s squirrelmail-1.4.4 squirrelmail

Create the required directory structure

mkdir /var/squirrelmail
# create the data dir. This is where users personal preferences are stored if not using MySQL backend
mkdir /var/squirrelmail/data
# create the attach dir. This is where temp files for emails in progress are store
mkdir /var/squirrelmail/attach
cd squirrelmail
cp data/default_pref /var/squirrelmail/data
chown -R root.www /var/squirrelmail
chmod -R 0770 /var/squirrelmail/data
chmod -R 0730 /var/squirrelmail/attach

SquirrelMail allows you to add your company logo to the login page. So whack a copy of your logo into the Apache images directory so it is available for SquirrelMail to use

cp /usr/local/src/yourcompanylogo-100.gif /usr/local/apache/htdocs/images

Configure SquirrelMail

cd config
perl conf.pl
D. SET PRE-DEFINED SETTINGS FOR SPECIFIC IMAP SERVERS
  Choose Courier
1. ORGANIZATION PREFERENCES
  1.  Organization name            : YourCompany WebMail
  2.  Organization Logo            : /images/yourcompanylogo-100.gif
  3.  Org. Logo Height/Width       : 100/100
  4.  Organization title           : YourCompany WebMail (v$version)
  7.  Provider link                : http://www.yourdomain.com
  8.  Provider name                : YourCompany
2. SERVER SETTINGS
  1.  Domain                       : yourdomain.com
3. FOLDER DEFAULTS
  15. Default Unseen Type          : 2
4. GENERAL OPTIONS
  1.  Data directory               : /var/squirrelmail/data
  2.  Attachment directory         : /var/squirrelmail/attach
  5.  Usernames in lower case      : true
  7.  Hide SM attributions         : true
  11. Allow server-side sorting    : false
  ( Note, server-sorting is faster, but I personally find the sort results to be not as "intuitive"
   compared with when you let SquirrelMail do the sorting. If you toggle this option on/off and compare
   the resultant displays in SquirrelMail you will see what I mean. For example if you server-sort the
   FROM column then the sort will be done senders email address, whereas if you let SquirrelMail do the
   sort then column will be sorted on senders name. I would suggest you try toggling this
   option on and off to make your own decision on which sorting method provides the better results.)
6. ADDRESS BOOKS
  2. Use Javascript Address Book Search : True
9. DATABASE
  1.  DSN for address book : mysql://squirreluser:squirrelpassword@localhost/squirrelmail
  3.  DSN for preferences  : mysql://squirreluser:squirrelpassword@localhost/squirrelmail
Now Save and quit the config program

Create the necessary database and tables in MySQL, so that SquirrelMail can store the address books and user preferences there :

cd /usr/local/mysql/bin
./mysql --password="mysql-root-pwd"
CREATE DATABASE squirrelmail;
GRANT select,insert,update,delete ON squirrelmail.*
TO squirreluser@localhost IDENTIFIED BY 'squirrelpassword';
USE squirrelmail;
CREATE TABLE address (
  owner varchar(128) DEFAULT '' NOT NULL,
  nickname varchar(16) DEFAULT '' NOT NULL,
  firstname varchar(128) DEFAULT '' NOT NULL,
  lastname varchar(128) DEFAULT '' NOT NULL,
  email varchar(128) DEFAULT '' NOT NULL,
  label varchar(255),
  PRIMARY KEY (owner,nickname),
  KEY firstname (firstname,lastname)
);
CREATE TABLE userprefs (
  user varchar(128) DEFAULT '' NOT NULL,
  prefkey varchar(64) DEFAULT '' NOT NULL,
  prefval blob DEFAULT '' NOT NULL,
  PRIMARY KEY (user,prefkey)
);
quit

You can define what default SquirrelMail settings that users will receive when they log in.

For MySQL backend

cd /usr/local/apache/htdocs/squirrelmail
# replace the default preferences definition in the db_prefs file
# with our own customised defaults.
# Open the file, scroll down and replace the existing "var $default"
# entry (on line 102) with our customised version shown below
vi functions/db_prefs.php
var $default = Array('chosen_theme' => '../themes/default_theme.php',
  'show_html_default' => '1',
  'language' => 'en_US',
  'use_javascript_addr_book' => '1',
  'left_size' => '140',
  'left_refresh' => '3600',
  'show_username' => '1',
  'show_username_pos' => 'top',
  'order1' => '1',
  'order2' => '2',
  'order3' => '3',
  'order4' => '5',
  'order5' => '4',
  'order6' => '6');

Or, if you aren’t running MySQL backend for SquirrelMail, you can adjust the default preferences like this :

vi /var/squirrelmail/data/default_pref :

show_html_default=1
language=en_US
use_javascript_addr_book=1
left_size=140
left_refresh=3600
show_username=1
show_username_pos=top
order1=1
order2=2
order3=3
order4=5
order5=4
order6=6

Setup periodic purging of the “attach” directory

When SquirrelMail users are composing a message that has attachment(s), the attachment is temporarily stored in the /var/squirrelmail/attach directory.  When the user sends the message, the associated temp files will get deleted.

However sometimes the temp files do not get deleted (eg if the user closes their browser mid-compose?).  Since the permissions on this directory are setup (as a security measure) to prevent the webserver from listing the files in this directory, there is no way for Apache/SquirrelMail to do a periodic scan/purge of old files.

So we are going to setup a daily crontab to clean up any attachments that get left hanging around

crontab -e
# delete any files that are more than 2 days old from the SquirrelMail attachment dir
0 0 * * * find /var/squirrelmail/attach/* -atime +2 -exec /bin/rm {} \;

Install the quota_usage plugin so users can see their mailbox quota usage

cd /usr/local/src
wget http://www.squirrelmail.org/plugins/quota_usage-1.2.tar.gz
wget http://www.squirrelmail.org/plugins/compatibility-1.3.tar.gz
cd /usr/local/apache/htdocs/squirrelmail/plugins
tar xzf /usr/local/src/quota_usage-1.2.tar.gz
cp quota_usage/config.php.sample quota_usage/config.php
chown -R root.www quota_usage
chmod -R o-rx quota_usage
# qmailadmin and the other tools all classify a 1Mb as 1048576 bytes (1024 * 1024 )
# Fix up the quota_plugin so it works with the same units.
# Otherwise your quota would show as 20M in qmailadmin, and 21M in SquirrelMail  :-/
vi quota_usage/functions.php
Go to line 43 and change the value 1000000 to 1048576
tar xzf /usr/local/src/compatibility-1.3.tar.gz
chown -R root.www compatibility
chmod -R o-rx compatibility
cd ../config
perl conf.pl
8. Plugins
      choose quota_usage
      choose compatibility

Optionally, Setup SSL mode at login time

cd /usr/local/src
wget http://www.squirrelmail.org/plugins/secure_login-1.2-1.2.8.tar.gz 
cd /usr/local/apache/htdocs/squirrelmail/plugins
tar xzf /usr/local/src/secure_login-1.2-1.2.8.tar.gz
cp secure_login/config.php.sample secure_login/config.php
chown -R root.www secure_login
chmod -R o-rx secure_login
cd ../config
perl conf.pl
8. Plugins, and choose secure_login

Optionally, modify SquirrelMail so that it will any failed login attempts to the syslog

modify squirrelmail/functions/imap_general.php

search for the line that has “Unknown user or password incorrect”
above this line add :

syslog(LOG_MAIL|LOG_NOTICE,"Squirrelmail login failed for Username : $username, Password : $password");

now failed SquirrelMail logins will be logged to /var/log/maillog  :-)

We also added some code to squirrelmail/src/login.php to add a notes page to the login screen. We inserted this chunk just before the line that says “do_hook(‘login_bottom’);

echo "<BR><CENTER>".
"<TABLE BORDER=1 WIDTH=75%><TR><TD ALIGN=CENTER><FONT FACE=Arial SIZE=2>".
"<P><B><FONT SIZE=3>IMPORTANT NOTES REGARDING THE WEBMAIL SYSTEM</FONT></B></P>".
"<P><B>AUTOMATIC MAIL DELETION</B></P>".
"<P>The mail server will automatically delete mail from the<BR> ".
"following folders after the specified number of days :<br>".
"Trash Folder - 7 days, Sent Folder - 30 days".
"<P><B>POP3 MAIL CLIENTS</B></P>".
"<P>If you check your mail using a POP3 mail client (such as Outlook Express),<BR> ".
"it will download and delete the mail from your WebMail inbox.</P>".
"<P>If you want to be able to download the mail using POP3 and also<BR> ".
"leave it on the server so you can see it with WebMail, you will need<BR> ".
"to adjust the settings in your POP3 client to tell it not to delete<BR> ".
"mail after downloading.</P>".
"<P>For example, to configure this in Outlook Express you would go to<br> ".
"<i>Tools -> Accounts -> Mail -> Properties -> Advanced</i><BR> ".
"and then tick the box<BR><i>'Leave a copy of message on server'</i><P>".
"</FONT>".
"</TD><TR></TABLE></CENTER>";

Now, another cosmetic change… : modify the squirrelmail/src/login.php and change the wording of “Name:” to “Email address:”.

Next, we setup a default document in the web servers root, to redirect our customers through to the SquirrelMail login page. That way when people want to access the WebMail tool they can point their browser to “http://webmail.yourdomain.com” and they will get automatically redirected through to the SquirrelMail directory

vi /usr/local/apache/htdocs/index.html
<HTML>
<HEAD>
<TITLE>Redirect to WebMail login screen...</TITLE>
<META HTTP-EQUIV="refresh" CONTENT="1; url=http://webmail.yourdomain.com/squirrelmail/">
</HEAD>
<BODY>
Redirecting to the WebMail login screen...<br>
<a href=squirrelmail/>Click here if you are not automatically redirected</a>
</BODY>
</HTML>

SPAM AND VIRUS CHECKING

OK, now you have a working mail server.. You have loaded all your users and they are giving the new system a good workout. Everything is running nice and smoothly. You sit back and think “my job is done!”

Until… users starting coming to you and saying… “Hey, this new mail server is really good… But how do I block out all these viruses and spam?”… Uh oh…!

Well, luckily the answer is relatively easy….. The qmail-scanner program lets us easily implement anti-spam and anti-virus. Installation instructions follow :

OPTIONAL : RAZOR V2

http://razor.sourceforge.net

If Razor is installed, SpamAssassin will automatically include it in the list of tests run. We found that Razor is quite accurate in identifying spam, and it only added small amount of extra CPU load on the server, so it is definitely worth installing. Note though, that I believe the licensing of Razor states that it isn’t free for commercial use – so you should probably check the docs before deciding whether you wish to enable this function or not

Compile and install :

# install the pre-requisite modules for razor
perl -MCPAN -e shell
#(enter your way through all the questions. The only one you will likely have to answer is regarding your Continent/Country)
# tell the cpan shell to follow the dependency tree and automatically grab any required modules
o conf prerequisites_policy follow
# make sure you have some of the basic tools needed to get the CPAN downloads working smoothly
install LWP MD5
# install the razor pre-requisites now
install Net::Ping Net::DNS Time::HiRes Digest::SHA1 Getopt::Long File::Copy Digest::Nilsimsa URI::Escape
quit
# now install the actual razor software
wget http://optusnet.dl.sourceforge.net/sourceforge/razor/razor-agents-2.77.tar.bz2
bunzip2 razor-agents-2.77.tar.bz2
tar xf razor-agents-2.77.tar
chown -R root.root razor-agents-2.77
cd razor-agents-2.77
perl Makefile.PL
make
make test
make install
cd ..

The Razor programs will now be installed in /usr/bin. In particular, SpamAssassin makes use of the program called : “razor-check”

Last job is to create the Razor configuration files (they get put into /etc/razor/) by using these commands :

razor-admin -d -create -home=/etc/razor

If your server is going to be busy, then I would recommend you edit the razor config file and turn down the debugging level a bit :

vi /etc/razor/razor-agent.conf
debuglevel=1

SPAMASSASSIN 

http://www.spamassassin.org

Description :

SpamAssassin is program that scans email messages using a set of rules, and then assigns a score. If the score is higher than your nominated limit, then the message will be tagged as spam.

# install the pre-requisite modules for spamassassin
perl -MCPAN -e shell
# tell the cpan shell to follow the dependency tree and automatically grab any required modules
o conf prerequisites_policy follow
# make sure we have all the SpamAssassin prerequisites installed
install Digest::SHA1 HTML::Parser Storable MIME::Base64 DB_File Net::DNS Net::SMTP Mail::SPF::Query IP::Country::Fast BerkeleyDB
exit

Download and compile

wget http://apache.mirror.pacific.net.au/spamassassin/source/Mail-SpamAssassin-3.1.2.tar.gz
tar xzf Mail-SpamAssassin-3.1.2.tar.gz
chown -R root.root Mail-SpamAssassin-3.1.2
cd Mail-SpamAssassin-3.1.2
perl Makefile.PL
make
make install
cd ..

“make install” creates the following main files :

/usr/bin/spamassassin            <- This is the command-line version of the SpamAssassin program
/usr/bin/spamc                   <- Daemonised SpamAssassin client
/usr/bin/spamd                   <- Daemonised SpamAssassin server
/usr/share/spamassassin/         <- The SpamAssassin logic/filter files live here
/etc/mail/spamassassin/local.cf  <- sitewide configuration settings

Test to see if the installation was successful. (Watch the output from the script. SpamAssassin will add headers to the message. In particular look for the “X-Spam-Status: ” and see if it correctly tags the message with a Yes or No)

spamassassin -t < sample-nonspam.txt
spamassassin -t < sample-spam.txt

To improve security, modify the configuration of the spamd daemon so it runs under its own uid

Create a spamd user for the spamd process to run as

groupadd spamd
useradd -g spamd spamd

Modify / create the spamd configuration file

vi /etc/sysconfig/spamassassin
# Hint : if you want to enable SpamAssassin debugging
# (the debug output goes to /var/log/maillog) then use :
# SPAMDOPTIONS="-x -u spamd -H /home/spamd -d -D"
# Don't leave debugging turned on unnecessarily though,
# because it will slow down a busy server.
#
# Otherwise, for normal operation (debugging disabled) use following combo :
# -x means not to look for any per-user preferences ( since all our users are virtual)
# -u means to run as userid spamd
# -H tells the addon apps like .razor to store all their files into eg /home/spamd/.razor
# -d tells spamd to run as a daemon
SPAMDOPTIONS="-x -u spamd -H /home/spamd -d"

Configure the spamd daemon so it is running all the time from bootup onwards

cp spamd/redhat-rc-script.sh /etc/rc.d/init.d/spamd
chmod 700 /etc/rc.d/init.d/spamd
cd ..
chkconfig --add spamd

Then I like to use the ntsysv program to double-check that spamd is set to launch at boot time

Setup the SpamAssassin configuration

vi /etc/mail/spamassassin/local.cf
# Define the sensitivity level.
required_score 5
# Allow SpamAssassin to rewrite the subject line of any messages it classifies as spam
# This is the value that will prepended to the subject line of messages classified as spam
rewrite_header Subject [SPAM]
# Put spam analysis reports into to the headers of the message (rather than the body)
report_safe 0
# Enable SpamAssassin's RBL checking features :
# Although we have already done some RBL filtering earier in qmail's rblsmtpd program,
# it is still recommended to turn on RBL checking in SpamAssassin, as it will run
# checks against a variety of different RBL sources, and the results will help
# tag spam more accurately
skip_rbl_checks 0
# If we haven't received a response from the RBL server in X seconds, then skip that test
rbl_timeout 3
# You can nominate any netblocks that you control, and contain mailservers that
# you trust. IE you control the mailservers in these netblocks so there is no
# need to be running RBL checks against these particular servers.
# You should include all the netblocks used by email clients on your local lan.
# Also make sure you include any netblocks that host your mail servers.
trusted_networks 127.0.0.1
trusted_networks 123.123.123.0/24
# Enable auto-learning
use_bayes 1
bayes_auto_learn 1
# we are going to run a single global bayes db for all users ( rather than a db per user)
bayes_path /home/spamd/.spamassassin/bayes
# Enable auto-whitelisting
use_auto_whitelist 1

Just to make sure the bayes database directory will be setup correctly :

mkdir /home/spamd/.spamassassin
chown -R spamd.spamd /home/spamd/.spamassassin

If you wish to view all the possible configuration options, use this command :

perldoc Mail::SpamAssassin::Conf

Enable the razor functions

vi /etc/mail/spamassassin/v310.pre
#uncomment the following line :
loadplugin Mail::SpamAssassin::Plugin::Razor2

OK, the SpamAssassin software is now fully installed!

Any mail that SpamAssassin classifies as spam will have [SPAM] added to the subject line.  You should now probably setup some docs for your users showing them how they can use message filtering rules in their email client. You can see our message filtering guides here

If you aren’t ready to reboot the server now, you can fire up spamd in the mean time with this command :

/etc/rc.d/init.d/spamd start

If all goes well you will see some output like this :

9721 ? S 0:01 /usr/bin/spamd -x -u spamd -H /home/spamd -d

(Note that spam filtering isn’t actually operational on your server yet, you need to use the qmail-scanner program to feed mail through the SpamAssassin scripts)

CLAM ANTI-VIRUS

http://www.clamav.net

Clam antivirus can run in two different modes. Either as a normal command line scanner, or as a client/daemon pair.

When working as a command line scanner, you perform your scanning using the program “clamscan”. If a complex program like a virus scanner is run repetitively (ie being launched for every email that passes through your system), it chews up a lot of CPU/disk resources. To get around this issue you can launch Clam as a daemon (clamd). This is where a copy of Clam is launched and stays active in the background. You then do your scanning using the clamdscan client, which is only small, thus making it fast to launch/run. The client sends commands to the daemon, and the daemon will take care of scanning the message and returning the results to the client. (The same technique is used by SpamAssassin where you can use the full spamassassin command line version, or the spamc/spamd client/daemon pair).

In a busy environment, there is no doubt that the client/daemon method is the best way to go

groupadd clamav
useradd -g clamav -s /bin/false -c "Clam AntiVirus" clamav
cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/clamav/clamav-0.88.tar.gz
tar xzf clamav-0.88.tar.gz
chown -R root.root clamav-0.88
cd clamav-0.88
./configure
make
make install

Customise the clamd configuration file

vi /usr/local/etc/clamd.conf
# make sure you comment out the "example" line
LogSyslog
FixStaleSocket
User clamav

Configure clamd so it is running all the time from bootup onwards

cp contrib/init/RedHat/clamd /etc/rc.d/init.d/
chmod 744 /etc/rc.d/init.d/clamd
chkconfig --add clamd

Then I like to use the ntsysv program to double-check that clamd is set to launch at boot time

If you aren’t ready to reboot the server now, you can fire up clamd in the mean time with this command :

/etc/rc.d/init.d/clamd start

At this point the clamd software should be running. A good way to verify this is to use this command :

ps axf

And if all is well, you should be able to see something like this :

18144 ? S 0:00 /usr/local/sbin/clamd

Setup the freshclam configuration file

vi /usr/local/etc/freshclam.conf
# make sure you comment out the "example" line
LogSyslog
DatabaseOwner clamav
DatabaseMirror db.au.clamav.net  (where "au" matches your country code)
NotifyClamd

Configure freshclam to start on boot

vi /etc/rc.d/rc.local
/usr/local/bin/freshclam -d

Launch freshclam now

/usr/local/bin/freshclam -d

At this point the freshclam software should be running. A good way to verify this is to use this command :

ps axf

And if all is well, you should be able to see something like this :

18144 ? S 0:00 /usr/local/sbin/clamd

QMAIL-SCANNER

http://qmail-scanner.sourceforge.net

Description :

Qmail-Scanner is an add-on that enables a qmail server to scan messages for certain characteristics. It is typically used for its anti-virus protection functions, in which case it is used in conjunction with commercial (or open source) virus scanners. It also capable of blocking email that contains specific strings in particular headers, or particular attachment filenames or types (e.g. *.VBS attachments).

Install the required supporting modules for Qmail-Scanner

TNEF unpacker

http://sourceforge.net/projects/tnef/
cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/tnef/tnef-1.3.4.tar.gz
tar xzf tnef-1.3.4.tar.gz
chown -R root.root tnef-1.3.4
cd tnef-1.3.4
./configure
make
make install
cd ..

ReformatMIME (from the Maildrop package)

http://sourceforge.net/projects/courier
cd /usr/local/src
wget http://optusnet.dl.sourceforge.net/sourceforge/courier/maildrop-2.0.1.tar.bz2
bunzip2 maildrop-2.0.1.tar.bz2
tar xf maildrop-2.0.1.tar
chown -R root.root maildrop-2.0.1.tar
cd maildrop-2.0.1
./configure
make
make install-strip
make install-man
cd ..

A “Qmail-Scanner ST patch” has been released by Salvatore Toribio, which greatly extends the functionality of qmail-scanner. The patch adds extra features to help deal with spam (such as dropping messages that exceed a certain SpamAssassin score). We are going to use this patch, as it makes qmail-scanner much more useful.

cd /usr/local/src
# Grab the qmail-scanner source
wget http://optusnet.dl.sourceforge.net/sourceforge/qmail-scanner/qmail-scanner-1.25.tgz
tar xzf qmail-scanner-1.25.tgz
chown -R root.root qmail-scanner-1.25
# Grab and apply the qmail-scanner-st patch
wget http://toribio.apollinare.org/qmail-scanner/download/q-s-1.25st-20050406.patch.gz
gunzip q-s-1.25st-20050406.patch.gz
patch -p0 < q-s-1.25st-20050406.patch
cd qmail-scanner-1.25

Now at this point, I would recommend you spend some time reading the qmail-scanner documentation. And once you have read that, take a look at the qmail-scanner-st patch doco

Next, create a user and group for the qmailscanner to run under

groupadd qscand
useradd -c "Qmail-Scanner Account" -g qscand -s /bin/false qscand

For qmailscanner to work correctly with clamav, you need to adjust clamav to run under the qscand username

vi /usr/local/etc/clamd.conf
# look for the line that says "User clamav" and replace with
User qscand
/etc/rc.d/init.d/clamd restart

Configure Qmail-Scanner :

# Here are the settings we used at our site for configuring Qmail-Scanner :
#
# configure Qmail-Scanner to work in the following manner :
#   - notify a nominated admin each time a virus is detected
#     (in this case it will be virusadmin@yourdomain.com)
#   - use the client/server version of Clam AV for anti-virus scanning.
#   - enable support for spamc/spamd in "verbose" mode.
#     Qmail-Scanner can run spamd in "fast" mode or "verbose" mode.
#     You can read more about this at the Qmail-Scanner FAQ page.
#     I would recommend that you use verbose mode as this allows you to get access to
#     the full reporting/tagging features that SpamAssassin can provide. It costs you
#     a fraction more CPU power, but provides a much greater range of features.
#   - Use a medium level of sensitivity when blocking mail due to broken MIME formatting
#
#   THE COMMANDS HIGHLIGHTED IN BLUE BELOW ARE FROM THE QMAIL-SCANNER-ST PATCH
#   - sa-delete sets the point that spam mail is autodeleted.
#     sa-delete is a relative value to the SpamAssassin required_hits.
#     so in our case, the spam will be deleted at a score of 10
./configure \
  --admin virusadmin \
  --domain yourdomain.com \
  --admin-fromname "yourdomain.com Postmaster" \
  --local-domains "yourdomain.com" \
  --scanners clamdscan,verbose_spamassassin \
  --fix-mime 1 \
  --debug no \
  --sa-delete 5 \
  --sa-reject yes \
  --install

Note : If the install fails with an error like this :

Redhat hosts need to have perl-suidperl installed to get setuid support

Then you will need to do something like this (this example for Redhat 7.3) :

cd /usr/local/src
wget http://redhat.pacific.net.au/redhat/redhat-7.3-en/os/i386/RedHat/RPMS/perl-suidperl-5.6.1-34.99.6.i386.rpm
rpm -ivh perl-suidperl-5.6.1-34.99.6.i386.rpm

Edit the perscanner file which is used to block mail that contains particular strings. perlscanner is a tool that is included with qmail-scanner, and it is executed after all the other anti-virus scanners have run (eg clamscan). This system provides a good failsafe in case some new virus comes along that the virus-scanner cant detect yet. perlscanner is perfect for blocking those virus-prone attachments that have no legitimate purpose in email.

vi /var/spool/qscan/quarantine-events.txt

Uncomment the following lines :

.lnk SIZE=-1 LNK files not allowed per Company security policy
.wsh SIZE=-1 WSH files not allowed per Company security policy
.vbs SIZE=-1 VBS files not allowed per Company security policy
.scr SIZE=-1 SCR files not allowed per Company security policy
.hta SIZE=-1 HTA files not allowed per Company security policy
.pif SIZE=-1 PIF files not allowed per Company security policy
.cpl SIZE=-1 CPL files not allowed per Company security policy
# rebuild the perlscanner database
setuidgid qmaild /var/qmail/bin/qmail-scanner-queue.pl -g

Any SMTP sessions that are dropped (due to network outages/etc) may lead to files lying around in /var/spool/qmailscan . Running /var/qmail/bin/qmail-scanner-queue.pl -z at least once daily will ensure such files are deleted when they’re over 30 hours old. We will make a cronjob to do that :

crontab -e
0 0 * * * /var/qmail/bin/qmail-scanner-queue.pl -z

Now define what mail is to be sent through the Qmail-Scanner, also make sure that your qmail-smtpd script allocates sufficient resources to support the needs of Qmail-Scanner + Antivirus + SpamAssassin. At our site, we have configured Qmail-Scanner to virusscan all messages (ie inbound and outbound mail). We did this by setting up our our /var/qmail/supervise/qmail-smtpd/run file like this :

vi /var/qmail/supervise/qmail-smtpd/run
#!/bin/sh
# when QMAILQUEUE is set, all mail will be sent to the nominated script
QMAILQUEUE="/var/qmail/bin/qmail-scanner-queue.pl" export QMAILQUEUE

QMAILDUID=`id -u qmaild`
NOFILESGID=`id -g qmaild`

# softlimit needs to be set at something large such as 15000000
# to allow virusscanning software to run successfully
exec /usr/local/bin/softlimit -m 15000000 \
 /usr/local/bin/tcpserver \
  -v -x /etc/tcp.smtp.cdb \
  -c 20 -R -u "$QMAILDUID" -g "$NOFILESGID" 0 smtp \
... and the rest of the file snipped ...

Restart the qmail-smtpd service :

svc -d /service/qmail-smtpd
svc -u /service/qmail-smtpd

However, if you don’t want to virusscan all mail, you can selectively nominate which IP ranges should or shouldn’t be checked by setting the QMAILQUEUE variable via your /etc/tcp.smtp file rather than inside the supervise/qmail-smtpd/run file. Refer to the Qmail-Scanner home page for setup examples.

QMAIL-SCANNER / SPAMASSASSIN NOTES :

How can I tell if SpamAssassin is working?

Each time SpamAssassin processes a message, it will log some information to /var/log/maillog (score, message size, time taken to process)

Not all mail gets passed through SpamAssassin

We have configured our supervise/qmail-smtpd/run script so that it runs Qmail-Scanner for every mail message. This means all incoming and outgoing mail will get virus-checked. However this doesn’t necessarily mean that every message passing through Qmail-Scanner will also get sent through SpamAssassin.

Qmail-Scanner has been coded so that messages are only passed onto SpamAssassin if the RELAYCLIENT variable from tcp.smtp is not set. The idea behind this to reduce load on the system by not running SpamAssassin on mail originated by your users.

It is possible to force SpamAssassin checking for local users if you choose by setting QS_SPAMASSASSIN=”on” for the appropriate entries in your tcp.smtp file

You can read more about this subject at the Qmail-Scanner FAQ page

Is it possible to configure per-user settings for SpamAssassin?

It depends on your configuration. We believe it will be possible to implement an interface so that vpopmail users can turn SpamAssassin checking on/off, and also set their own custom required_hits. We are hoping to store these settings as additional columns in the vpopmail MySQL database… Stay tuned and we will post more info as it comes to hand

Can I make it so that all the spam get sent to my a SPAM or TRASH folder?

Yes, have a look at this example, or take a look at the $smaildir option in the qmail-scanner-st patch

Qmail-scanner’s quarantine directory

Each virus infect mail message gets quarantines into the following directory :

/var/spool/qmailscan/quarantine/new

So you will need to periodically purge the files from that dir, or else your hard disk will eventually fill up!

eg setup a crontab entry like this :

0 * * * * find /var/spool/qmailscan/quarantine/new -type f -mtime +30 -exec rm '{}' \;

TIPS & MISC NOTES :

“ps axf” is your friend. Particularly useful for visualising how the supervise/qmail processes all fit together.
“ps axfu” is good for double checking what accounts that individual server processes are running under


SOME EXAMPLE MAILBOX MANAGEMENT SCRIPTS :

Since all the information for your email domains and mailboxes are store in MySQL, it is easy to create scripts so your support staff can quickly navigate / view all this account information.

Our support staff’s intranet site is a Windows 2000 machine running IIS5 with ASP. Here is a couple of example ASP scripts that I hacked together that show what can be achieved : vpopmail-asp-scripts.v120.zip.. No doubt it would be easy enough though to use these same techniques in PHP if you are running linux/apache for your intranet

The script “viewvlogs” allows you to view browse through the vpopmail “vlog” table in MySQL to look for people who have failed to auth successfully when trying to check mail.

The script “viewpop3″ allows you to see a list of email domains hosted on your server. You can do things like view all users from a domain, or view an individual mailbox. The output will show useful things like clear passwords, mailbox size. Also there are buttons that will log you into qmailadmin or SquirrelMail as a given user using just a single mouse click

Some screenshots of viewpop3 script:

Main login screen
Login to a domain, View all mailboxes on a domain
Login to an email address, View details for email address

One final note, if you are running IIS, you need to download and install the MySQL Connector ODBC “Windows Driver Installer” files onto your server to allows these ASP scripts to work.

On a related subject, have you ever wanted to be able to create mailboxes “on-the-fly” via a webpage or similar? Well if you are running the MySQL back-end, then you are in luck! It is possible to use an INSERT command to create the new user in the MySQL. When the user 1st POP/IMAP’s into their account, or when they first receive a message, their mailbox will automatically be created on the hard disk of the mail server. I have an example showing how I create mailboxes on-the-fly from an IIS server using an ASP script asp-vpopmail-passwd-entries.txt. ( And here is another link that shows how you can generate suitably encrypted passwords using PHP ). And there is some more spirited discussion on this subject here http://www.mail-archive.com/qmailadmin@inter7.com/msg03509.html


TODO :

  • Use netqmail-1.05
  • Update to MySQL v4.x
  • Use Fedora rather than Redhat

Other misc ramblings :

I sold the ISP that I used to own to a larger national provider, and now “I work for them”. At this larger company we use Postfix (and amavisd/spamassassin/clamd) rather than qmail (and qmail-scanner/spamd/clamd). After learning Postfix I can confidently say that it is a much superior MTA to qmail. However even the most pro-Postfix staff are amazed at the ease of use of the vpopmail/qmail system. Although Postfix also has virtual mailbox support, there is no easy-to-use package like vpopmail for driving this system. Since I now spend my days working with Postfix, my development of this webpage has slowed somewhat. Hopefully I will be able to find the time to keep this page fairly up to date  :-)    I have published a Postfix server guide


I have an Amazon wish list

A big thank you to these people who have sent me a gift :

  • Dave Richardson
  • Ken Winke
  • Joseph Schmitt II
  • Oban Lambie
  • Andrew Seely
  • Marco Varanda
  • Raymond Luong
  • Mansung Nojima
  • Charlie
  • Andrew Harteveldt
  • Nick Strupp
  • Carol Blevins
  • Marc van de Geijn

Back to Michael’s ISP Links page

Hit Counter<!––>

Last updated : 15-May-2007
Please send me your feedback!



ChangeLog :

15th May 2007 :

  • No further changes will be made to this guide. See the text at the top of the document for more info.

13th September 2006 :

  • Updated the URL of the page to new site.
  • I have an updated version of this guide probably 90% written – based on CentOS / Fedora with RPM installs of many apps… Let me know if you are interested in seeing it !

13th June 2006 :

  • Updated the SpamAssassin v3.1.2
  • For safety sake, added a mkdir/chown for /home/spamd/.spamassassin dir (Thanks to Steven Looi for the tip)
  • Updated to Courier-IMAP v4.1.1
  • Added a note about FAM to the Courier-IMAP section.

19th March 2006 :

29th March 2006 :

  • Added info about autorespond-2.0.5
  • Updated to Courier-Authlib v0.58
  • Updated to Courier-IMAP v4.1.0
  • Updated to SqWebMail v5.1.1
  • Updated to SpamAssassin v3.1.1
  • Updated to ClamAV 0.88
  • Have been madly working on Postfix/MySQL guide. Should be ready for publication soon. So far its a 140Kb, 2875-line monster html doc!

7th November 2005

  • Updated to SpamAssassin v3.1.0
  • Updated qmail-scanner, and added qmail-scanner-st patch

27th Sep 2005

  • Upgraded to vpopmail-5.4.10, qmailadmin-1.2.9, Courier-Authlib-0.57, Courier-IMAP-4.0.6, ClamAV-0.87
  • Added some SqWebMail installation notes
  • Added a note on SpamAssassin 3.1
  • Added Carol Blevins to the list of people who have sent me a gift :-)

15th Sep 2005

  • Increased the POP3d softlimit from 4000000 to 6000000, after James Ecker reported to me that 4000000 wasn’t sufficient when using Fedora/MySQL 4.1

1st Sep 2005

  • Added a ChangeLog  :-)
  • Updated SpamAssassin hyperlink from v303 to v304
  • Added a hyperlink for Razor download
  • Added note to see if anyone would be interested to see my Postfix equivalent to this guide

_uacct = “UA-898065-1″; urchinTracker();

10 nguyên tắc cho một website thương mại thành công

August 13, 2007 by duynam

Thương mại điện tử đã phát triển khác xa 10 năm trước và hiện nay, tính ứng dụng luôn được đặt lên hàng đầu. Sự nổi tiếng của một website đôi khi lại nhờ những yếu tố tưởng như rất nhỏ nhặt.


Ảnh: Larta.

1. Thông báo người sử dụng đang ở đâu

Bất cứ khi nào người dùng truy cập đến một gian hàng, website cần hiển thị vị trí của họ trong cấu trúc chung của site, chẳng hạn Home > Category > Sub-cat > Product.

2. Phân loại đa dạng

Website phải cung cấp đủ các chuẩn phân loại như “Giá cả” (Từ cao đến thấp, Từ thấp đến cao), “Tính phổ biến” (Bán chạy nhất, Được người dùng đánh giá cao nhất…), “Tính năng”, “Màu sắc”, “Kích cỡ”, “Sản phẩm mới” để khách hàng thỏa sức lựa chọn theo tiêu chí của riêng họ mà không gặp khó khăn.

3. Hiển thị tất cả sản phẩm cùng loại trên một trang

Trừ khi số sản phẩm lên tới hơn 200, website nên tạo điều kiện cho người sử dụng quan sát tổng thể các mặt hàng để họ dễ đối chiếu. Điều này cũng không khó thực hiện nhờ sự phổ biến của băng thông rộng hiện nay.

4. Càng chi tiết càng tốt

Một website sẽ được đánh giá cao nếu cung cấp một vài thông tin ấn tượng trước khi khách hàng bấm vào trang riêng về sản phẩm đó.

5. Chia sẻ thông tin có ích

Nhiều người sử dụng cho biết họ đã thấy rất nhiều mẫu quần áo đẹp, phù hợp “gu” thẩm mỹ của họ nhưng lại không biết bộ đồ đó có vừa với số đo của mình hay không. Hay không ít website kinh doanh cặp laptop “quên” thông báo chiếc cặp đó phù hợp cho máy tính xách tay 14 inch, 15 inch hay 17 inch…

5. Đặt thanh tìm kiếm ở vị trí dễ thấy

Ngay cả khi thực hiện xong lệnh search, website vẫn nên đặt thanh tìm kiếm ở vị trí trung tâm và giữ lại từ khóa cũ trong trường hợp người sử dụng muốn điều chỉnh lệnh để đạt kết quả phù hợp hơn. Bên cạnh đó, hệ thống tìm kiếm nâng cao theo giá cả, màu sắc, kích cỡ… sẽ không bao giờ thừa với khách hàng. (Người dùng vẫn xếp “tìm kiếm” là tính năng khó chịu nhất trên các website thương mại điện tử).

6. “Khoe” tối đa kho hàng của bạn


eBay mở rộng kết quả tìm kiếm bằng cách loại bỏ bớt từ khóa. Ảnh chụp màn hình.

eBay đã rất thông minh trong việc hiển thị sản phẩm mà họ có dựa trên lệnh tìm kiếm của khách hàng. Chỉ một chi tiết nhỏ thôi cũng góp phần thúc đẩy công việc kinh doanh của chủ nhân một gian hàng trực tuyến.

7. Thông báo ngay nếu hết hàng

Người sử dụng sẽ khó chịu nếu họ dành cả tiếng đồng hồ ngắm nghía sản phẩm nhưng mãi đến khi bấm chọn nó thì mới phát hiện ra rằng mặt hàng đó không còn trong kho.

8. Trực quan sinh động

Do không thể cảm nhận sản phẩm như trong đời thực, ảnh, video và những lời nhận xét là thông tin vô giá với khách hàng. Một bức ảnh ở một góc chụp duy nhất không thể đủ thuyết phục người mua.

9. Các cách chuyển hàng

Website nên liệt kê các phương pháp thanh toán và phân phối hàng hóa để người sử dụng xem có phù hợp với hoàn cảnh của họ không trước khi bắt đầu mua sắm.

10. Khẳng định giao dịch qua e-mail

Một khách hàng của Dell cho hay anh ta rất lo lắng không hiểu chiếc laptop mình đặt mua có được chuyển đến trước chuyến du lịch Trung Quốc không bởi anh không muốn dành 28 giờ trên máy bay mà thiếu máy tính. Rất may, e-mail khẳng định thời hạn giao hàng của Dell đã giúp anh bình tâm.