HOWTO Linux Virtual Hosting Server
From Gentoo Linux Wiki
| Installation • Kernel & Hardware • Networks • Portage • Software • System • X Server • Gaming • Non-x86 • Emulators • Misc |
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
|
[edit] Introduction
[edit] 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.
[edit] 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.
[edit] 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.
[edit] The Basic Architecture of the System Described in this Doc.
[edit] SMTP delivery
Sending mail server --> Your mail server --> Postfix --> Mysql lookup --> delivery
[edit] SMTP relay
Mail client --> Your mail server --> Postfix --> Cyrus SASL smtp auth --> Courier authdaemond --> Mysql lookup --> smtp relayed
[edit] POP3
Mail reader --> Your mail server --> Courier-imap --> Mysql lookup --> read mail
[edit] Portage and System Configuration
[edit] 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.
[edit] 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.
[edit] 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
- Uninstall ssmtp (the default MTA).
- Sync to get up to date
- Install postfix immediately aftter (otherwise ssmtp would be remerged by any app that has an MTA dependency).
- Install everything else we need for this tutorial
- 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):
- apache-2.0.52-r1
- mod_php-4.3.10
- php-4.3.10
- cyrus-sasl-2.1.20
- postfix-2.1.5-r2
- courier-imap-4.0.1
- mysql-4.0.22-r2
- clamav-0.82-r1
- amavisd-new-0.20040701
[edit] Virtual Web Hosting
[edit] 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 PHP4 -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.
[edit] 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!
[edit] Troubleshooting
Stop your apache server
/etc/init.d/apache2 stop
then /usr/sbin/apache2 -S
will show how it parses the vhosts config file
[edit] Virtual Mail Hosting
[edit] Postfix
Postfix is going to be our MTA of choice. It should be noted that Postfix does not like a comment on the same line as a variable.
Here is an example of a bad comment:
| Code: Misc |
myhostname = host.domain.tld # my fqdn |
Here is an example of a good comment
| Code: Misc |
# my fqdn myhostname = host.domain.tld |
Postfix needs to be tested with a basic config to make sure all parts are working before moving on to the more complicate virtual setup. This will often save hours of troubleshooting later.
| File: /etc/postfix/main.cf |
myhostname = host.domain.tld mydomain = domain.tld inet_interfaces = all mydestination = $myhostname, localhost.$mydomain, $mydomain mynetworks = 192.168.1.0/24, 127.0.0.0/8 |
We need to turn on debugging, so if something doesn't work you can troubleshoot. So, open up /etc/postfix/master.cf and add a '-vv' to the end of virtual, local, smtp, and smtpd services.
| File: /etc/postfix/master.cf |
smtp inet n - n - - smtpd -vv |
The next step is configure you /etc/mail/aliases file. All that needs to be done if to add a entry for the root user. thing we need to do is get or base aliases going. Here is a list of standard RFC 2142 aliases and common aliases (these are taken directly from my /etc/mail/aliases, incase you don't have them). Place them in /etc/mail/aliases:
| Code: /etc/mail/aliases |
# Well-known aliases -- these should be filled in! root: localuser |
We now need to update our aliases database, so run the following:
| Code: Commands |
# /usr/bin/newaliases |
Postfix should work now, so let's get it going:
| Code: Commands |
# /etc/init.d/postfix start |
And since we want it to start by default, we need to add it to the default startup:
| Code: Commands |
# rc-update add postfix default |
It's *highly* recommended you test your Postfix installation right now, so do that we shall (colors that are highlightes in red are commands you need to type; colors that are in black are the responses you should get):
telnet 127.0.0.1 25 Trying 127.0.0.1... Connected to 127.0.0.1. Escape character is '^]'. 220 mail.domain.tld ESMTP Postfix helo mail.domain.tld 250 mail.domain.tld mail from:<a@a.com> 250 Ok rcpt to:<root@domain.tld> 250 Ok data 354 End data with <CR><LF>.<CR><LF> To: you@domain.tld Subject: Test Email <enter> Cows go moo. . 250 Ok: queued as CC89074009 quit 221 Bye Connection closed by foreign host.
Your queued number should be different than listed above. If you recieve any problems, you should troubleshoot them before proceeding any further.
[edit] 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 |
[edit] 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 |
[edit] 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.
[edit] 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.
- alias - local domain email aliases (becuase we are telling Postfix that our primary domain is virtual, this should remain empty)
- relocated - users that have changed email addresses and you want to tell any connecting server where they went
- transport - a list of all the domains that you are hosting
- users - a list of all your users, including virtual, for all domains you are hosting
- virtual - a list of virtual aliases
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 |
[edit] 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.
[edit] 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.
[edit] 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 |
[edit] 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 |
[edit] 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/vmail – and 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 nail installed, use the sendmail command instead.)
[edit] 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
[edit] 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.
[edit] Squirrelmail
Since emerging will auto-magically install it as well, let's emerge it:
# emerge squirrelmail
To manually install it or install it to a different directory, do the following (the version numbers may be different though):
# webapp-config -I -h domain.tld -d /sqmail squirrelmail 1.4.4
Let's configure squirrelmail so, Change your Organization, Server, and Folder settings for squirrelmail.
# cd /var/www/localhost/htdocs/mail/config # perl ./conf.pl
I also suggest visiting the SquirrelMail website and looking at the plugins. There are a couple of virtual hosting plugins you may be intersted in. None are required but can make life a little better (as all plugins should do in one way or another).
Now you should be able to login to squirrelmail, again - with your full email address, and use your new webmail setup. Your username is your email address.
[edit] 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').
[edit] Troubleshooting
[edit] 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
[edit] 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 (Generic search purposes, but mostly the tips+tricks)
http://forums.gentoo.org/viewtopic-t-163861-highlight-amavisd+clamav+postfix.html
