Dedicated Mail Server Hosting Multiple Domains – Step 3 – Postfix and Dovecot
On a typical Linux mail server mail is stored on the disk either using one big file in /var/mai/%user either in one Maildir in users’s home folder. This Maildir usually contains one small file for each mail stored on your server and some indexing information etc.
In this setup, because users are stored on a virtual manner (in an SQL database) we need to create a user on the system, to which all the Maildirs will belong to.
adduser mails --shell=/usr/sbin/nologin
This will create a user that has “nologin” shell. There’s no need to set a password for it, as we will never use it for SSH login and by default ssh does not allow you to login remotely using empty passwords.
One of the most important sub-steps here is to get this user’s UID. For example I did not create any user on CentOS install, so my new user’s ID is 1000, it also gas GID 1000. This is important becautse your mail server will use this ID to store and access files.
We need to create a new SQL user to be used by Postfix MTA and Dovecot as the one used by Postfix Admin has write permissions and for this one there’s no need. After launching from the shell mysql -p and entering the password:
grant select on postfix.* to postfix@localhost identified by 'POSTFIX_PASSWORD'; flush privileges;
Then we start creating SQL config files for Postfix in /etc/postfix as follows:
mysql_virtual_alias_maps.cf
user = postfix password = POSTFIX_PASSWORD hosts = 127.0.0.1 dbname = postfix query = SELECT goto FROM alias WHERE address='%s' AND active = 1
mysql_virtual_domains_maps.cf
user = postfix password = POSTFIX_PASSWORD hosts = 127.0.0.1 dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'
mysql_virtual_mailbox_maps.cf
user = postfix password = POSTFIX_PASSWORD hosts = 127.0.0.1 dbname = postfix query = SELECT maildir FROM mailbox WHERE username='%s' AND active = 1
mysql_relay_domains_maps.cf
user = postfix password = POSTFIX_PASSWORD hosts = 127.0.0.1 dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1'
Then in Postfix’s main.cf
virtual_alias_maps = proxy:mysql:/etc/postfix/mysql_virtual_alias_maps.cf virtual_gid_maps = static:1000 virtual_mailbox_base = /home/mails virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql_virtual_domains_maps.cf virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf relay_domains = $mydestination, proxy:mysql:/etc/postfix/mysql_relay_domains_maps.cf virtual_minimum_uid = 1000 virtual_transport = dovecot virtual_uid_maps = static:1000
and in master.cf add the lines:
dovecot unix - n n - - pipe flags=DRhu user=mails:mails argv=/usr/libexec/dovecot/dovecot-lda -f ${sender} -d ${recipient}
The next step is Dovecot. It is important to set it up as Postfix uses Dovecot LDA to deliver mail. After a simple yum install dovecot dovecot-mysql we need to change directory to /etc/dovecot/conf.d where we edit some files as follows:
10-auth.conf
disable_plaintext_auth = no # some people just don' bother auth_mechanisms = plain login # Otherwise Windows 8/8.1's Mail app won't authenticate #!include auth-system.conf.ext # comment this line !include auth-sql.conf.ext #uncomment this one
15-lda.conf
lda_mailbox_autocreate = yes lda_mailbox_autosubscribe = yes
10-mail.conf
mail_location = maildir:/home/mails/%u:INDEX=/home/mails/%u/index
/etc/dovecot/dovecot-sql.conf.ext
driver = mysql connect = host=localhost dbname=postfix user=postfix password=$POSTFIX_PASSWORD password_query = SELECT password FROM mailbox WHERE username = '%u' user_query = SELECT username, 1000 AS uid, 1000 AS gid , '/home/mails/%u' as home FROM mailbox WHERE username = '%u'
Instead of 1000 you might put in the UID/GID from the user you created.
Have you added a new domain in your Postfix Admin interface? How about a new user? it is time to send him a test mail.
echo test |mail -s test USER@DOMAIN.COM
Now tail your mailllog. tail /var/log/maillog should show you something like:
Sep 6 12:31:46 mail postfix/qmgr[32482]: C44CD80BBFFE: from=<root@mail.cheriches.com>, size=438, nrcpt=1 (queue active) Sep 6 12:31:46 mail dovecot: lda(emil@cheriches.com): msgid=<20140906085511.C44CD80BBFFE@mail.cheriches.com>: saved mail to INBOX Sep 6 12:31:46 mail postfix/pipe[365]: C44CD80BBFFE: to=<emil@cheriches.com>, relay=dovecot, delay=5880, delays=5880/0.02/0/0.22, dsn=2.0.0, status=sent (delivered via dovecot service)
So, right now you have a functional email server, meaning that you are able to send and receive mail, but there’s still a lot of work to be done.
And if mails user isnt my first user?
I get this error in mailin file:
Oct 25 00:42:23 my-vps dovecot: auth: Error: userdb(example@mail.com): client doesn’t have lookup permissions for this user: userdb uid (1000) doesn’t match peer uid (1002) (to bypass this check, set: service auth { unix_listener /var/run/dovecot/auth-userdb { mode=0777 } })
Oct 25 00:42:23 my-vps dovecot: lda: Error: user example@mail.com: Auth USER lookup failed
Oct 25 00:42:23 my-vps dovecot: lda: Fatal: Internal error occurred. Refer to server log for more information.
Oct 25 00:42:23 my-vps postfix/pipe[27566]: BA9AE42461: to=, relay=dovecot, delay=0.14, delays=0.07/0.01/0/0.05, dsn=4.3.0, status=deferred (temporary failure)
I read that i have to modify /var/run/dovecot/auth-userdb , its true?
I’ am very newly with this, sory
I am a stupid haha, it was only I forget to modify the correct UID for the user mails in /etc/dovecot/dovecot-sql.conf.ext.
To get the UID for user mails run in ssh:
cat /etc/passwd | grep "^mails:" | cut -d":" -f3
Thanks for putting together this guide. But I am running into a roadblock on the test message. I followed the guide up until the end of this page, and then logged into the postfixadmin site and added the virtual domain and virtual user. And yes I do have the DNS setup already as well, its routeable to the host and there is an mx record thats appropriate. I get the following errors in /var/log/maillog:
Mar 20 05:16:03 mx dovecot: auth-worker(3811): Error: mysql: Query timed out (no free connections for 60 secs): SELECT username, 1000 AS uid, 1000 AS gid , ‘/home/mails/andrew@andrewschott.com’ as home FROM mailbox WHERE username = ‘andrew@andrewschott.com’
Mar 20 05:16:03 mx dovecot: auth-worker(3811): Error: sql(andrew@andrewschott.com): User query failed: Not connected to database
Mar 20 05:16:03 mx dovecot: auth: Error: auth worker: Aborted request: Lookup timed out
Mar 20 05:16:03 mx dovecot: lda: Error: user andrew@andrewschott.com: Auth USER lookup failed
Mar 20 05:16:03 mx dovecot: lda: Fatal: Internal error occurred. Refer to server log for more information.
Mar 20 05:16:03 mx dovecot: auth-worker(3821): Error: mysql(localhost): Connect failed to database (postfix): Access denied for user ‘postfix’@’localhost’ (using password: YES) – waiting for 1 seconds before retry
Mar 20 05:16:03 mx postfix/pipe[3807]: 34CE33CE0: to=, relay=dovecot, delay=60, delays=0.05/0.01/0/60, dsn=4.3.0, status=deferred (temporary failure)
Mar 20 05:16:04 mx dovecot: auth-worker(3821): Error: mysql(localhost): Connect failed to database (postfix): Access denied for user ‘postfix’@’localhost’ (using password: YES) – waiting for 5 seconds before retry
Mar 20 05:16:09 mx dovecot: auth-worker(3821): Error: mysql(localhost): Connect failed to database (postfix): Access denied for user ‘postfix’@’localhost’ (using password: YES) – waiting for 25 seconds before retry
It looks as you have a problem connecting to the SQL server.
Try connecting from the shell with “mysql -u postfix -p” then run something like “show processlist;” to see if you really have to many opened connections.
Another thing to look for is SELinux, try setting it to permissive(“setenforce 0” as root) and see if it works this way.
Thanks for the tips. Firstly, SELinux is off as this is a vps using some backend that prevents it.
[root@mx ~]# sestatus
SELinux status: disabled
[root@mx ~]#
As for the mysql stuff, not very familiar with that command, but here it goes. I booted the vps, did the test mail message command (the piped one from above) and then did the show processlist, It looks like this:
MariaDB [(none)]> show processlist;
+—-+———+—————–+———+———+——+——-+——————+———-+
| Id | User | Host | db | Command | Time | State | Info | Progress |
+—-+———+—————–+———+———+——+——-+——————+———-+
| 2 | postfix | localhost | NULL | Query | 0 | NULL | show processlist | 0.000 |
| 3 | postfix | localhost:48496 | postfix | Sleep | 22 | | NULL | 0.000 |
| 4 | postfix | localhost:48498 | postfix | Sleep | 22 | | NULL | 0.000 |
| 5 | postfix | localhost:48500 | postfix | Sleep | 22 | | NULL | 0.000 |
+—-+———+—————–+———+———+——+——-+——————+———-+
4 rows in set (0.00 sec)
MariaDB [(none)]>
You should also run in MySQL:
show variables like ‘max_connections’;
MariaDB [(none)]> show variables like “max_connections”;
+—————–+——-+
| Variable_name | Value |
+—————–+——-+
| max_connections | 151 |
+—————–+——-+
1 row in set (0.00 sec)
MariaDB [(none)]>
Hello good day Thank you for your tutorial excelnte mail and domain. But I was a problem with the alias domains : Recipient address rejected : User unknown in virtual mailbox table ; could you help me with this Thanks and Regards