Virtual mail server using Postfix, Courier and PostfixAdmin

From Gentoo Linux Wiki
Jump to: navigation, search
Please format this article according to the Style Guidelines and Wikification suggestions, then remove this notice {{Wikify}} from the article.

Reason(s): This article is a port from the old wiki, located here: http://www.gentoo-wiki.info/HOWTO_Setup_a_Virtual_Postfix/Courier_Mail_System_with_PostfixAdmin, please fix any errors and remove this

Contents

[edit] Introduction

I recently moved my original mail system, built using the Gentoo Virtual How-to, over to a PostfixAdmin run system. Additionally I took this time to add Postgrey and switch to encrypted passwords using Courier's new authlib, which I'll detail as well.

Virtual Mailhosting System with Postfix Guide

[edit] Notes From the Author

kashani (2007.04.17): I just ran through this how-to on my new vps server so it's pretty fresh. Should be updating this over the next week.

kashani (2008.06.25): A few updates, but I haven't really looked to hard at what is new in Postfixadmin 2.2

kashani (2008.08.21): Added syslog-ng stuff to split mail out, added mysql account creation stuff a couple of weeks ago.

[edit] Notes From Users

Put things you'd like me to fix or comments here

Bigun - Possibly some code on how to setup courier-imapd-ssl and courier-pop3d-ssl, certificates and all

[edit] Why PostfixAdmin

PostfixAdmin provides a nice front-end for a Postfix/Courier based virtual mail server. As super-admin you can create domain admins, create their domains, own the domains to the domain admin, and then you can go back to reading the Gentoo forums rather than creating users, changing passwords, or deleting accounts.

(...and managing your email system with PHPMyadmin sucks.)

[edit] Which Packages

This HowTo assumes you have the following prerequisites:

[edit] Default Settings

The system we're going to build will have the settings below. You can change any of these to reflect your own system.

  • All mail is in /var/vmail/
  • All mail is owned by user postfix:postfix
  • The database is postfix_db
  • The database user is named postfix_user
  • The database password is “postfix_pass” — you should change this to something different, use the app-admin/pwgen utility to generate a good password

[edit] Portage

These are the Use flags that should be set.

File: /etc/portage/package.use
dev-db/mysql                community perl ssl
dev-lang/php                apache2 bzip2 crypt ctype curl filter ftp gd gdbm imap json mysql mysqli nls pcre pic posix reflection session spl ssl unicode xml xsl zlib
dev-libs/cyrus-sasl         -berkdb authdaemond crypt gdbm mysql ssl urandom
mail-mta/postfix            mysql ssl sasl vda
net-mail/courier-imap       fam gdbm nls
net-libs/courier-authlib    crypt gdbm mysql
www-apps/postfixadmin       mysql vhosts
www-servers/apache          ssl

If any of them are in your USE variable in the /etc/make.conf file, you can safely remove it from the list. If more USE flags than the above are showing up that fine too. Most of the daemons above will have pam ipv6 or others that appear.

We're going to slave SASL off Courier-authlib instead of having it talk directly to the database. This allows us to use encrypted passwords and seems to work better as well. However there have been some weird authlib problems in recent updates so watch your upgrades.

Some webmail clients require php to be compiled with Unicode support, so just enable it to be sure, you may be needing it eventually.

[edit] Installing and configuring the packages

[edit] MySQL

There is a great guide here for installing MySQL, so I suggest you read it too, so you don't miss anything: MySQL Startup Guide

[edit] Installation

First install the package

# emerge -a dev-db/mysql

Once that is done, setup the root user in mysql

# emerge --config dev-db/mysql

Now you need install library pam_mysql.so. Do it typing:

# emerge -av pam_mysql

The last thing that needs doing, is adding mysql to the default runlevel, so it starts when the server starts

# rc-update add mysql default

That is really all that is needed to install mysql.

[edit] Configuration

