Virtual Users And Domains With Postfix, Courier, MySQL And SquirrelMail (Fedora 10) - Page 2

6 Set MySQL Passwords And Configure phpMyAdmin

Start MySQL:

chkconfig --levels 235 mysqld on
/etc/init.d/mysqld start

Then set passwords for the MySQL root account:

mysqladmin -u root password yourrootsqlpassword
mysqladmin -h -u root password yourrootsqlpassword

If the last command throws an error at you...

[root@server1 i386]# mysqladmin -h -u root password howtoforge
mysqladmin: connect to server at '' failed
error: 'Access denied for user 'root'@'localhost' (using password: NO)'
[root@server1 i386]#

... we can set the password as follows: connect to MySQL:

mysql -u root -p

Type in the password for the MySQL root user. Then, on the MySQL shell, do this:

mysql> USE mysql;

mysql> UPDATE user SET Password = password('yourrootsqlpassword') WHERE Host = '' AND User = 'root';

mysql> UPDATE user SET Password = password('yourrootsqlpassword') WHERE Host = '' AND User = 'root';


mysql> SELECT * FROM user;

to make sure that all rows where the user is root have a password.

If everything is looking ok, run


... and leave the MySQL shell:

mysql> quit;

Now we configure phpMyAdmin. We change the Apache configuration so that phpMyAdmin allows connections not just from localhost (by commenting out the <Directory /usr/share/phpMyAdmin/> stanza):

vi /etc/httpd/conf.d/phpMyAdmin.conf

# phpMyAdmin - Web based MySQL browser written in php
# Allows only localhost by default
# But allowing phpMyAdmin to anyone other than localhost should be considered
# dangerous unless properly secured by SSL

Alias /phpMyAdmin /usr/share/phpMyAdmin
Alias /phpmyadmin /usr/share/phpMyAdmin
#<Directory /usr/share/phpMyAdmin/>
#   order deny,allow
#   deny from all
#   allow from

# This directory does not require access over HTTP - taken from the original
# phpMyAdmin upstream tarball
<Directory /usr/share/phpMyAdmin/libraries>
    Order Deny,Allow
    Deny from All
    Allow from None

# This configuration prevents mod_security at phpMyAdmin directories from
# filtering SQL etc.  This may break your mod_security implementation.
#<IfModule mod_security.c>
#    <Directory /usr/share/phpMyAdmin>
#        SecRuleInheritance Off
#    </Directory>

Then we create the system startup links for Apache and start it:

chkconfig --levels 235 httpd on
/etc/init.d/httpd start

Now you can direct your browser to or and log in with the user name root and your new root MySQL password.


7 Create The MySQL Database For Postfix/Courier

We create a database called mail:

mysqladmin -u root -p create mail

Next, we go to the MySQL shell:

mysql -u root -p

On the MySQL shell, we create the user mail_admin with the passwort mail_admin_password (replace it with your own password) who has SELECT,INSERT,UPDATE,DELETE privileges on the mail database. This user will be used by Postfix and Courier to connect to the mail database:

GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost' IDENTIFIED BY 'mail_admin_password';
GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost.localdomain' IDENTIFIED BY 'mail_admin_password';

Still on the MySQL shell, we create the tables that Postfix and Courier need:

USE mail;

CREATE TABLE domains (
domain varchar(50) NOT NULL,
PRIMARY KEY (domain) )

CREATE TABLE forwardings (
source varchar(80) NOT NULL,
destination TEXT NOT NULL,
PRIMARY KEY (source) )

email varchar(80) NOT NULL,
password varchar(20) NOT NULL,
quota bigint(20) DEFAULT '10485760',

