| Home Profile Fun |
#149 Linux 07.01.2008
How to set up a Postfix mail server with MySQL backend on GentooThis tutorial explains the basic setup of a Postfix mail server with the following services: Port 995: POP3S (TLS protocol: SSLv3) with Clear text, LOGIN, PLAIN and CRAM-MD5 Port 993: IMAPS (TLS protocol: SSLv3) with Clear text, LOGIN, PLAIN and CRAM-MD5 Port 025: SMTPS (TLS protocol: TLSv1) with CRAM-MD5 und DIGEST-MD5 In all cases the authentication data and the actual mail traffic is encrypted, no matter which mechanism is used. All authentication data is stored in a MySQL database. No system accounts are needed. Nevertheless each mail account has its own UID/GID in the filesystem. Currently Cyrus SASL can handle plain text passwords only in the MySQL backend. There is a patch available but I haven't tested it yet. Here is a diagram that illustrates the authentication procedure: POP3S / IMAPS: Mail client -> Courier-IMAP -> Courier-authlib(authdaemond) -> MySQL (Mapping with MySQL tables is done in /etc/courier/authlib/authmysqlrc) SMTPS: Mail client -> Postfix -> Cyrus SASL(auxprop plugin) -> MySQL (Mapping with MySQL tables is done in /etc/sasl2/smptd.conf) (Cyrus SASL is run by Postfix, it has no separate daemon) Emails are written in Qmail style to /var/mail/vdomains/DOMAIN/USER. We will create our own certificate authority (CA) for the test certificates. 1. Postfix,MySQL,syslog-ng: basic setup 2. Courier-IMAP 3. MySQL 4. Postfix 5. Cyrus SASL 6. Courier-authlib 7. SSL certificate for Postfix 8. Configure Postfix to use TLS and Cyrus SASL 9. Virtual mail hosting 10. Final configuration 11. Clean-up 1. Postfix, MySQL, syslog-ng: basic setup We start with a fresh Gentoo system. emerge -uav world Test that all security updates are installed: glsa-check -l affected Then make sure no other MTA is installed like ssmtp, exim or qmail. Install MySQL, Cyrus SASL and Postfix USE="berkdb perl ssl" emerge -va mysql USE="berkdb crypt gdbm mysql pam ssl" emerge -va cyrus-sasl USE="mysql pam sasl ssl -ipv6" emerge -va postfix It is important that the command "hostname" prints the correct hostname. In this tutorial we use "postfix". The FQDN name of this system is postfix.test.acodedb.com. If the hostname is not correct you can change it in "/etc/conf.d/hostname" and activate the changes with /etc/init.d/hostname restart Make sure that the FQDN resolves to the IP Postfix should bind to. If the DNS record is not yet configured you can add a record in /etc/hosts for the testing period. vi /etc/hosts [IP] postfix.test.acodedb.com postfix Now, as Postfix is installed we do the basic setup. The main configuration file of postfix is /etc/postfix/main.cf. Add the following lines at the end of the file and adapt the values according to your system: myorigin=$myhostname myhostname = postfix.test.acodedb.com mydomain = test.acodedb.com inet_interfaces = $myhostname mydestination = $myhostname, localhost.$mydomain, localhost mynetworks = 127.0.0.0/8, 192.168.1.0/24 home_mailbox = Maildir/ local_destination_concurrency_limit = 2 default_destination_concurrency_limit = 10 Now we have to set the root alias. This is necessary because Postfix wants to know the target account for mails for the user root. This has a security background, set it to a local nonroot account: vi /etc/mail/aliases # Well-known aliases -- these should be filled in! root: test1 # operator: So that Postfix has fast access to the alias data we create the aliase database newaliases Postfix is logging to /var/log/messages per default. For a better overview I want it to log into a seperate log file: /var/log/mail.log. Therefore we must configure syslog-ng so that it writes Postfix logs solely to this file and keeps /var/log/messages free from Postfix entries. Additionally I want the authdaemond to log into /var/log/authdaemond.log: vi /etc/syslog-ng/syslog-ng.conf:
options {
chain_hostnames(off);
sync(0);
stats(43200);
};
source src {
unix-stream("/dev/log" max-connections(256));
internal();
};
# direct postfix logs to /var/log/mail.log
destination postfix { file("/var/log/mail.log"); };
filter postfix { match("^postfix"); };
log { source(src); filter(postfix); destination(postfix); };
destination messages { file("/var/log/messages"); };
filter nopostfix { not match("^postfix"); };
# direct authdaemond logs to /var/log/authdaemond.log
destination authdaemond { file("/var/log/authdaemond.log"); };
filter authdaemond { match("^authdaemond"); };
log { source(src); filter(authdaemond); destination(authdaemond); };
filter noauthdaemond { not match("^authdaemond"); };
# By default messages are logged to tty12...
destination console_all { file("/dev/tty12"); };
log { source(src); filter(nopostfix); filter(noauthdaemond); destination(messages); };
log { source(src); destination(console_all); };
The file master.cf contains the configuration of the master processes of Postfix. To get debug output for SMTP we add -v to the smpt line: vi /etc/postfix/master.cf: smtp inet n - n - - smtpd -v Restart both services # /etc/init.d/syslog-ng restart # /etc/init.d/postfix restart It's a good idea to test everything that has been set up so far. Just send a mail locally to a local account. Make also sure that logging data is written to /var/log/mail.log (If the mail command is not available emerge -va mail-client/mailx) # cd /home/test1 # chmod o+w . # mail root@test.acodedb.com Subject: test1 test1 . Cc: # chmod o-w . The next test is to use telnet from another system and send a mail to a local account. And also make sure that you can send to external addresses. Here you see the telnet session for the local account (root@postfix.test.acodedb.com). # telnet postfix.test.acodedb.com 25 Trying 78.47.177.74... Connected to postfix.test.acodedb.com. Escape character is '^]'. 220 postfix.test.acodedb.com ESMTP Postfix helo client.homenet 250 postfix.test.acodedb.com mail from: <test@homenet> 250 2.1.0 Ok rcpt to: <root@postfix.test.acodedb.com> 250 2.1.5 Ok data 354 End data with <CR><LF>.<CR><LF> This is a testmail from home. . 250 2.0.0 Ok: queued as BD162A0294 quit 221 2.0.0 Bye Connection closed by foreign host. # Because of the root alias the mail must be delivered to /home/test1/Maildir/new/. You can "cat" the message an verify that it is the one you have just sent. To make sure that we have not created an open relay which can be used by everyone to send mail/spam it is important to test wether you can send a mail via telnet to an external account without authentication. The server must respond with "Relay access denied" if you run telnet from a host which is not part of the networks defined with mynetworks in /etc/postfix/main.cf. # telnet postfix.test.acodedb.com 25 Trying 78.47.177.74... Connected to postfix.test.acodedb.com. Escape character is '^]'. 220 postfix.test.acodedb.com ESMTP Postfix helo client.homenet 250 postfix.test.acodedb.com mail from: <test@homenet> 250 2.1.0 Ok rcpt to: <remoteaccount@somewhere.xyz> 554 5.7.1 <remoteaccount@somewhere.xyz>: Relay access denied quit 221 2.0.0 Bye Connection closed by foreign host. # If everything works, great! If not, verify every single step and make sure you have adapted it to your scenario. The last operation of this step is to add the daemons to the default runlevel. rc-update add postfix default rc-update add mysql default rc-update add syslog-ng default 2. Courier-IMAP The Courier-IMAP package allows mail clients access to their mailboxes via IMAP(S) and POP3(S). To make it secure so that the authentication data and the actual mail traffic is encrypted we use SSLv3 for transport layer security (TLS). For SSL a SSL certificate is needed. In this tutorial we create only a self-signed certificate for testing. Later it makes sense to use a certificate which is signed by an official certificate authority (CA). emerge -va courier-imap courier-authlib The short way to create self signed test certificates for Courier-IMAP is to use its build-in programs, mkpop3dcert and mkimapdcert. Just fill out two configuration files: cd /etc/courier-imap vi ./pop3d.cnf RANDFILE = /usr/share/pop3d.rand [ req ] default_bits = 1024 encrypt_key = yes distinguished_name = req_dn x509_extensions = cert_type prompt = no [ req_dn ] C=DE ST=HESSEN L=WIESBADEN O=Courier Mail Server OU=Automatically-generated POP3 SSL key CN=postfix.test.acodedb.com emailAddress=postmaster@test.acodedb.com [ cert_type ] nsCertType = server vi ./imapd.cnf RANDFILE = /usr/share/imapd.rand [ req ] default_bits = 1024 encrypt_key = yes distinguished_name = req_dn x509_extensions = cert_type prompt = no [ req_dn ] C=DE ST=HESSEN L=WIESBADEN O=Courier Mail Server OU=Automatically-generated IMAP SSL key CN=postfix.test.acodedb.com emailAddress=postmaster@postfix.test.acodedb.com [ cert_type ] nsCertType = server Run these programs to create the certificates: # mkpop3dcert # mkimapdcert Two files have been created which contain both the certificates and the private keys. pop3d.pem imapd.pem In case you want to do things manually here are some instructions. The following steps are just a dirty way to generate test certificates! A complete and secure setup of CAs and certificates is beyond the scope of this article. The first step is to create your own certificate authority (CA): # cd /root # /etc/ssl/misc/CA.sh -newca ... Some explanations here. The first password "Enter PEM pass phrase:" is the password for the CA itself. Then all the information which should appear in the certificate must be entered like country etc. The field "Common Name (eg, YOUR name) []:" must contain the FQDN of your mail server: "postfix.test.acodedb.com". I leave the following fields empty "A challenge password []:" and "An optional company name []:". Now the certificate for the certificate authority is issued: ./demoCA/cacert.pem. This certificate authority is not officially known. So for the testing its certificate should be imported into the local mail client. If this certificate is signed by an official authority this last step is not necessary of course, The next step is to generate the actual certificate for the mail server: # openssl req -new -nodes -keyout imapd_privatekey.pem -out imapd_req.pem -days 9999 ... Two files have been created, the private key and the certificate request: imapd_privatekey.pem imapd_req.pem Now we have to transform the certificate request into a certificate with our own CA: # openssl ca -policy policy_anything -out imapd_cert.pem -infiles imapd_req.pem ... The new certificate is in the new file imapd_cert.pem. For the testing phase I store all certificates in subfolders of /root: mkdir /root/certs_imapd/ mv imapd_cert.pem imapd_privatekey.pem imapd_req.pem /root/certs_imapd/ To protect the private key use chown root:root /root/certs_imapd/imapd_privatekey.pem chmod 600 /root/certs_imapd/imapd_privatekey.pem Now we check where courier-imap expects the SSL certificate by opening the SSL configuration file: vi /etc/courier-imap/imapd-ssl TLS_CERTFILE=/etc/courier-imap/imapd.pem courier-imap wants to have private key and certificate together in this file. So we go to /root/certs_imapd: cat imapd_privatekey.pem imapd_cert.pem > /etc/courier-imap/imapd.pem chown root:root /etc/courier-imap/imapd.pem chmod 600 /etc/courier-imap/imapd.pem imapd-ssl shall listen only on one IP: vi /etc/courier-imap/imapd-ssl SSLADDRESS=192.168.1.56 Finally courier-imapd with SSL support can be started: /etc/init.d/courier-imapd-ssl start To make sure we have access to the server via IMAPS(993) check the connection with telnet. # telnet postfix.test.acodedb.com 993 Trying 78.47.177.74... Connected to postfix.test.acodedb.com. Escape character is '^]'. The same has to be done for pop3d. Creating the certificate: # cd /root # openssl req -new -nodes -keyout pop3d_privatekey.pem -out pop3d_req.pem -days 9999 ... Two files have been created, the private key and the certificate request: pop3d_privatekey.pem pop3d_req.pem Again we have to transform the certificate request into a certificate with our own CA: # openssl ca -policy policy_anything -out pop3d_cert.pem -infiles pop3d_req.pem ... The new certificate is in the file pop3d_cert.pem. Like in the previous step we create a tempory directory for the certificate: mkdir /root/certs_pop3d mv pop3d_cert.pem pop3d_privatekey.pem pop3d_req.pem /root/certs_pop3d chown root:root /root/certs_pop3d/pop3d_privatekey.pem chmod 600 /root/certs_pop3d/pop3d_privatekey.pem Also courier-imap wants to have private key and certificate together in one file. So we go to /root/certs_pop3d: cat pop3d_privatekey.pem pop3d_cert.pem > /etc/courier-imap/pop3d.pem chown root:root /etc/courier-imap/pop3d.pem chmod 600 /etc/courier-imap/pop3d.pem pop3d-ssl shall listen only on one IP: vi /etc/courier-imap/pop3d-ssl SSLADDRESS=192.168.1.56 Finally courier-pop3d with SSL support can be started: /etc/init.d/courier-pop3d-ssl start To make sure we have access to the server via POP3S(995) check the connection with telnet. # telnet postfix.test.acodedb.com 995 Trying 78.47.177.74... Connected to postfix.test.acodedb.com. Escape character is '^]'. So far we have configured and running: Postfix (MTA) Syslog-ng (system logging daemon) Courier-IMAP (courier-imap-ssl, courier-pop3d-ssl) Summary and overview: Postfix: responsible for sending and receiving emails. Courier-IMAP: responsible for the access to mailboxes via POP3S and IMAPS. Courier-authlib: authentication backend for Courier-IMAP (not yet configured) The relevant process list at this point should look like this: USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND ... root 6545 0.0 0.1 40520 2348 ? Ss Nov26 0:00 /usr/lib/postfix/master postfix 6551 0.0 0.1 40620 2420 ? S Nov26 0:00 qmgr -l -t fifo -u root 8243 0.0 0.0 12476 724 ? Ss Nov27 0:00 /usr/sbin/syslog-ng root 31044 0.0 0.0 3704 424 ? S Nov27 0:00 /usr/sbin/courierlogger -pid=/var/run/authdaemon.pid -start /usr/lib/courier root 31045 0.0 0.0 28540 1660 ? S Nov27 0:00 /usr/lib/courier/courier-authlib/authdaemond root 31046 0.0 0.0 28540 552 ? S Nov27 0:00 /usr/lib/courier/courier-authlib/authdaemond root 31047 0.0 0.0 28540 552 ? S Nov27 0:00 /usr/lib/courier/courier-authlib/authdaemond root 31048 0.0 0.0 28540 552 ? S Nov27 0:00 /usr/lib/courier/courier-authlib/authdaemond root 31049 0.0 0.0 28540 552 ? S Nov27 0:00 /usr/lib/courier/courier-authlib/authdaemond root 31050 0.0 0.0 28540 552 ? S Nov27 0:00 /usr/lib/courier/courier-authlib/authdaemond root 13203 0.0 0.0 6876 552 ? S 04:53 0:00 /usr/lib64/courier-imap/couriertcpd -address=0 -stderrlogger=/usr/lib64/cour root 13205 0.0 0.0 3576 380 ? S 04:53 0:00 /usr/lib64/courier-imap/courierlogger imapd-ssl root 13307 0.0 0.0 6880 568 ? S 04:54 0:00 /usr/lib64/courier-imap/couriertcpd -address=0 -stderrlogger=/usr/lib64/cour root 13309 0.0 0.0 3708 520 ? S 04:54 0:00 /usr/lib64/courier-imap/courierlogger pop3d-ssl postfix 13930 0.0 0.1 40568 2324 ? S 05:16 0:00 pickup -l -t fifo -u ... Note that the command lines are not displayed in their full lenght due to the limited screen size. You can view the full command line bei using the proc pseudo filesystem and the PID: # cat /proc/13203/cmdline /usr/lib64/courier-imap/couriertcpd-address=0-stderrlogger=/usr/lib64/courier-imap/courierlogger-stderrloggername=imapd-ssl-maxprocs= 40-maxperip=4-pid=/var/run/imapd-ssl.pid-nodnslookup-noidentlookup993/usr/sbin/couriertls-server-tcpd/usr/sbin/imaplogin/usr/lib64/ courier-imap/courier-imapd.indirect.maildir 3. MySQL The MySQL server is used as the authentication backend for courier-authlib and Cyrus sasl(auxprop plugin). There will be only one single database which is used for authentication by both services. I want to put as much configuration and authentication data as possible into MySQL so that everything can be configured via PHPmyadmin. Let's create the database and tables for that. Database: mysql> CREATE DATABASE mailserver; mysql> USE mailserver; Virtual domains: mysql> CREATE TABLE virtualdomains ( id int unsigned NOT NULL auto_increment, domain varchar(255) default NULL, PRIMARY KEY (id), FULLTEXT KEY `indexdomain` (domain)) ENGINE=MyISAM; Virtual users: mysql> CREATE TABLE virtualusers ( id int unsigned NOT NULL auto_increment, name varchar(255) NOT NULL default '-', realm varchar(255) NOT NULL default 'test.acodedb.com', userpassword varchar(255) NOT NULL default 'CHANGETHIS', email varchar(255) NOT NULL default '-', auth tinyint(1) default 1, enabled tinyint(1) default 1, uid int default 9000, gid int default 9000, mbox varchar(255) default NULL, home varchar(255) default '/var/mail/vdomains/', PRIMARY KEY (id), FULLTEXT KEY `indexemail` (email)) ENGINE=MyISAM; Virtual aliases: mysql> CREATE TABLE virtualaliases ( id int unsigned NOT NULL auto_increment, alias varchar(255) default NULL, email varchar(255) default '-', PRIMARY KEY (id), FULLTEXT KEY `indexalias` (alias)) ENGINE=MyISAM; Create a read-only user for the mail system to access these tables. (USAGE means "no privileges") GRANT USAGE ON *.* TO 'mailserver'@'localhost' IDENTIFIED BY 'CHANGETHIS'; GRANT SELECT ON mailserver.virtualdomains TO 'mailserver'@'localhost'; GRANT SELECT ON mailserver.virtualusers TO 'mailserver'@'localhost'; GRANT SELECT ON mailserver.virtualaliases TO 'mailserver'@'localhost'; Create a virtual test domain, a test user and a test alias. mysql> INSERT INTO virtualdomains VALUES (1,'test.acodedb.com'); INSERT INTO virtualusers VALUES (1,'test1','test.acodedb.com', 'CHANGETHIS','test1@test.acodedb.com',1,1,9001,9001, 'test.acodedb.com/test1/','/var/mail/vdomains/'); INSERT INTO virtualaliases VALUES (1,'aliastest1@test.acodedb.com','test1@test.acodedb.com'); mysql> select * from virtualusers where id=1 \G
*************************** 1. row ***************************
id: 1
name: test1
realm: test.acodedb.com
userpassword: CHANGETHIS
email: test1@test.acodedb.com
auth: 1
enabled: 1
uid: 9001
gid: 9001
mbox: test.acodedb.com/test1/
home: /var/mail/vdomains/
1 row in set (0.01 sec)
Remember to use plain text passwords in the MySQL database. 4. Postfix We must tell Postfix that it has to look in the MySQL database for the user authentication data. For that we create a file for each map. # mkdir /etc/postfix/maps # chown postfix:root /etc/postfix/maps # chmod 500 /etc/postfix/maps # cd /etc/postfix/maps # vi virtualdomains.cf user=mailserver password=CHANGETHIS hosts=localhost dbname=mailserver table=virtualdomains query=SELECT domain FROM virtualdomains WHERE domain like '%s' # vi virtualuids.cf user=mailserver password=CHANGETHIS hosts=localhost dbname=mailserver table=virtualusers query=SELECT uid FROM virtualusers WHERE email like '%s' AND enabled like '1' # vi virtualgids.cf user=mailserver password=CHANGETHIS hosts=localhost dbname=mailserver table=virtualusers query=SELECT gid FROM virtualusers WHERE email like '%s' AND enabled like '1' # vi virtualaliases.cf user=mailserver password=CHANGETHIS hosts=localhost dbname=mailserver table=virtualaliases query=SELECT email FROM virtualaliases WHERE alias like '%s' # vi virtualrecipients.cf user=mailserver password=CHANGETHIS hosts=localhost dbname=mailserver table=virtualusers query=SELECT mbox FROM virtualusers WHERE email like '%s' AND enabled like '1' Protect the files: # chmod 640 /etc/postfix/maps/* # chown root:postfix /etc/postfix/maps/* The permissions should look like this. # cd /etc/postfix/maps/ # ls -lha total 28K dr-x------ 2 postfix root 4.0K Dec 6 11:07 . drwxr-xr-x 4 root root 4.0K Dec 14 10:33 .. -rw-r----- 1 root postfix 155 Dec 5 11:03 virtualaliases.cf -rw-r----- 1 root postfix 157 Dec 1 10:18 virtualdomains.cf -rw-r----- 1 root postfix 170 Dec 1 10:19 virtualgids.cf -rw-r----- 1 root postfix 171 Dec 1 10:22 virtualrecipients.cf -rw-r----- 1 root postfix 170 Dec 1 10:17 virtualuids.cf Set the following parameters in /etc/postfix/main.cf to tell Postfix how to access the maps virtual_mailbox_domains=mysql:/etc/postfix/maps/virtualdomains.cf virtual_mailbox_maps=mysql:/etc/postfix/maps/virtualrecipients.cf virtual_uid_maps=mysql:/etc/postfix/maps/virtualuids.cf virtual_gid_maps=mysql:/etc/postfix/maps/virtualgids.cf virtual_alias_maps=mysql:/etc/postfix/maps/virtualaliases.cf virtual_mailbox_base=/var/mail/vdomains Now test if Postfix can access the data in MySQL. # postmap -q "test.acodedb.com" mysql:/etc/postfix/maps/virtualdomains.cf test.acodedb.com # postmap -q "test1@test.acodedb.com" mysql:/etc/postfix/maps/virtualuids.cf 9001 # postmap -q "test1@test.acodedb.com" mysql:/etc/postfix/maps/virtualgids.cf 9001 # postmap -q "test1@test.acodedb.com" mysql:/etc/postfix/maps/virtualrecipients.cf test.acodedb.com/test1/ 5. Cyrus SASL Until now we have nothing running that realises authentication for SMTPS connections (SMTP AUTH). Courier-IMAP does this for IMAPS and POP3S access only. For SMTPS we will use the authentication framework Cyrus SASL and offer the following mechanisms: CRAM-MD5, DIGEST-MD5. The auxprop plugin is used as the password verification service to communicate with MySQL. The communication with the client will be encrypted with transport layer security (TLSv1). Cyrus SASL will use the same structure in MySQL we have already created, no need to store redundant data. Install Cyrus SASL. emerge -va cyrus-sasl As mentioned before Cyrus SASL does not run as a daemon. It is just used by Postfix. Therefore we have to tell the smtpd daemon from Postfix how to access MySQL via Cyrus SASL. Postfix looks up this information in the Cyrus SASL configuration file which has the name of the corresponding Postfix daemon: vi /etc/sasl2/smtpd.conf Remove all existing records and copy/paste the following: pwcheck_method: auxprop mech_list: CRAM-MD5 DIGEST-MD5 log_level: 3 # auxprop parameters for database access auxprop_plugin: sql sql_engine: mysql sql_hostnames: localhost sql_database: mailserver sql_user: mailserver sql_passwd: CHANGETHIS sql_select: select %p from virtualusers where name like '%u' and realm like '%r' and auth = '1' sql_usessl: no 6. Courier-authlib Courier-authlib is the IMAPS/POP3S counterpart for Cyrus SASL(auxprop plugin). First tell Courier-authlib to use the MySQL module for authentication. vi /etc/courier/authlib/authdaemonrc authmodulelist="authmysql " DEBUG_LOGIN=1 Then configure the module itself. The first part is the login data for the MySQL server so that Courier-authlib has access to the database. The second part tells Courier-authlib the database name and table names where it finds the authentication data of the email accounts. The third part contains the relevant table columns. vi /etc/courier/authlib/authmysqlrc MYSQL_SERVER localhost MYSQL_USERNAME mailserver MYSQL_PASSWORD CHANGETHIS MYSQL_PORT 0 MYSQL_OPT 0 MYSQL_DATABASE mailserver MYSQL_USER_TABLE virtualusers MYSQL_CLEAR_PWFIELD userpassword MYSQL_UID_FIELD uid MYSQL_GID_FIELD gid MYSQL_LOGIN_FIELD email MYSQL_HOME_FIELD home MYSQL_NAME_FIELD name MYSQL_MAILDIR_FIELD mbox 7. SSL certificate for Postfix Up to this point we have certificates for the CA and Courier-IMAP but still not for Postfix. The procedure ist the same as for the previous certificates. First, let's create the private key and certificate request. # cd /root # openssl req -new -nodes -keyout postfix_privatekey.pem -out postfix_req.pem -days 9999 ... We get the files postfix_privatekey.pem and postfix_req.pem. Now our own CA is used again to create the certificate from the certificate request: # openssl ca -policy policy_anything -out postfix_cert.pem -infiles postfix_req.pem ... The result is postfix_cert.pem To have all relevant files together create another new directory: mkdir /root/certs_postfix mv postfix_cert.pem postfix_privatekey.pem postfix_req.pem /root/certs_postfix chown root:root /root/certs_postfix/postfix_privatekey.pem chmod 600 /root/certs_postfix/postfix_privatekey.pem The next step is to make the certificate for Postfix and the certificate for our CA available for Postfix: mkdir /etc/postfix/certs cp /root/certs_postfix/postfix_privatekey.pem /etc/postfix/certs cp /root/certs_postfix/postfix_cert.pem /etc/postfix/certs cp /root/demoCA/cacert.pem /etc/postfix/certs chown root:root /etc/postfix/certs/postfix_privatekey.pem chmod 600 /etc/postfix/certs/postfix_privatekey.pem 8. Configure Postfix to use TLS and Cyrus SASL The use of TLS and Cyrus SASL is configured in the main Postfix configuration file: vi /etc/postfix/main.cf Add the following lines at the end of the file: # local accounts alias_maps = hash:/etc/mail/aliases smtpd_sasl_auth_enable = yes smtpd_sasl2_auth_enable = yes smtpd_sasl_security_options = noanonymous, noplaintext smtpd_sasl_tls_security_options = noanonymous, noplaintext broken_sasl_auth_clients = yes smtpd_sasl_local_domain = $myhostname # must be left without value smtpd_sasl_local_domain = smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination smtp_use_tls = yes smtp_tls_note_starttls_offer = yes smtpd_tls_security_level = may smtpd_tls_auth_only = yes smtpd_tls_key_file = /etc/postfix/certs/postfix_privatekey.pem smtpd_tls_cert_file = /etc/postfix/certs/postfix_cert.pem smtpd_tls_CAfile = /etc/postfix/certs/cacert.pem smtpd_tls_loglevel = 3 smtpd_tls_received_header = yes smtpd_tls_session_cache_timeout = 3600s tls_random_source = dev:/dev/random At this point we have finished the configuration of the basic components of our mail system. # /etc/init.d/postfix restart # /etc/init.d/courier-authlib restart 9. Virtual mail hosting So far Postfix can handle only one domain. Postfix must be configured for virtual domains which means that email accounts for several domains can be hosted. The first step is to define a directory which will contain all emails of all domains. # cd /var/mail # mkdir vdomains # chmod 755 vdomains/ The Postfix virtual daemon will write into this directory with different UID and GID for each email account. The users don't need a system account. All information is stored in the MySQL database. For each new virtual account the user data must be stored in MySQL and a directory structure must be created. The data for test1@test.acodedb.com is already stored in MySQL. So here we just create the structure in the filesystem: cd /var/mail/vdomains mkdir test.acodedb.com chgrp mail test.acodedb.com/ chmod g+w test.acodedb.com/ cd test.acodedb.com/ mkdir test1 chown 9001:9001 test1/ chmod 700 test1/ cd test1/ mkdir cur new tmp chmod 700 * chown 9001:9001 * The result should look like this: # cd /var/mail/vdomains
postfix vdomains # ls -lha
total 16K
drwxrwxr-x 4 root mail 4.0K Dec 8 14:20 .
drwxrwxr-x 3 root mail 4.0K Dec 5 11:11 ..
drwxrwxr-x 7 root mail 4.0K Dec 10 10:59 test.acodedb.com
# tree -Apug -L 4
.
??? [drwxrwxr-x root mail ] test.acodedb.com
??? [drwx------ 9001 9001 ] test1
??? [drwx------ 9001 9001 ] cur
??? [drwx------ 9001 9001 ] new
??? [drwx------ 9001 9001 ] tmp
10. Final configuration We are almost done. To enable LOGIN and CRAM-MD5 for imap-ssl a line in /etc/courier-imap/imapd must be changed (yes it's /etc/courier-imap/imapd not /etc/courier-imap/imapd-ssl): IMAP_CAPABILITY="IMAP4rev1 UIDPLUS CHILDREN NAMESPACE THREAD=ORDEREDSUBJECT THREAD=REFERENCES SORT QUOTA AUTH=LOGIN AUTH=CRAM-MD5 IDLE" pop3-ssl has CRAM-MD5 activated per default. To configure it according to our plan I remove the CRAM-SHA mechanisms: vi /etc/courier-imap/pop3d POP3AUTH_ORIG="PLAIN LOGIN CRAM-MD5" If you have configured /etc/sasl2/smtpd.conf as described before no plain mechanisms are available via SMTPS. Actually this is not necessary because Postfix is also configured to not offer plain mechanisms for SMTPS in /etc/postfix/main.cf. Just to be on the safe side. # /etc/init.d/courier-authlib restart Now, I assume there are no problems and we can switch to production mode. Therefore we reduce the debug level for all involved services: vi /etc/postfix/main.cf smtpd_tls_loglevel = 0 vi /etc/sasl2/smtpd.conf log_level: 1 vi /etc/courier/authlib/authdaemonrc DEBUG_LOGIN=0 vi /etc/postfix/master.cf smtp inet n - n - - smtpd To make sure all involved services come up after a reboot we add them to the default runlevel: # rc-update add syslog-ng default # rc-update add vixie-cron default # rc-update add mysql default # rc-update add postfix default # rc-udpate add courier-authlib default # rc-update add courier-pop3d-ssl default # rc-update add courier-imapd-ssl default Disable all unwanted services: cd /etc/init.d/ mv saslauthd saslauthd_OFF mv courier-pop3d courier-pop3d_OFF mv courier-imapd courier-imapd_OFF 11. Clean-up Finally we remove the temporary folders for the certificates: rm -r /root/certs_imapd rm -r /root/certs_pop3d The setup is complete. All necessary services are installed and configured. # netstat -tulpen Active Internet connections (only servers) Proto Recv-Q Send-Q Local Address Foreign Address State User Inode PID/Program name tcp 0 0 192.168.1.56:993 0.0.0.0:* LISTEN 0 11497695 6952/couriertcpd tcp 0 0 192.168.1.56:995 0.0.0.0:* LISTEN 0 11497819 7063/couriertcpd tcp 0 0 192.168.1.56:3306 0.0.0.0:* LISTEN 60 2743167 9666/mysqld tcp 0 0 192.168.1.56:22 0.0.0.0:* LISTEN 0 6551044 29456/sshd tcp 0 0 192.168.1.56:25 0.0.0.0:* LISTEN 0 11497211 6600/master In case of problems increase the log levels and look in the following files: /var/log/messages /var/log/mail.log /var/log/authdaemond.log |