Now we need to create the postfix database in mysql, and create the user to login with

$ mysql -u root -p
create database postfix_db;
GRANT ALL PRIVILEGES ON postfix_db.* TO postfix_user@localhost IDENTIFIED BY 'postfix_pass';
flush privileges; 

By default MySQL binds only to 127.0.0.1, aka localhost, and will not be accessible from outside your server. In order to let it bind to the normal ethernet interface you need to comment out the bind-address line in /etc/mysql/my.cnf. You will also need to change your GRANT line to allow access from more than localhost.

[edit] Apache2

For a guide on how to install and configure apache, please read the Apache2 article.

Once Apache2 is installed, add it to the default runlevel like you did with mysql

# rc-update add apache2 default

[edit] PHP

Now that you have Apache installed, installing PHP is really just running this command

# emerge -a php

Once that is done, edit /etc/conf.d/apache2 and add -D PHP5 to the APACHE2_OPTS variable

File: /etc/conf.d/apache2
APACHE2_OPTS="-D DEFAULT_VHOST -D INFO -D LANGUAGE -D SSL -D SSL_DEFAULT_VHOST -D PHP5"

[edit] Cyrus-SASL

To install Cyrus-SASL, simply emerge it

# emerge -a cyrus-sasl

Thats it, there isn't really any configuration to be done for this package, so just add it to the default runlevel

# rc-update add saslauthd default

SMTP Authentication settings:

File: /etc/sasl2/smtpd.conf
pwcheck_method:authdaemond
mech_list:PLAIN LOGIN
authdaemond_path:/var/lib/courier/authdaemon/socket

[edit] Postfix

Postfix is the SMTP server, that handles all the incoming emails

[edit] Installation

First verify that you have all the proper USE flags enabled. A pretend should look like this.

# emerge -pv postfix
mail-mta/postfix-2.5.6  USE="ipv6 mysql pam sasl ssl vda -cdb
-dovecot-sasl -hardened -ldap -mailwrapper -mbox -nis -postgres
(-selinux)"

Now install Postfix

# emerge -a postfix

Once Postfix is installed you'll need to add local aliases and run /usr/bin/newaliases so Postfix will start and be happy. Postfix does not deliver mail to root so you'll want to point the mail for root to some other user or mail account. Edit the /etc/mail/aliases file, where you uncomment and fill out the root and operator lines with your own login name:

File: /etc/mail/aliases
# Basic system aliases -- these MUST be present.
MAILER-DAEMON:      postmaster
postmaster:         root

# General redirections for pseudo accounts.
adm:                root
bin:                root
daemon:             root
exim:               root
lp:                 root
mail:               root
named:              root
nobody:             root
postfix:            root

# Well-known aliases -- these should be filled in!
root:               yourusername
operator:           yourusername

# Standard RFC2142 aliases
abuse:              postmaster
ftp:                root
hostmaster:         root
news:               usenet
noc:                root
security:           root
usenet:             root
uucp:               root
webmaster:          root
www:                webmaster

# trap decode to catch security attacks
# decode:           /dev/null

Now run the newaliases utility, to regenerate the aliases database file

# newaliases

Now add postfix to the default runlevel

# rc-update add postfix default

And start it

# /etc/init.d/postfix start

[edit] Configuration

Now you need to change the /etc/postfix/main.cf and merge the changes below into it

File: /etc/postfix/main.cf
# local settings. Remember any domain you want treated as virtual
# can not be listed in either relay_domains or mydestination. 
myhostname = mail01.domain.com
mydomain = domain.com
myorigin = $myhostname
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost
mynetworks_style = subnet
mynetworks = 127.0.0.0/8

# attachment filtering, optional
#mime_header_checks = regexp:/etc/postfix/mime_header_checks.regexp

# Size settings, optional
#message_size_limit= 112400000
#mailbox_size_limit = 224800000

