|
Postifx w/ SASL + Courier IMAP w/ SSL + Maildrop + MySQL + SpamAssassin
By: Serge Stepanov. If you have any questions, comments or flames (yes, even those), please direct them to my address above. UPDATE: You can post comments about this article at the bottom of the page. UPDATE 1/6/2005: Thanks to Mark Biek for his contributions to this article! Before asking a question, check this article for some fixes. In this document I am going to share my experience with setting up a viable virtual mail server solution for a Linux system. I have made countless attempts at trying to setup mail servers in the past, but have never been able to acheive the results that I desired. Whether it was the incomplete HOWTOs that I was reading or my own lack of knowledge on the subject, I don't know; but after eventually reading through enough document I was able to conceive a solution that works great (so far on two boxes). Most importantly, however, I will attempt to cover and help you resolve the common problems that myself and others have ran into. If you found this document interesting, I invite you to look at my VPN Server HOWTO: PoPToP PPTP + MPPE 128bit Encryption + MPPC Compression VPN Server By the end of this document you will hopefully achieve what I have:
To start off, you will use the following applications:
Installing Sources
First and foremost, you need to compile the sources of the top applications. I will not go through installing MySQL since it is outside of the scope of this document. OpenSSL Compile and install OpenSSL.
$ tar zxvf openssl-0.9.7c.tar.gz
$ ./config $ make $ make test $ make install (as root) Cyrus SASL v2 The following assumes that you have MySQL setup in: /usr/local/mysql. We will be using the built in MySQL authentication module, instead of having to redirect the authentication to PAM-MySQL. Prior to installing these modules, attempt to remove any pre-installed ones (look in: /usr/lib, /usr/local/lib, /usr/local/lib/sasl2).
$ tar zxvf cyrus-sasl-2.1.15.tar.gz
$ export CPPFLAGS="-I/usr/local/mysql/include/mysql" $ ./configure \ --enable-anon \ --enable-plain \ --enable-login \ --disable-krb4 \ --disable-otp \ --disable-cram \ --disable-digest \ --with-mysql=/usr/local/mysql/lib/mysql \ --without-pam \ --without-saslauthd \ --without-pwcheck \ --with-dblib=berkeley \ --with-bdb-libdir=/usr/local/bdb/lib \ --with-bdb-incdir=/usr/local/bdb/include \ --with-openssl=/usr/local/ssl \ --with-plugindir=/usr/local/lib/sasl2 $ make $ make install (as root) Check to make sure that the path /usr/local/lib is in /etc/ld.so.conf. If it is not, append that path to the file and run ldconfig (as root): $ echo "/usr/local/lib" >> /etc/ld.so.conf
$ ldconfig Postfix Compiling Postfix is pretty straight forward. Be sure to add the postfix user and group. During the install it will ask for the user and group, use postfix and postdrop. For the configuration directory, specify /etc/postfix.
$ groupadd postdrop -g 1001 (as root)
$ useradd postfix -u 1001 -g 1001 (as root) $ tar zxvf postfix-2.0.16.tar.gz $ make makefiles 'CCARGS=-DHAS_MYSQL \ -I/usr/local/mysql/include/mysql -DUSE_SASL_AUTH \ -I/usr/local/include/sasl -I/usr/local/bdb/include' 'AUXLIBS=-L/usr/local/mysql/lib/mysql \ -lmysqlclient -lz -lm -L/usr/local/lib -lsasl2 -L/usr/local/bdb/lib' $ make install (as root) After you finish with the interactive installation, you will need to check and see if Postfix is linked against SASL. To do this run the following from within the root of Postfix's source:
$ ldd ./bin/postconf
If everything worked well (and I hope it did), one of the lines should read: libsasl2.so.2 => /usr/local/lib/libsasl2.so.2
Courier IMAP As with Postfix, Courier IMAP should be simple to install. We will use /usr/local/courier as the base directory for the IMAPd and for Maildrop. This also allows you to use Courier MTA in the future without having to re-do a lot of things.
$ bzip2 -dc courier-imap-2.2.1.20031219.tar.bz2 | tar xvf -
$ ./configure \ --prefix=/usr/local/courier \ --with-mysql-libs=/usr/local/mysql/lib/mysql \ --with-mysql-includes=/usr/local/mysql/include/mysql/ \ --with-authmysql \ --with-authmysql=yes \ --with-authchangepwdir $ make $ make install (as root) Now here is where I ran into a problem, Courier IMAP wouldn't compile with SSL support (in the log it was complaining about couriertls not being found). For some reason it wasn't finding the SSL libraries. However, here is a quick fix that I found in a mail list (thanks to Michael Carmack).
$ cd <courier-source-dir>/tcpd
$ make distclean $ export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/local/ssl/lib $ export LD_RUN_PATH=${LD_RUN_PATH}:/usr/local/ssl/lib $ export C_INCLUDE_PATH=${C_INCLUDE_PATH}:/usr/local/ssl/lib $ export LDFLAGS="${LDFLAGS} -L/usr/local/ssl/lib -Wl,--rpath=/usr/local/ssl/lib" $ export CC="gcc -L/usr/local/ssl/lib -Wl,--rpath=/usr/local/ssl/lib" $ ./configure $ make couriertls $ cp ./couriertls /usr/local/courier/bin (as root) Viola! You just compiled courier's TLS interface with SSL support. Lastly, create an SSL certificate by running: $ /usr/local/courier/share/mkimapdcert
Courier Maildrop Now we go to installing Maildrop, our local delivery agent. First you create the user and group that Maildrop will deliver as. For our application, we will use vmail for both.
$ groupadd vmail -g 1004 (as root)
$ useradd vmail -u 1004 -g 1004 (as root) $ tar zxvf maildrop-1.6.3.tar.gz $ export CPPFLAGS="-I/usr/local/mysql/include" $ export LDFLAGS="-L/usr/local/mysql/lib" $ ./configure \ --prefix=/usr/local/courier \ --enable-maildropmysql \ --with-mysqlconfig=/usr/local/courier/etc/maildropmysql.config \ --enable-maildrop-uid=1004 \ --enable-maildrop-gid=1004 $ make $ make install (as root) SpamAssassin We're almost done installing our sources, just one more to go. Prior to installing SpamAssassin, get all the required Perl modules (check the INSTALL file).
$ tar zxvf Mail-SpamAssassin-2.63.tar.gz
$ perl MakeFile.PL $ make $ make install (as root) Database and Virtual Mail Directory Setup
Database The database side of this was used from Martin List-Petersen's excellent document, ISP Mailserver Solution Howto that helped me most of the way. I will just copy the CREATE TABLE syntax that is provided in his HOWTO and explain the use of two main tables (things such as the default uid and gid have been modified to fit this document). I expect that you have created the database (in this document we will use "mail" as our database) and have secured it with a user and password. CRITICAL NOTE: When creating the user for our database, create TWO: one that authenticates from "localhost" and one from "127.0.0.1" CREATE TABLE postfix_alias (
id int(11) unsigned NOT NULL auto_increment, alias varchar(128) NOT NULL default '', destination varchar(128) NOT NULL default '', PRIMARY KEY (id) ) TYPE=MyISAM; CREATE TABLE postfix_relocated ( CREATE TABLE postfix_transport ( CREATE TABLE postfix_users ( CREATE TABLE postfix_virtual ( CREATE TABLE postfix_access ( In this document I will only go over the postfix_users and postfix_virtual tables, as Martin List-Petersen does a great job at describing the rest. When we get to testing, I will go into detail on what goes into those tables, for now just leave them empty. Virtual Mail Directory All mail for our virtual users will be stored in the following format:
/home/vmail
- domain.tld -- user1 -- user2 --- Maildir - domain2.tld Seems simple enough, right? Go ahead and create only the top-most directory (/home/vmail) and set it's owner and group to vmail. For security reasons, chmod it 700.
$ mkdir /home/vmail
$ chown vmail.vmail /home/vmail $ chmod 700 /home/vmail Next we move onto configuration. Configuring Installed Packages
The majority of this was found in Martin List-Petersen's document. Postfix Most configuration will be done to Postfix. Open up /etc/postfix/master.cf and change the following:
flags=DRhu user=vmail argv=/usr/local/bin/maildrop -d ${recipient}
To:
flags=R user=vmail argv=/usr/local/courier/bin/maildrop -d ${recipient}
CRITICAL NOTE: Be sure that the two leading spaces on those lines remain present. Now open up /etc/postfix/main.cf and configure the following:
myhostname = mail.example.com
mydomain = example.com myorigin = $mydomain mydestination = example.com, $transport_maps local_recipient_maps = $alias_maps $virtual_mailbox_maps unix:passwd.byname home_mailbox = Maildir/ # Add the following to the bottom smtpd_sasl_auth_enable = yessmtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = $myhostname broken_sasl_auth_clients = yes smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, check_recipient_access mysql:/etc/postfix/mysql-recipient.cf, reject_unauth_destination, permit smtpd_sender_restrictions = check_sender_access mysql:/etc/postfix/mysql-sender.cf smtpd_client_restrictions = check_client_access mysql:/etc/postfix/mysql-client.cf alias_maps = mysql:/etc/postfix/mysql-aliases.cf relocated_maps = mysql:/etc/postfix/mysql-relocated.cf transport_maps = mysql:/etc/postfix/mysql-transport.cf virtual_maps = mysql:/etc/postfix/mysql-virtual.cf virtual_mailbox_base = /home/vmail virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-maps.cf virtual_uid_maps = mysql:/etc/postfix/mysql-virtual-uid.cf virtual_gid_maps = mysql:/etc/postfix/mysql-virtual-gid.cf Once again, the following is borrowed from Martin List-Petersen's document. To conserve time writing this document, I will paste the contents of the required files that allow Postfix to communicate with MySQL.
# mysql-aliases.cf
user = mysql-postfix-user password = mysql-postfix-pass dbname = mail table = postfix_alias select_field = destination where_field = alias hosts = 127.0.0.1 # mysql-relocated.cf user = mysql-postfix-user password = mysql-postfix-pass dbname = mail table = postfix_relocated select_field = destination where_field = email hosts = 127.0.0.1 # mysql-transport.cf user = mysql-postfix-user password = mysql-postfix-pass dbname = mail table = postfix_transport select_field = destination where_field = domain hosts = 127.0.0.1 # mysql-virtual.cf user = mysql-postfix-user password = mysql-postfix-pass dbname = mail table = postfix_virtual select_field = destination where_field = email hosts = 127.0.0.1 # mysql-recipient.cf user = mysql-postfix-user password = mysql-postfix-pass dbname = mail table = postfix_access select_field = access where_field = source additional_conditions = and type = 'recipient' hosts = 127.0.0.1 # mysql-sender.cf user = mysql-postfix-user password = mysql-postfix-pass dbname = mail table = postfix_access select_field = access where_field = source additional_conditions = and type = 'sender' hosts = 127.0.0.1 # mysql-client.cf user = mysql-postfix-user password = mysql-postfix-pass dbname = mail table = postfix_access select_field = access where_field = source additional_conditions = and type = 'client' hosts = 127.0.0.1 # mysql-virtual-maps.cf Of course you will have to substitue the username and password for the one you created earlier. Courier IMAP Open /usr/local/courier/etc/authdaemonrc (if it doesn't exist, make a copy from authdaemonrc.dist located in the same directory). Change the line that starts with "authmodulelist" to read:
authmodulelist="authmysql authpam"
Next create a file called authmysqlrc (in the same directory) and put the following in:
MYSQL_USERNAME USRENAME
MYSQL_PASSWORD PASSWORD MYSQL_PORT 0 MYSQL_OPT 0 MYSQL_DATABASE mail MYSQL_USER_TABLE postfix_users MYSQL_LOGIN_FIELD email MYSQL_CRYPT_PWFIELD crypt MYSQL_CLEAR_PWFIELD clear MYSQL_UID_FIELD uid MYSQL_GID_FIELD gid MYSQL_HOME_FIELD homedir MYSQL_MAILDIR_FIELD maildir MYSQL_WHERE_CLAUSE access='y' Open imapd and make sure the following lines looks like this: # This is all on one line # Seperate line Open imapd-ssl and make sure the following line looks like this: IMAPDSSLSTART=YES
Courier Maildrop While we're still in /usr/local/courier/etc edit or create a file called maildropmysql.config and put in the following:
hostname localhost
port 3306 database mail dbuser USERNAME dbpw PASSWORD dbtable postfix_users default_uidnumber 1004 default_gidnumber 1004 uid_field email uidnumber_field uid gidnumber_field gid maildir_field maildir homedirectory_field homedir quota_field quota # unused for now, but needs to be a valid field. mailstatus_field postfix where_clause AND postfix = 'y' Now we need to setup Maildrop to deliver our mail. Create (or edit) /etc/maildroprc and put in the following: NOTE: Take care in bracket placement, Maildrop is very picky in this sense.
if ( $SIZE < 26144 )
{ exception { xfilter "/usr/bin/spamassassin" } } if (/^X-Spam-Flag: *YES/) { exception { to "$HOME/$DEFAULT/.Spam/" } } else { exception { to "$HOME/$DEFAULT" } } Cyrus SASL Since Cyrus will be doing some authenticating, we need to configure it as well. Create the file smptd.conf in /usr/local/lib/sasl2 and put in the following:
sasl_pwcheck_method: auxprop
sasl_auxprop_plugin: mysql login plain crammd6 digestmd5 mysql_user: USERNAME mysql_passwd: PASSWORD mysql_hostnames: localhost mysql_database: mail mysql_statement: SELECT clear FROM postfix_users WHERE email = '%u@%r' mysql_verbose: yes Finalizing
Adding a user You are now ready to add a test user to the database, start the mailserver and test the whole system out. Populate the postfix_transport table with the following:
domain: "test.com"
destination: "maildrop:" The domain field needs no explination, however, the destination field does. In the destination field Postfix is told what program the message should be carried to. For instance, if you wanted delivery to be handled by Postfix's internal system, you would put "virtual:" In our example however, we are using maildrop, so we put "maildrop:" Next add a test user by populating the postfix_users table.
email: "test@test.com"
clear: "mypassword" homedir: "/home/vmail" maildir: "test.com/test/Maildir/" That's all there is to adding a new user. The "email" field stores just that, the user's email (it must include the TLD). The "clear" field stores the user's password in clear text. "Homedir" contains the root directory for all virtual mail, if we were using "local:" delivery, this would be set to the user's home directory. Finally, "maildir" is the Maildir location relative to the homedir. Starting the Daemons Open up your system log (/var/log/messages or /var/log/maillog) and monitor it as you start your daemons:
$ /usr/local/courier/libexec/authlib/authdaemond start
$ /usr/local/courier/sbin/imapd start $ /usr/local/courier/sbin/imapd-ssl start $ /usr/sbin/postfix start If everything went right, the daemons should start without any failures. nmap yourself and see what ports are open, there should be three (smtp, imap and imap-ssl) Testing the SMTP and IMAP Servers Everything not starting with a ">" or "$" is a response from the server.
$ telnet localhost 25
Trying 127.0.0.1... Connected to localhost. Escape character is '^]'. 220 mail.test.com ESMTP Postfix > EHLO test.com 250-mail.test.com 250-PIPELINING 250-SIZE 10240000 250-VRFY 250-ETRN 250-AUTH LOGIN PLAIN 250-AUTH=LOGIN PLAIN 250-XVERP 250 8BITMIME If you see something like that, congratulations, you're still in good shape!
> MAIL FROM: test@test.com
250 Ok > RCPT TO: test@test.com 250 Ok > DATA 354 End data with <CR><LF>.<CR><LF> > . 250 Ok: queued as 6CE4223727 Now, if everything is setup right, the mailserver should queue your message. Check inside of /home/vmail/test.com/test/Maildir/new for anything, if you see a file, congratulations, the message was delivered! When using a mail client (such as Outlook or Mozilla), be sure to use the full email address for the username (ie: "user@domain.com", not just "user"). |