Search:  
Gentoo Wiki

HOWTO_Linux_Virtual_Server

This article is part of the HOWTO series.
Installation Kernel & Hardware Networks Portage Software System X Server Gaming Non-x86 Emulators Misc
Split-arrows.gifIt has been suggested that this article be split into multiple articles accessible from a disambiguation or index page.   (Discuss)

BETA Version -- I've been busy lately and haven't been able to update this document. While I think this document is complete, it hasn't been completely tested (as far as I know) -- so feel free to update with your findings.

NOTE: There have been heavy changes in configuration files and paths of the Gentoo Apache2 package. Thus, large parts of the Apache-related instructions are NOT up to date. Please be careful. LX 15:51, 7 November 2005 (GMT)

Contents

Introduction

What is the Purpose of this Doc?

This document will explain how to install and configure a mail server capable of handling hundreds of domains and users. This how-to uses Postfix, Courier-imap, Mysql, and Apache as the core of this virtual system. If these packages don't appeal to you, Gentoo has a number of how-to's built around other MTA's or databases.

Why Write Another How-To?

This how-to is based off the Gentoo Virtual How-To which can be found at: http://www.gentoo.org/doc/en/virt-mail-howto.xml. The Gentoo how-to is starting to show it's age. This doc will update various parts and try to add missing functionality.

Terminology

This doc will use domain.tld as the default domain and host as the default hostname. Please make sure you replace those with your settings.

The Basic Architecture of the System Described in this Doc.

SMTP delivery

Sending mail server --> Your mail server --> Postfix --> Mysql lookup --> delivery

SMTP relay

Mail client --> Your mail server --> Postfix --> Cyrus SASL smtp auth --> Courier authdaemond --> Mysql lookup --> smtp relayed

POP3

Mail reader --> Your mail server --> Courier-imap --> Mysql lookup --> read mail

Portage and System Configuration

Portage Configuration

We'll need to configure Portage so that each package is built correctly. The mail system is highly dependent on mysql, so that's going to be added to most of the major packages. Here's the full list of changes.


Open up /etc/make.conf and add these USE variables to your existing ones:

File: /etc/make.conf
# USE="apache2 authdaemond imap libwww maildir mysql sasl spell ssl vda"


However if you prefer to not to activate all these variables globally, you can set them in /etc/portage/package.use. This might be better if you prefer not to have mysql built into everything. On my home server I normally add apache2 ssl, spell, sasl, and vhost to my /etc/make.conf and then add the rest through /etc/portage/package.use. I've included all USE variables below for clarity.

File: /etc/portage/package.use
mail-mta/postfix                mysql sasl ssl vda
dev-libs/cyrus-sasl             authdaemond -mysql
mail-client/squirrelmail        mysql spell ssl virus-scan
www-apps/horde                  mysql
net-mail/courier-imap           -fam
net-libs/courier-authlib        mysql ssl
net-www/apache                  ssl
mail-filter/amavisd-new         mysql
net-libs/libwww                 mysql ssl
dev-php/mod_php                 apache2 gd imap mysql nls session spell ssl
dev-php/php                     apache2 gd imap mysql nls session spell ssl


Notice the -fam. I've found the fam daemon to work sporadically and crash fairly often. I recommend compiling Courier-imap without fam support. I also recommend using -mysql with cyrus-sasl so that it relies completely on Courier's authlib.

Note: fam is required for more advanced features like imap shared folders, and for multi-client access to the same maildir. Please read deeper into FAM if you decide to enable it.

Adding "-acl -alsa -cups -doc -gnome -gtk -gtk2 -java -kde -nls -oss -qt -sdl -X" in your USE flags may save a few hours if you are setting up a headless server. I use these settings on my work server to eliminate packages that aren't required.

Note: If you are getting errors in /var/log/messages such as "pop3d: authentication error: Input/output error," you may want to add "-ipv6" to your use variable, as ipv6 is not compatible with ipv4 (and you probably want to use ipv4).

Also, if you're starting from a fresh install, make sure you have sys-auth/pam_mysql emerged, or else PAM will not be able to talk to the MySQL database.

System Configurations

Now, we need to add our hostname. Open "/etc/conf.d/hostname" (N.B.: /etc/hostname and /etc/dnsdomainname are both obsolete under the older baselayout).

File: /etc/conf.d/hostname
# /etc/conf.d/hostname
# $Header: /var/cvsroot/gentoo-src/rc-scripts/etc/conf.d/hostname,v 1.2.4.1 200$

# Set to the hostname of this machine
HOSTNAME="host"
Code: Command
# hostname host

The file changes the hostname permenantly while the command changes it immediately.

Next edit your /etc/hosts file so that your machine can resolve itself properly:

File: /etc/hosts
127.0.0.1 localhost
127.0.0.1 host.domain.tld host
127.0.0.1 domain.tld