# SASL settings
broken_sasl_auth_clients = yes
smtpd_sasl_auth_enable = yes
smtpd_sasl_authenticated_header = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =

# TLS stuff - Enable if you want to use SMTP over SSL
smtpd_use_tls = no
#smtpd_tls_key_file = /etc/postfix/newkey.pem
#smtpd_tls_cert_file = /etc/postfix/newcert.pem
#smtpd_tls_CAfile = /etc/postfix/cacert.pem
#smtpd_tls_loglevel = 3 #### change to 0 after everything works
#smtpd_tls_received_header = yes
#smtpd_tls_session_cache_timeout = 3600s
#tls_random_source = dev:/dev/urandom 

# transport Stuff, optional
#transport_maps = hash:/etc/postfix/transport
#relay_domains = proxy:mysql:/etc/postfix/mysql_relay_domains_maps.cf

# virtual stuff. We're going to punt and make all virtual mail users use the same UID:GID of Postfix. 
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf
virtual_gid_maps = static:207
virtual_mailbox_base = /var/vmail/
virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf
virtual_mailbox_limit = 112400000
virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf
virtual_minimum_uid = 207
virtual_transport = virtual
virtual_uid_maps = static:207
mailbox_transport = virtual

smtpd_recipient_restrictions = 
        #reject_non_fqdn_recipient
        #reject_non_fqdn_sender
        reject_unknown_recipient_domain
        permit_mynetworks
        permit_sasl_authenticated
        #check_policy_service inet:127.0.0.1:2501 #needed for sqlgrey and optional
        reject_unauth_destination
        permit

# additional spam fighting checks, optional
#smtpd_helo_restrictions = reject_unknown_helo_hostname
#smtpd_sender_restrictions = reject_unknown_sender_domain
#smtpd_data_restrictions = reject_unauth_pipelining

Then create the following files in /etc/postfix

File: /etc/postfix/mysql_relay_domains_maps.cf
# you only need this if you plan to act as a backup mx for various domains.
user = postfix_user
password = postfix_pass
hosts = localhost
dbname = postfix_db
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '1' AND active = '1'
File: /etc/postfix/mysql_virtual_alias_maps.cf
user = postfix_user
password = postfix_pass
hosts = localhost
dbname = postfix_db
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
File: /etc/postfix/mysql_virtual_domains_maps.cf
user = postfix_user
password = postfix_pass
hosts = localhost
dbname = postfix_db
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
File: /etc/postfix/mysql_virtual_mailbox_maps.cf
user = postfix_user
password = postfix_pass
hosts = localhost
dbname = postfix_db
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
File: /etc/postfix/mime_header_checks.regexp
/^\s*Content-(Disposition|Type).*name\s*=\s*"?(.+\.(ad[ep]|asd|ba[st]|c[ho]m|cmd|cpl|crt|dbx|dll|exe
|hlp|hta|in[fs]|isp|js|jse|lnk|md[etw]|ms[cipt]|nws|ocx|ops|pcd|pi|pif|prf|reg|scf|scr|sct|sh[bms]|uue
|vb|vb[esx]|vxd|wab|ws[cfh]))"?\s*$/ REJECT Files attached to emails that contain or end in "$3" are
prohibited on this server as they may contain viruses. The file named "$2" was rejected.
Note: You'll need to tweak the last file somewhat for your system, but I used this in production and have had no complaints. This needs to be all one line.

[edit] OS stuff

[edit] Directories

Now that you have Postfix installed it's time to create and chown properly our mail directory.

# mkdir /var/vmail
# chown postfix: /var/vmail

The directory name and location does not matter, but it's a good idea to have it in a large directory. For performance reason in a very busy server you may want to move it to another partition because the Postfix internal queues are also on /var/ and those are write heavy. Moving the main mail store to a partition on another physical disk can increase performance on a box that is struggling under I/O issues.