CREATE TABLE transport (
domain varchar(128) NOT NULL default '',
transport varchar(128) NOT NULL default '',
UNIQUE KEY domain (domain)


As you may have noticed, with the quit; command we have left the MySQL shell and are back on the Linux shell.

The domains table will store each virtual domain that Postfix should receive emails for (e.g.


The forwardings table is for aliasing one email address to another, e.g. forward emails for to

source destination

The users table stores all virtual users (i.e. email addresses, because theemail address and user name is the same) and passwords (in encrypted form!) and a quota value for each mail box (in this example the default value is 10485760 bytes which means 10MB).

email password quota No9.E4skNvGa. ("secret" in encrypted form) 10485760

The transport table is optional, it is for advanced users. It allows to forward mails for single users, whole domains or all mails to another server. For example,

domain transport smtp:[]

would forward all emails for via the smtp protocol to the server with the IP address (the square brackets [] mean "do not make a lookup of the MX DNS record" (which makes sense for IP addresses...). If you use a fully qualified domain name (FQDN) instead you would not use the square brackets.).


8 Configure Postfix

Now we have to tell Postfix where it can find all the information in the database. Therefore we have to create six text files. You will notice that I tell Postfix to connect to MySQL on the IP address instead of localhost. This is because Postfix is running in a chroot jail and does not have access to the MySQL socket which it would try to connect if I told Postfix to use localhost. If I use Postfix uses TCP networking to connect to MySQL which is no problem even in a chroot jail (the alternative would be to move the MySQL socket into the chroot jail which causes some other problems).

Now let's create our six text files.

vi /etc/postfix/

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT domain AS virtual FROM domains WHERE domain='%s'
hosts =

vi /etc/postfix/

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT destination FROM forwardings WHERE source='%s'
hosts =

vi /etc/postfix/

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM users WHERE email='%s'
hosts =

vi /etc/postfix/

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT email FROM users WHERE email='%s'
hosts =

vi /etc/postfix/

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT transport FROM transport WHERE domain='%s'
hosts =

vi /etc/postfix/

user = mail_admin
password = mail_admin_password
dbname = mail
query = SELECT quota FROM users WHERE email='%s'
hosts =

chmod o= /etc/postfix/mysql-virtual_*.cf
chgrp postfix /etc/postfix/mysql-virtual_*.cf

Now we create a user and group called vmail with the home directory /home/vmail. This is where all mail boxes will be stored.

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /home/vmail -m

Next we do some Postfix configuration. Go sure that you replace with a valid FQDN, otherwise your Postfix might not work properly!

postconf -e 'myhostname ='
postconf -e 'mydestination =, localhost, localhost.localdomain'
postconf -e 'mynetworks ='
postconf -e 'virtual_alias_domains ='
postconf -e ' virtual_alias_maps = proxy:mysql:/etc/postfix/, mysql:/etc/postfix/'
postconf -e 'virtual_mailbox_domains = proxy:mysql:/etc/postfix/'
postconf -e 'virtual_mailbox_maps = proxy:mysql:/etc/postfix/'
postconf -e 'virtual_mailbox_base = /home/vmail'
postconf -e 'virtual_uid_maps = static:5000'
postconf -e 'virtual_gid_maps = static:5000'
postconf -e 'smtpd_sasl_auth_enable = yes'
postconf -e 'broken_sasl_auth_clients = yes'
postconf -e 'smtpd_sasl_authenticated_header = yes'
postconf -e 'smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination'
postconf -e 'smtpd_use_tls = yes'
postconf -e 'smtpd_tls_cert_file = /etc/postfix/smtpd.cert'
postconf -e 'smtpd_tls_key_file = /etc/postfix/smtpd.key'
postconf -e 'transport_maps = proxy:mysql:/etc/postfix/'
postconf -e 'virtual_create_maildirsize = yes'
postconf -e 'virtual_maildir_extended = yes'
postconf -e 'virtual_mailbox_limit_maps = proxy:mysql:/etc/postfix/'
postconf -e 'virtual_mailbox_limit_override = yes'
postconf -e 'virtual_maildir_limit_message = "The user you are trying to reach is over quota."'
postconf -e 'virtual_overquota_bounce = yes'
postconf -e 'proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps'
postconf -e 'inet_interfaces = all'

Afterwards we create the SSL certificate that is needed for TLS:

cd /etc/postfix
openssl req -new -outform PEM -out smtpd.cert -newkey rsa:2048 -nodes -keyout smtpd.key -keyform PEM -days 365 -x509

Country Name (2 letter code) [GB]: <-- Enter your Country Name (e.g., "DE").
State or Province Name (full name) [Berkshire]:
<-- Enter your State or Province Name.
Locality Name (eg, city) [Newbury]:
<-- Enter your City.
Organization Name (eg, company) [My Company Ltd]:
<-- Enter your Organization Name (e.g., the name of your company).
Organizational Unit Name (eg, section) []:
<-- Enter your Organizational Unit Name (e.g. "IT Department").
Common Name (eg, your name or your server's hostname) []:
<-- Enter the Fully Qualified Domain Name of the system (e.g. "").
Email Address []:
<-- Enter your Email Address.

Then change the permissions of the smtpd.key:

chmod o= /etc/postfix/smtpd.key

Share this page:

6 Comment(s)

Add comment


From: at: 2009-04-12 05:48:16

While building the RPMs for authlib and courier-imap, you may encounter an error saying that ltdl.h and fam.h are required (respectively). You can install these by doing the following:

ltdl.h-- Download and install the latest libtool and libtool-ltdl-devel packages from

fam.h--As root, run:

yum intall -y gamin-devel

 Since this tutorial is designed for Fedora 10, make sure you are getting the right build for your distribution.

 Hopefully this will save some of you some time, as it added about an extra 20 minutes to my install progress finding the source of the error and a way to fix it.

From: Anonymous at: 2009-03-05 03:34:30

mails are not getting delivered. they are stuck in deferred folder. any clue?

From: jonyssss at: 2009-06-28 23:42:52

Hi. I have a problem. When i want login to realy user and realy domain on my server then the imap was error.

Jun 29 01:35:31 $mydomain imapd: Connection, ip=[::ffff:]
Jun 29 01:35:31 $mydomain imapd: chdir $$user/: No such file or directory
Jun 29 01:35:31 $mydomain imapd: $user@$ No such file or directory

$mydomain is realy domain
$user is realy user

From: Anonymous at: 2009-08-20 03:27:26

For FC11 I downloaded the latest source files and found that they built to $HOME/rpm/RPMS/i586 rather than $HOME/rpm/RPMS/i386. I only diuscovered this when I tried to build courier-imap and it could not write the .rpm to the $HOME/rpm/RPMS/i586 folder as it had been created by sudo (root).

A quick chown and chgrp fixed it.

I presume that it would not have been a problem if I had created the $HOME/rpm/RPMS/i586 directory at the start of Step 4 above instead of $HOME/rpm/RPMS/i386.

From: at: 2009-08-01 03:10:50

If /var/log/maillog shows following error -

imapd: Connection, ip=[::ffff:]
imapd: authdaemon: s_connect() failed: Connection refused
imapd: [Hint: perhaps authdaemond is not running?]
imapd: LOGIN FAILED, user=<-user->, ip=[::ffff:]
imapd: authentication error: Connection refused

Try the following -

#mv /usr/sbin/authdaemond /usr/sbin/authdaemond.orig
#mv /etc/authlib /etc/authlib.orig

#vi /etc/init.d/courier-authlib
- change location of authdaemonrc in both places from  /etc/authlib/authdaemonrc to /usr/local/etc/authlib/authdaemonrc

- change sbindir="/usr/sbin" to sbindir="/usr/local/sbin"

save the file.

# rm -rf /usr/local/lib/courier-authlib/*.a

#rm -rf /usr/local/lib/courier-authlib/*.la

# /etc/init.d/courier-authlib stop

# /etc/init.d/courier-authlib start


File not found error in log files -

You should install the mysql runtime libraries.


ldd /usr/local/lib/courier-authlib/

This should show which mysql runtime libs need to be present.

From: at: 2009-04-12 17:25:31

While running the razor_admin commands at the top of the page, if you encounter an error saying " up," (my apologies, I did not write the exact error message, but this is the gist of it) it means you need to open port 2703 on your firewall. Once you have done this, try running the commands again and they should work.