DNS is also a critical thing. You need to have at least an MX record pointing to your IP address. You can goto dnsreport.com to run a report on your domain or hostname. Feel free to run on etherpunk.com so you can compare.

Installing the Packages

We're going to emerge almost all packages at this point. If you're building everything from scratch it can take several hours.

Here's what we do

  1. Uninstall ssmtp (the default MTA).
  2. Sync to get up to date
  3. Install postfix immediately after (otherwise ssmtp would be remerged by any app that has an MTA dependency).
  4. Install everything else we need for this tutorial
  5. Update all packages with the new USE flags
emerge -C ssmtp;\
emerge --sync &&\
emerge -n postfix &&\
emerge -n apache dev-lang/php cyrus-sasl courier-imap mysql amavisd-new clamav &&\
emerge --newuse world

NOTE: You should, of course, use --pretend or --ask if you want to see what will be emerged rather than emerge it.

One day dev-lang/php may be used and php-5 will install with ease

For what it's worth, here are the version numbers as of this writing (currently: 2005.03.07):

Virtual Web Hosting

Apache, mod_php, and PHP

A nicely organized directory structure is important, most especially when you are hosting multiple domains. We will start with this first, so let's move and change a few things.

Code: Commands
# cd /var/www
# mv localhost domain.tld
# ln -sf domain.tld localhost

You will need to make a directory structure for each domain you will be hosting. If you want to give control of a domain over to a user such that they can take control and do whatever they need to do, you would do the following:

Code: Commands
# mkdir -p /var/www/domain2.tld/{htdocs,cgi-bin}
# chown -R some_user:users /var/www/domain2.tld
# ln -sf /var/www/domain2.tld /home/some_user/domain2.tld
# chown some_user:users /home/some_user/domain2.tld

Now, let's configure /etc/conf.d/apache2 by finding and replacing the APACHE2_OPTS with this:

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

Note by Che: You don't need to do this with latest dev-lang/php, it configures apache by itself

Now, open /etc/apache2/httpd.conf and change the following:

File: /etc/apache2/httpd.conf
ErrorLog logs/apacheserver-error_log
DocumentRoot /var/www/domain.tld/htdocs

Note by Che: ErrorLog is now in /etc/apache2/modules.d/00_mod_log_config.conf and DocmentRoot is in /etc/apache2/vhosts.d/default_vhost.include


Now edit /etc/apache2/httpd.conf and find and replace the 'ServerAdmin' variable to hostmaster. The reason we choose hostmaster is so we stay within RFC 2142 requirements. The way it's supposed to work is if your server goes down or if something nasty is happening, the other admin is supposed to know that 'hostmaster@domain.tld' is a method I can contact them so they can fix it.

File: /etc/apache2/httpd.conf
ServerAdmin hostmaster@domain.tld

Note by Che: ServerAdmin is now in /etc/apache2/vhosts.d/default_vhost.include

/* I need to double check this, I think the vhosts.conf file replaces these */ Comment by Doudou: Yes, they do. I'll update this section on monday. Inform apache of the htdocs for every domain:

File: /etc/apache2/httpd.conf
<Directory /var/www/domain.tld/htdocs>
    Options -Indexes FollowSymLinks MultiViews
    AllowOverride All
    <IfModule mod_access.c>
        Order allow,deny
        Allow from all
    </IfModule>
</Directory>

Change the cgi-bin to point to your primary domain (I like to keep the htdocs and cgi-bin section near each other, which is usually at the very end of the conf file):

File: /etc/apache2/httpd.conf
###
### This is intended for your world-accessible CGI programs.
###
<Directory /var/www/domain.tld/cgi-bin>
    AllowOverride All
    Options ExecCGI
    <IfModule mod_access.c>
        Order allow,deny
        Allow from all
    </IfModule>
</Directory>

Comment by Che: this is now in /etc/apache2/vhosts.d/default_vhost.include, probably the only thing that needs editing is to replace localhost with domain.tld and same thing for ScriptAlias

Now we need to edit /etc/apache2/conf/vhosts/vhosts.conf. For each domain you plan on hosting (or add them as you get them), you will need to add another 'domain.tld' section (not the first two lines, but everything past it). The first two lines is so you server knows it's responding on those ports to any domain listed below. You can also specify a different SSL certificate for each virtual host if need be.

File: /etc/apache2/conf/vhosts/vhosts.conf
NameVirtualHost *:80
NameVirtualHost *:443
###################################################
# domain.tld
###################################################
<VirtualHost *:80>
    ServerName domain.tld
    Serveralias www.domain.tld
    DocumentRoot /var/www/domain.tld/htdocs
    DirectoryIndex index.php index.html
    ErrorLog /var/log/apache2/domain.tld-error
    CustomLog /var/log/apache2/domain.tld-access combined