Owning the /var/vmail to Postfix allows Postfix to create new mail directories for new users when the first piece of mail comes in for that user. I recommend setting Postfixadmin to send a welcome message to new users to make sure their .maildir is created.

[edit] Syslog-NG configuration

Just make sure you are using >=syslog-ng-2* and you will be fine.

To be sure, check that your /etc/syslog-ng/syslog-ng.conf contains these lines

File: /etc/syslog-ng/syslog-ng.conf
destination mail { file("/var/log/mail.log"); };

filter f_mail { facility(mail); };
filter f_messages { level(info..warn) # this line should already exist
       and not facility(mail); };    # make sure this line is under the above line.

log { source(src); filter(f_mail); destination(mail); };

[edit] Courier-IMAP

Courier-IMAP is that package that contains the pop3 and imap server.

Those are the ones that are used when the user is reading the mails in their inboxes.

[edit] Installation

Again verify USE flags.

# emerge -pv courier-imap
These are the packages that would be merged, in order:

[ebuild  N    ] net-mail/courier-imap-4.4.1-r1  USE="fam gdbm ipv6 nls -berkdb -debug -gnutls (-selinux)" 0 kB

Total: 1 package (1 new), Size of downloads: 0 kB

Then emerge it

# emerge -a courier-imap

Once done, add the services that you need to the default runlevel

  • POP3
# rc-update add courier-pop3d default
  • IMAP
# rc-update add courier-imapd default
  • POP3 over SSL
# rc-update add courier-pop3d-ssl default
  • IMAP over SSL
# rc-update add courier-imapd-ssl default
Note: You need to create a SSL certificate before starting the ssl init scripts the first time:
# mkimapdcert
# mkpop3dcert

[edit] Configuration

For large virtual systems remember to increase per IP connections in /etc/courier-imap/imapd and any other services you plan to offer to the public. Even on a small system Thunderbird tends to cache several connections to the server. I run my personal mail servers to allow 40 connections from a single IP for IMAP. That seems to work.

This is done by changing the MAXPERIP varible to 40

File: /etc/courier-imap/imapd
MAXPERIP=40

[edit] Courier-AuthLib

Courier-AuthLib handles the authentication of the users, when they connect to imapd or pop3d to read their mail.

[edit] Installation

Again verify the use variables

# emerge -pv courier-authlib
These are the packages that would be merged, in order:

[ebuild  N    ] net-libs/courier-authlib-0.61.1  USE="crypt gdbm mysql -berkdb -debug -ldap -pam -postgres -vpopmail" 0 kB

Total: 1 package (1 new), Size of downloads: 0 kB

Then emerge it

# emerge -a courier-authlib

And add it to the default runlevel

# rc-update add courier-authlib default

[edit] Configuration

First the /etc/courier/authlib/authmysqlrc file needs to be fitted to our needs

File: /etc/courier/authlib/authmysqlrc
#DEFAULT_DOMAIN         domain.tld
MYSQL_CRYPT_PWFIELD     password
MYSQL_DATABASE          postfix_db
MYSQL_GID_FIELD         '207'
MYSQL_HOME_FIELD        '/var/vmail'
MYSQL_LOGIN_FIELD       username
MYSQL_MAILDIR_FIELD     maildir
MYSQL_NAME_FIELD        name
MYSQL_OPT               0
MYSQL_PASSWORD          postfix_pass
# Uncomment below if you want quota support.
#MYSQL_QUOTA_FIELD      quota
MYSQL_SERVER            localhost
MYSQL_UID_FIELD         '207'
MYSQL_SOCKET            /var/run/mysqld/mysqld.sock
MYSQL_USERNAME          postfix_user
MYSQL_USER_TABLE        mailbox
# You can also turn off IMAP authentication when a user is
# marked as inactive. Be aware that this will cause webmail auth,
# smtp relay if slaved off courier-authlib, and POP3/IMAP logins to fail.
#MYSQL_WHERE_CLAUSE     active='1'

Then you need to edit /etc/courier/authlib/authdaemonrc and make sure authmysql is the first in the authmodulelist variable

File: /etc/courier/authlib/authdaemonrc
authmodulelist="authmysql authpam"

You may need to loosen permissons on /var/lib/courier/authdaemon/socket I'd try it on your system first and if you see permission denied errors this is likely the problem.

# chmod +x /var/lib/courier/authdaemon

[edit] PostfixAdmin

This section will show you how to set up PostfixAdmin. This is done first because it doesn't depend on anything else and sets up the databases that will be used by Postfix and Courier.

[edit] Virtual Host Setup

This section will install PostfixAdmin and configure the Apache virtual host. This section does not deal with configuring SSL, although it is highly recommended that you only access PostfixAdmin over SSL.

Using webapp-config, install PostfixAdmin using the following command, replacing the 2.2.1.1 with the version you're using:
webapp-config --install --host=mailadmin.example.org postfixadmin 2.2.1.1

Pay attention to any messages that webapp-config displays and follow any instructions you're given.

PostfixAdmin will now be installed to /var/www/mailadmin.example.org/htdocs

Note: If you want PostfixAdmin to be installed to a directory within the virtual host, use webapp-configs -d (--dir) option. For further help, see:
webapp-config --help

Now you need to tell Apache about the virtual host. To do so, put the following into a new file, /etc/apache2/vhosts.d/mailadmin.example.org.conf (based on the Gentoo default virtual host). Remember to change "mailadmin.example.org" into your hostname in this file, it appears four times:

File: /etc/apache2/vhosts.d/mailadmin.example.org.conf
<VirtualHost *:80>
    ServerName mailadmin.example.org
    DocumentRoot "/var/www/mailadmin.example.org/htdocs"

    <Directory "/var/www/mailadmin.example.org/htdocs">
        # Possible values for the Options directive are "None", "All",
        # or any combination of:
        #   Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews
        #
        # Note that "MultiViews" must be named *explicitly* --- "Options All"
        # doesn't give it to you.
        #
        # The Options directive is both complicated and important.  Please see
        # http://httpd.apache.org/docs/2.2/mod/core.html#options
        # for more information.
        Options Indexes FollowSymLinks

        # AllowOverride controls what directives may be placed in .htaccess files.
        # It can be "All", "None", or any combination of the keywords:
        #   Options FileInfo AuthConfig Limit
        AllowOverride All

        # Controls who can get stuff from this server.
        Order allow,deny
        Allow from all
    </Directory>

    <IfModule alias_module>
        # Alias: Maps web paths into filesystem paths and is used to
        # access content that does not live under the DocumentRoot.
        # Example:
        #   Alias /webpath /full/filesystem/path
        #
        # If you include a trailing / on /webpath then the server will
        # require it to be present in the URL.  You will also likely
        # need to provide a <Directory> section to allow access to
        # the filesystem path.

        # ScriptAlias: This controls which directories contain server scripts.
        # ScriptAliases are essentially the same as Aliases, except that
        # documents in the target directory are treated as applications and
        # run by the server when requested rather than as documents sent to the
        # client.  The same rules about trailing "/" apply to ScriptAlias
        # directives as to Alias.
        ScriptAlias /cgi-bin/ "/var/www/mailadmin.example.org/cgi-bin/"
    </IfModule>

    <Directory "/var/www/mailadmin.example.org/cgi-bin">
        AllowOverride None
        Options None
        Order allow,deny
        Allow from all
    </Directory>


    <IfModule mpm_peruser_module>
        ServerEnvironment apache apache
    </IfModule>
</VirtualHost>

# vim: ts=4 filetype=apache
Finally, to apply the changes, restart Apache with:
/etc/init.d/apache2 restart


[edit] Configuration

Open up the config.inc.php file in the postfixadmin directory. The following settings are listed in the order that they appear.