</VirtualHost>
<VirtualHost *:443>
    ServerName domain.tld
    Serveralias www.domain.tld
    DocumentRoot /var/www/domain.tld/htdocs
    DirectoryIndex index.php index.html
    ErrorLog /var/log/apache2/domain.tld-error
    CustomLog /var/log/apache2/domain.tld-access combined
    SSLEngine On
    SSLCertificateFile /etc/apache2/conf/ssl/domain.tld/domain.tld.cert
    SSLCertificateKeyFile /etc/apache2/conf/ssl/domain.tld/domain.tld.key
</VirtualHost>

Edit by Che: this is now in /etc/vhosts.d for every new vhost create a new file like 01_vhost_domain2.tld.conf etc. The configuration for your main domain is in default_vhost.include

I know this said not to edit it, but I wanted to make something clear. In order to add another domain, say dmain2.tld, you just make another alias for it, like so....

IMPORTANT! If you need 2 SEPARATED domains with SEPARATE SSL certs - remember, that it isn't possible if you have only 1 IP. You must to have separate IP per each SSL cert/domain.

File: /etc/apache2/conf/vhosts/vhosts.conf
###################################################
# domain2.tld
###################################################
<VirtualHost *:80>
    ServerName domain2.tld
    Serveralias www.domain2.tld
    DocumentRoot /var/www/domain2.tld/htdocs
    DirectoryIndex index.php index.html
    ErrorLog /var/log/apache2/domain2.tld-error
    CustomLog /var/log/apache2/domain2.tld-access combined
</VirtualHost>
<VirtualHost *:443>
    ServerName domain2.tld
    Serveralias www.domain2.tld
    DocumentRoot /var/www/domain2.tld/htdocs
    DirectoryIndex index.php index.html
    ErrorLog /var/log/apache2/domain2.tld-error
    CustomLog /var/log/apache2/domain2.tld-access combined
    SSLEngine On
    SSLCertificateFile /etc/apache2/conf/ssl/domain2.tld/domain.tld.cert
    SSLCertificateKeyFile /etc/apache2/conf/ssl/domain2.tld/domain.tld.key
</VirtualHost>

Obviously you need to create the directory /var/www/domain2.tld for this to work, but it will work. You also need to add the new directory to the httpd.conf file:

File: /etc/apache2/httpd.conf
<Directory /var/www/domain2.tld/htdocs>
    Options -Indexes FollowSymLinks MultiViews
    AllowOverride All
    <IfModule mod_access.c>
        Order allow,deny
        Allow from all
    </IfModule>
</Directory>

Edit by Che: this goes into the vhosts.d files as well

As a shortcut, you can use '<Directory /var/www/*/htdocs>' to avoid adding a new line for each domain. However, I don't know if this would create security problems. Also, note that doing things this way doesn't allow you to tweak the setting for each virtual domain (although, you could use .htaccess for that task anyway....). Enjoy.

SSL Certs for Postfix and Apache

It should be noted that only one SSL certificate can be associate with an IP address. So, for example, if you have associated the domain.tld with an SSL cert and are hosting domain2.tld, then when someone goes to https://www.domain2.tld then they will see domain.tld's SSL cert -- so it will look spoofed. This is by design. I suggest informing your users of this and letting them know the last few digits of your SSL cert so they can at least look at it and know if it's real or not (depends on how high you want to set your paranoia level). Our first step here is to make SSL certificates for our services, so change our default values for our domain in /etc/ssl/openssl.cnf (if they don't exist, create them). Also, 'commonName' should be your website, such as 'www.domain.tld' this is expect in browsers or it won't like you very much. I suggest using your 'hostmaster@domain.tld' address for the email address, due to spam harvesters. Find these values and replace them with the corresponding information:

The configuration you need to edit here has two parts: A key, and a default value. This affects the UI you get in the next step (you'll understand). Here is an example of the things you most likely want to change:

File: /etc/ssl/openssl.cnf
countryName = Country
countryName_default = US
stateOrProvinceName = State
stateOrProvinceName_default = Vermont
localityName = City
localityName_default = Shelburne
0.organizationName = Domain.Tld
0.organizationName_default = Kernel.org
commonName = FQDN
commonName_default = www.kernel.org
emailAddress = E-mail Contact
emailAddress_default = nullandvoid@kernel.org

Note: commonName NEEDS to be specified. If, when executing the following commands, you get a line like:

Code: Commands
www.domain.com[]

Make sure that you still fill it in, or else the certificate will not properly be created (you'll understand just what I'm talking about in a minute).

Now we need to make the cert, make a request to sign it, and sign it. Usually you would have a major authority like Thawte but many people either can't afford it or don't want to use them so we will do it ourselves. Do the following to generate our pass-phrase-less Postfix cert:

Code: Commands
# cd /etc/ssl/misc
# ./CA.pl -newca
# ./CA.pl -newreq-nodes
# ./CA.pl -sign

Now we do the same for apache:

Code: Commands
# openssl req -new > new.cert.csr
# openssl rsa -in privkey.pem -out new.cert.key
# openssl x509 -in new.cert.csr -out new.cert.cert -req -signkey new.cert.key -days 365

Let's move the certs over to the apache directory (we will worry about the Postfix certs later):

Code: Commands
# export VHOST=www.kernel.org
# mkdir /etc/apache2/conf/ssl/${VHOST}
# cp /etc/ssl/misc/new.cert.cert /etc/apache2/conf/ssl/${VHOST}/${VHOST}.cert
# cp /etc/ssl/misc/new.cert.key /etc/apache2/conf/ssl/${VHOST}/${VHOST}.key
# unset VHOST

Now, edit /etc/apache2/conf/modules.d/41_mod_ssl.default-vhost.conf:

File: /etc/apache2/conf/modules.d/41_mod_ssl.default-vhost.conf
##
## SSL Virtual Host Context
##
<VirtualHost _default_:443>
# General setup for the virtual host
DocumentRoot "/var/www/domain.tld/htdocs"
ServerName www.domain.tld:443
ServerAdmin hostmaster@domain.tld
ErrorLog logs/ssl_error_log

## Look further down for the next few lines ##

SSLCertificateFile conf/ssl/domain.tld/domain.tld.cert
SSLCertificateKeyFile conf/ssl/domain.tld/domain.tld.key

Start up apache:

Code: Commands
# /etc/init.d/apache2 start

Now point your browser to yor domain and check it out. Smile in awe and amazement. Congratulations, you have your web server going!

Troubleshooting

Stop your apache server

/etc/init.d/apache2 stop

then /usr/sbin/apache2 -S

will show how it parses the vhosts config file

Virtual Mail Hosting

Postfix

Postfix is going to be our MTA of choice. See Postfix

Courier-IMAP

Courier-IMAP isn't just an IMAP service, it will also provide our POP3, POP3-SSL, IMAP, IMAP-SSL, and authlib. We need to modify some config settings so you can use SSL (Eventually we will be autheticating against SASL, so you can use send mail without having to use webmail method or being on the local network). Modify the C, ST, L, CN, and email parameters in your /etc/courier-imap/pop3d.cnf and /etc/courier-imap/imapd.cnf. Your CN (common name) should be your domain name (ie: domain.tld) and email address should probably be something like: postmaster@domain.tld:

Code: Misc
# cd /etc/courier-imap
# nano -w pop3d.cnf
# nano -w imapd.cnf

Create the certificates:

Code: Commands
# mkpop3dcert
# mkimapdcert

Start the courier services:

Code: Commands
# /etc/init.d/courier-imapd start
# /etc/init.d/courier-imapd-ssl start
# /etc/init.d/courier-pop3d start
# /etc/init.d/courier-pop3d-ssl start

Add the courier services to default startup:

Code: Commands
# rc-update add courier-authlib default
# rc-update add courier-imapd default
# rc-update add courier-imapd-ssl default
# rc-update add courier-pop3d default
# rc-update add courier-pop3d-ssl default

Cyrus-sasl and Courier-authlib

Next we're going to config cyrus-sasl. Cyrus-sasl is going to allow users that aren't on allowed IP space to relay mail. Cyrus-sasl will use courier-authlib as an intermediate to Mysql. This will allow the use of encrypted passwords and be simpler to setup.

Open up /etc/sasl2/smtpd.conf and modify it so it contains only:

File: /etc/sasl2/smtpd.conf
pwcheck_method: authdaemond
log_level: 3
mech_list: PLAIN LOGIN
authdaemond_path:/var/lib/courier/authdaemon/socket
Code: warning: SASL authentication problem: unknown password verifier
##if you get something like this, this worked for me:
# vi /etc/sasl2/smtpd.conf
change "authdaemond" into "saslauthd" (without ")
# echo "sys-auth/pam_mysql ~amd64" >> /etc/portage/package.keywords
# emerge -v sys-auth/pam_mysql
# /etc/init.d/saslauthd restart


If you have trouble connecting to smtp and you see an error in the log saying: SASL authentication failure: cannot connect to Courier authdaemond: Connection refused, you may try adding the user 'postfix' to the group 'mail' by executing "gpasswd -a postfix mail"

Now open up /etc/conf.d/saslauthd and replace the 'SASLAUTHD_OPTS variable with this:

File: /etc/conf.d/saslauthd
SASLAUTHD_OPTS="${SASLAUTH_MECH} -a pam -r"

We need to copy our SSL certs from the apache section over:

Code: Commands
# cd /etc/ssl/misc
# cp demoCA/cacert.pem /etc/postfix
# cp newcert.pem /etc/postfix
# cp newreq.pem /etc/postfix

Now we need to modify /etc/courier/authlib/authdaemonrc and change 'authmodulelist' variable to be the following:

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

Now modify /etc/courier/authlib/authmysqlrc and modify the following values:

File: /etc/courier/authlib/authmysqlrc
MYSQL_SERVER localhost
MYSQL_USERNAME mailsql
MYSQL_PASSWORD Your_Passw0rd
MYSQL_DATABASE mailsql
MYSQL_USER_TABLE users
MYSQL_CLEAR_PWFIELD clear
MYSQL_UID_FIELD uid
MYSQL_GID_FIELD gid
MYSQL_LOGIN_FIELD email
MYSQL_HOME_FIELD homedir
MYSQL_NAME_FIELD name
MYSQL_MAILDIR_FIELD maildir
MYSQL_QUOTA_FIELD quota

Get authlib restarted:

Code: Commands
# /etc/init.d/courier-authlib restart

Adding SSL and SASL support to Postfix

Now edit the postfix config's to make it aware of your new sasl and ssl capabilities. Add the following parameters to the end of the file where they will be easy to find. Edit /etc/postfix/main.cf and append the following at the end:

File: /etc/postfix/main.cf
smtpd_sasl_auth_enable = yes
# No such thing as 'smtpd_sasl2_auth_enable', just commenting out for now
#smtpd_sasl2_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
smtpd_sasl_local_domain =
smtpd_recipient_restrictions =
	permit_sasl_authenticated,
	permit_mynetworks,
	reject_unauth_destination
smtpd_use_tls = yes
#smtpd_tls_auth_only = yes
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
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom

The broken_sasl_auth_clients option and the login auth method are for outlook and outlook express only and are undocumented. Make sure it's blank or your user names will get mangled by Postfix and be unable to auth. The smtpd_tls_auth_only option is commented out to ease testing the system. You can turn this on later if you desire.


Now we're going to verify that the config we changed were picked up by Postfix.

# telnet localhost 25
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
220 mail.domain.tld ESMTP Postfix
EHLO domain.tld
250-mail.domain.tld
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-XVERP
250 8BITMIME
^]
telnet> quit

Verify that the above AUTH and STARTTLS lines now appear in your Postfix install. As I said before, as it stands now AUTH will not work. That's because SASL will try to auth against it's sasldb, instead of the shadow file for some unknown reason, which we have not set up. So we're going to just plow through and set up MySQL to hold all of our auth and virtual domain information.

MySQL

Next we're going to install and configure MySQL. You'll need the [1] dumpfile for this step. Add MySQL to the default startup: # rc-update add mysql default

Let's install the base database: # /usr/bin/mysql_install_db


Now, follow the on screen instruction for changing your passwords for the MySQL database (not mysqladmin), otherwise your database will be wide open from the localhost. Start up MySQL: # /etc/init.d/mysql start

At this point, you may deviate from this HOWTO and follow this one: [2]. It explains how to set up a similar database structure. The difference is that the latter is administrable with 'postfixadmin', an easy web based posfix vitual tables admin tool. The ebuild is called 'postfixadmin'.

Download the genericmailsql.sql file

# cd /tmp

# wget http://www.gentoo.org/doc/en/files/genericmailsql.sql

Create and import our base mailsql # mysql -u root -p mysql

mysql> create database mailsql;

mysql> GRANT ALL PRIVILEGES ON mailsql.* TO mailsql@localhost IDENTIFIED BY 'Passw0rd';

mysql> quit

# mysql -u mailsql -p mailsql < genericmailsql.sql


Now, I will explain the tables that we imported so you understand what to change later and after this I will give you some specific things to try so you can get your stuff going.

These are some examples on the data you might want to place in the tables. host.domain1.tld will be a local domain and all others will be virtual.


Relocated Table

The relocated table informs a mailserver trying to send an email that a certain user's email address has changed, and provides them that address. For example, a woman getting married that needs to change her last name would want this kind of entry. In this example, the second entry changes their name. In the first entry, the user changes domains.

Code: Relocated Table
id	email			destination

1	juan@domain1.tld	juan@yahoo.com
2	jenb@domain2.tld	jeno@domain2.tld


Transport Table

The transport table tells Postfix if a domain is virtual or local. Since all the domains we will be recieving are virtual, we will flag them as such. In this example, host.domain.tld is a local domain and domain1.tld and doamin2.tld are our virtual domains.

Code: Transport Table
id	domain			destination

1	host.domain.tld	        local:
2	domain1.tld		virtual:
3	domain2.tld		virtual:


Alias Table

The alias table is only used for domains that have been specified as local. In this example, any email going to root@host.domain1.tld and postmaster@host.domain1.tld will be forwarded to mark@domain1.tld.

Code: Alias Table
id	alias		destination

1	root		mark@domain1.tld
2	postmaster	mark@domain1.tld


Users Table

The users table is the list of actual mail accounts on the system that may receive email. You will add new users by creating a new entry in this table. Once you have added a new user you will need to create their directory
# mkdir -p /home/vmail/domain.tld/user

and own it properly (note: you need to create user vmail first, see below)
# chown -R vmail: /home/vmail/domain.tld/user

Postfix will not deliver mail unless the user's homedir have been created and owned properly. Once this user receives their first email Postfix will auto-create the .maildir/ structure inside their home dir. It is recommended that new users are sent a test message to create the .maildir and verify that the account works.

If something goes wrong and Postfix does not make the required directories, you can manually make directories using maildirmake .maildir and then chown them correctly. I plan on researching on how to make it use an encrpted password. Here is an example list of users (lines spliced for easy reading on the eyes). Remember the maildir line must have the trailing / or Postfix will deliver to a file instead of a directory.:

Code: Users Table
id	email			clear		name	uid	gid	homedir \
	maildir					quota	postfix

1	mark@domain1.tld	markpass	Mark Y	1001	1000	/home/vmail/domain1.tld/mark \
	/home/vmail/domain1.tld/mark/.maildir/		y
2	jeno@domain1.tld	jenopass	Jen O	1001	1000	/home/vmail/domain1.tld/jeno \
	/home/vmail/domain1.tld/jeno/.maildir/		y
3	mike@domain2.tld	mikepass	Mike K	1001	1000	/home/vmail/domain2.tld/mike \
	/home/vmail/domain2.tld/mike/.maildir/		y
4	omar@domain2.tld	omarpass	Omar T	1001	1000	/home/vmail/domain2.tld/omar \
	/home/vmail/domain2.tld/omar/.maildir/		y


Virtual Table

The virtual table is very much like the alias table. It does all the alias mappings for the virtual domains. In this example there are a number of aliases as well as a wildcard alias. When a wildcard alias is added to a domain all other accounts for that domain must have a virtual entry. When a new mail comes into the system the virtual table is checked first. If the wildcard is the best match, Postfix delivers to that account without checking the user table. You'll notice in this example that domain1.tld does not have aliases for its accounts in the user table because it has no wildcard entry whereas domain2.tld does.

Code: Virtual Table
id	email			destination

1	sales@domain1.tld	mike@domain1.tld,jeno@domain1.tld
2	abuse@domain1.tld	jeno@domain1.tld
3	@domain2.tld		mark@domain2.tld
4	mark@domain2.tld	mark@domain2.tld
5	omar@domain2.tld	omar@domain2.tld
6	sales@domain2.tld	omar@domain2.tld,mark@domain2.tld

phpMyAdmin

phpMyAdmin is how we will be managing our users.

Let's emerge it (it should auto-magically install it to our localhost): # emerge -av phpmyadmin

If you want to install phpmyadmin to another website, do the following (the version number may be different): # /usr/sbin/webapp-config -I -h domain.tld -u root -d /phpmyadmin phpmyadmin 2.6.1_p2-r1

Let's configure phpmyadmin, so open /var/www/domain.tld/htdocs/phpmyadmin/config.inc.php and change the following parameters.

File: /var/www/domain.tld/htdocs/phpmyadmin/config.inc.php
$cfg['PmaAbsoluteUri'] = '' // Prevents the default option from redirecting to localhost
$cfg['blowfish_secret'] = ''; // Passphrase to enable cookie configuration, pick anything unique
$cfg['Servers'][$i]['auth_type'] = 'cookie'; // Enables cookie-based authentication
$cfg['Servers'][$i]['host'] = 'localhost'; // MySQL hostname
$cfg['Servers'][$i]['controluser'] = 'mailsql'; // MySQL control user settings
// (this user must have read-only
$cfg['Servers'][$i]['controlpass'] = 'Passw0rd'; // access to the "mysql/user"
// and "mysql/db" tables)
$cfg['Servers'][$i]['user'] = 'mailsql'; // MySQL user
$cfg['Servers'][$i]['password'] = 'Passw0rd'; // MySQL password

Some people prefer to have their user as the root mysql account and others believe this is a nasty security hole. Choose your poison.

Now, fire up a browser and goto your phpmyadmin directory (probably something like: http://www.domain.tld/phpmyadmin). In the combo box in the upper left corner, choose the mailsql table. In the middle/left of the screen you should see a list of tables. You might even recognize them, as they are the same as I mentioned eariler (when we imported them). Now we need to put in some data that is relevent to us.

Transport Table

Goto the 'transport' table. 'Insert' a new entry. Enter the following information (where domain.tld is your domain):

Code: Transport Table
Domain: 	domain.tld
Destination: 	virtual:

Repeat this process until all your domains that you plan on hosting are entered.

Users Table

Goto the 'users' table. 'Insert' a new entry. Enter the following information (where UID and GID is the 'vmail' 'users' UID and GID):

Code: Users Table
Email:		user@domain.tld
Clear:		Passw0rd
Name:		Some User
UID:		1001
GID:		100
Homedir:	/home/vmail/domain.tld/user
Maildir:	/home/vmail/domain.tld/user/.maildir/
Quota:		
Postfix:	y

Virtual Table

Goto the 'virtual' table. 'Insert' a new entry. Enter the follwing information:

Code: Virtual Table
email:		postmaster@domain.tld
destination:	user@domain.tld

email:		hostmaster@domain.tld
destination:	user@domain.tld

email:		abuse@domain.tld
destination:	user@domain.tld

email:		webmaster@domain.tld
destination:	user@domain.tld

The vmail user

The vmail user is the single user that all the virtual domains will go through, so let's set it up:

Code: Commands
# adduser -d /home/vmail -s /bin/false vmail
# uid=`grep vmail /etc/passwd | cut -f 3 -d :`
# groupadd -g $uid vmail
# mkdir /home/vmail
# chown -R vmail: /home/vmail

Attention: In case you have given /var a separate partition on your web server (a quite common configuration), you might want to put your mail there, too. In this case, replace all /home/vmail by /var/vmailand do accordingly in the "users" table in your mail data base!


When creating a new user, Postfix will automagically generate the directories as soon as they recieve an email. So it's usually a good idea to send them a 'Hello' email to make sure it works properly. If you have to do this frequently, you can speed it up, creating and using the following file:

File: /usr/sbin/newmailbox
#!/bin/bash

echo "Hello,
welcome to this mail server.
Your Postmaster" | mail -s "Welcome" -r "John Smith <postmaster@example.com>" $1

where $1 is the mailbox name as in the "users" table, field "email". So calling newmailbox user@example.com creates all needed folders. (If you don't have mail installed, use the sendmail command instead.)

Configuring MySQL Authentication and vhosts

We need to configure pam, so edit /etc/pam.d/imap, /etc/pam.d/pop3, /etc/pam.d/smtp to look like the following:

Code: File: /etc/pam.d/{imap,pop3,smtp}
#auth required pam_nologin.so
#auth required pam_stack.so service=system-auth
#account required pam_stack.so service=system-auth
#session required pam_stack.so service=system-auth
auth optional pam_mysql.so host=localhost db=mailsql user=mailsql \
passwd=Passw0rd table=users usercolumn=email passwdcolumn=clear crypt=0
account required pam_mysql.so host=localhost db=mailsql user=mailsql \
passwd=Passw0rd table=users usercolumn=email passwdcolumn=clear crypt=0

These files will contain passwords. Make sure only pam can read them.

Code: Commands
# chmod 640 /etc/pam.d/{imap*,pop*,smtp}

You also need to change the password to your real password in above files.


Note: The above does not appear to be necessary. Contrary to what is stated above, I have found that it is not in fact necessary to modify the files in /etc/pam.d. Modifying authdaemonrc and authmysqlrc in /etc/courier/authlib, as described below, allows courier to authenticate against both MySQL and UNIX accounts. My configuration looks like this and works just fine:

Code: File: /etc/pam.d/{imap,pop3,smtp}
auth       required     pam_nologin.so
auth       include      system-auth
account    include      system-auth
session    include      system-auth

Next, set up the rest of the necessary config's for postfix to interract with the database for all it's other transport needs. There are a couple files invovled with this.

Code: /etc/postfix/mysql-aliases.cf
# mysql-aliases.cf
user = mailsql
password = Passw0rd
dbname = mailsql
table = alias
select_field = destination
where_field = alias
hosts = unix:/var/run/mysqld/mysqld.sock
Code: /etc/postfix/mysql-relocated.cf
# mysql-relocated.cf
user = mailsql
password = Passw0rd
dbname = mailsql
table = relocated
select_field = destination
where_field = email
hosts = unix:/var/run/mysqld/mysqld.sock
Code: /etc/postfix/mysql-transport.cf
# mysql-transport.cf
user = mailsql
password = Passw0rd
dbname = mailsql
table = transport
select_field = destination
where_field = domain
hosts = unix:/var/run/mysqld/mysqld.sock
Code: /etc/postfix/mysql-virtual-gid.cf
#myql-virtual-gid.cf
user = mailsql
password = Passw0rd
dbname = mailsql
table = users
select_field = gid
where_field = email
additional_conditions = and postfix = 'y'
hosts = unix:/var/run/mysqld/mysqld.sock
Code: /etc/postfix/mysql-virtual-maps.cf
#myql-virtual-maps.cf
user = mailsql
password = Passw0rd
dbname = mailsql
table = users
select_field = maildir
where_field = email
additional_conditions = and postfix = 'y'
hosts = unix:/var/run/mysqld/mysqld.sock
Code: /etc/postfix/mysql-virtual-uid.cf
# mysql-virtual-uid.cf
user = mailsql
password = Passw0rd
dbname = mailsql
table = users
select_field = uid
where_field = email
additional_conditions = and postfix = 'y'
hosts = unix:/var/run/mysqld/mysqld.sock
Code: /etc/postfix/mysql-virtual.cf
# mysql-virtual.cf
user = mailsql
password = Passw0rd
dbname = mailsql
table = virtual
select_field = destination
where_field = email
hosts = unix:/var/run/mysqld/mysqld.sock

Lastly, edit /etc/postfix/main.cf and replace/add the following:

Code: /etc/postfix/main.cf
alias_maps = mysql:/etc/postfix/mysql-aliases.cf
relocated_maps = mysql:/etc/postfix/mysql-relocated.cf
local_transport = local
local_recipient_maps = $alias_maps $virtual_mailbox_maps unix:passwd.byname
virtual_transport = virtual
virtual_mailbox_domains =
domain.tld,
domain2.tld
virtual_minimum_uid = 1000
virtual_gid_maps = static:$vmail-gid
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual.cf
virtual_uid_maps = static:$vmail-uid
virtual_mailbox_base = /
transport_maps = mysql:/etc/postfix/mysql-transport.cf
#virtual_mailbox_limit =

Remember to change $vmail-gid and $vmail-uid to the gid and uid of your vmail user.

For security reasons you should change the permissions of the various /etc/postfix/mysql-*.cf:

Code: Commands
# chmod 640 /etc/postfix/mysql-*.cf
# chgrp postfix /etc/postfix/mysql-*.cf

As of Postfix 2.0.x, there were a number of significant changes over the 1.1.x release. Notably the transport, virtual-gid, and virtual-uid tables are no longer necessary. The tables are still included if you wish to use them. We are done, so let's refresh Postfix:

# postfix reload

Web Based Mail

You have one, documented, option here: SquirrelMail. Another is Horde, however it hasn't been placed in here yet. RoundCube is very nice, but not yet in Portage (there's an ebuild in the Gentoo Bugzilla). Outlook and Thunderbird should work too.

SquirrelMail

see SquirrelMail

Antivirus protection with Amavisd-new ClamAV

Add amavisd-new to the default startup:

# rc-update add amavisd default

Start up the server:

# /etc/init.d/amavisd start

Next, edit /etc/postfix/master.cf by adding the following lines (at the bottom of the file):

Code: /etc/postfix/master.cf
smtp-amavis unix - - n - 2 lmtp
 -o smtp_data_done_timeout=1200
127.0.0.1:10025 inet n - n - - smtpd
 -o content_filter=
 -o local_recipient_maps=
 -o relay_recipient_maps=
 -o smtpd_restriction_classes=
 -o smtpd_client_restrictions=
 -o smtpd_helo_restrictions=
 -o smtpd_sender_restrictions=
 -o smtpd_recipient_restrictions=permit_sasl_authenticated,permit_mynetworks,reject
 -o mynetworks=127.0.0.0/8
 -o mynetworks_style=host
 -o strict_rfc821_envelopes=yes
 -o smtpd_error_sleep_time=0
pre-cleanup unix n - n - 0 cleanup
 -o virtual_alias_maps=
 -o canonical_maps=
 -o sender_canonical_maps=
 -o recipient_canonical_maps=
 -o masquerade_domains=
cleanup unix n - n - 0 cleanup
 -o mime_header_checks=
 -o nested_header_checks=
 -o body_checks=
 -o header_checks=
smtp inet n - n - - smtpd
 -o cleanup_service_name=pre-cleanup
pickup fifo n - n 60 1 pickup
 -o cleanup_service_name=pre-cleanup

Then edit your /etc/postfix/main.cf file to include support for amavis (bottom of the file):

Code: File: /etc/postfix/main.cf
content_filter = smtp-amavis:[127.0.0.1]:10024

If you would like a notification sent to you or an admin when a virus (or spam) is detected, you can specify a default location at ~ line 450/500 in the /etc/amavisd.conf file (I like it so I know it's working):

Code: File: /etc/amavisd.conf
$virus_admin = 'av@domain.tld';

Don't forget to add a virtual alias to your main account (unless you want to use your main account above). To test your virus scanning capabilites, I suggest using: www.webmail.us/testvirus (many exists, just google for 'test virus email').

Troubleshooting

phpmyadmin

Once you install phpmyadmin, you must setup the database for phpmyadmin to authenticate and store prefs...

mysql -u root -p < /usr/share/webapps/phpmyadmin/VERSION/sqlscripts/mysql/VERSION.sql

Credits

A great many people helped in this matter, more than I can actually list. Obviously, if you tweak/add this document, feel free to add yourself.

irc.freenode.net #apache #gentoo #postfix

http://www.gentoo.org/doc/en/virt-mail-howto.xml

http://postfixwiki.org/index.php?title=Virtual_Users_and_Domains_with_Courier-IMAP_and_MySQL

http://forums.gentoo.org/viewtopic-t-163861-highlight-amavisd+clamav+postfix.html

Retrieved from "http://www.gentoo-wiki.info/HOWTO_Linux_Virtual_Hosting_Server"

Last modified: Wed, 01 Oct 2008 09:32:00 +0000 Hits: 100,474