First comment out the configured setting by placing a # in front of it to tell PostfixAdmin that we've configured it. Until you do this, PostfixAdmin will not run:

Let PostfixAdmin know that we changed the config-file. Do NOT uncomment the line because login.php use the variable configured.

$CONF['configured'] = true;

Tell PostfixAdmin what web address it will be accessed with:

$CONF['postfix_admin_url'] = 'http://mailadmin.example.org/';

If your native language isn't English, you'll want to change the default_language setting. A list of language files in the languages/language.php file. For example, if you want PostfixAdmin in German:

$CONF['default_language'] = 'de';

Next set up the MySQL connection. This uses the MySQL database and user set up above. The password should be the same password you entered when creating the postfix_user MySQL user.

$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix_user';
$CONF['database_password'] = 'postfix_pass';
$CONF['database_name'] = 'postfix_db';
$CONF['database_prefix'] = ;

You'll want to change the admin email address that PostfixAdmin uses. This is used as the From address when sending messages to new accounts.

$CONF['admin_email'] = 'postmaster@example.org';

This setup will use mailboxes stored in the format <domain>/<username>, so change the domain_path and domain_in_mailbox settings to match those below.

$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';

This setup will use quotas, so tell PostfixAdmin to turn them on.

$CONF['quota'] = 'YES';

PostfixAdmin displays a couple of customizable links. You'll probably want to change these to link to your website.

$CONF['user_footer_link'] = "http://example.org/";
$CONF['show_footer_text'] = 'YES';
$CONF['footer_text'] = 'Example Webhosting';
$CONF['footer_link'] = 'http://example.org/';

Finally, you can change the content of the email that is sent to new users.

$CONF['welcome_text'] = <<<EOM
Hi,
Welcome to your new account.
EOM;

[edit] Setup

You can now complete the setup of PostfixAdmin, creating the database, by visiting the setup page. For example: http://mailadmin.example.org/setup.php

At this point you'll be asked to set up a global admin user. Follow the instructions to do so. Remember the details as you'll need them to log in later.

Note: When setting e-mail for admin user, postfixadmin attempts to validate the domain - this normally just takes the form of a DNS lookup - so if the domain isn't registered yet, it won't work. However, you can tell postfixadmin to not check the validity of domains in it's config file :
File: /var/www/mailadmin.example.org/htdocs/config.inc.php
 $CONF['emailcheck_resolve_domain']='NO';
Finally remove the setup.php file to stop others from being able to reset / change your database unexpectedly:
rm /var/www/mailadmin.example.org/htdocs/setup.php

You can now visit your PostfixAdmin install at the location you set it up. For example: http://mailadmin.example.org/

However, you should not set any domains or mailboxes up yet because Postfix and Dovecot have not been set up yet.

[edit] Sqlgrey

[edit] Why Greylist?

It's the simplest way to stop significant spam and it uses far less resources than just about any other method. I've been using sqlgrey on multiple servers and it seems to work well so that's what we'll use here.

[edit] Installation

First install the package

# emerge sqlgrey

Now configure it with Portage system

# emerge --config sqlgrey

Then run this command to set the setting in /etc/conf.d/postgrey

# echo "POSTGREY_OPTS\=\"--delay=30\"" >> /etc/conf.d/postgrey

And finally add it to the default runlevel

# rc-update add sqlgrey default

[edit] Delay Time

I recommend a very small delay time as I've used above. Many webmail sites like Hotmail will attempt to delivery every thirty seconds for the first three minutes. The next retry will be fifteen minutes after the last retry. By using a very small delay you can still provide effective greylisting, but keep the total delay to a minimum.

[edit] Oddities

Here are a couple of weird issues that I ran into while installing Postfix Admin or using it.

[edit] Adding Multiple Emails to an Alias

Create an alias pointing to a single address. Now edit the alias again. You'll be able to add multiple email addresses, one per line, to the alias now.

Personal tools