In this tutorial, we will show you how to set up a mail server with PostfixAdmin on a Debian 9 VPS. We will configure a mail server with Postfix, Dovecot, and MariaDB.
PostfixAdmin is a web based GUI to the database that is used by Postfix. You can easily manage your mail server, like adding and removing domains, email accounts, aliases, and quotas through the use of Postfixadmin. The web-based GUI makes these functions and features more accessible, and allows you to change and access information while away from your terminal. Let’s get started.
Table of Contents
Prerequisites:
- a Debian 9 VPS
- SSH access with root privileges, or access to a user that has sudo privileges
Step 1: Log in via SSH and Update the System
Log in to your Debian 9 VPS:
# ssh root@IP_Address -p Port_number
You can check whether you have the proper Debian version installed on your server with the following command:
# lsb_release -a
You should get this output:
Distributor ID: Debian Description: Debian GNU/Linux 9.9 (Stretch) Release: 9.9 Codename: stretch
Then, run the following command to make sure that all installed packages on the server are updated to their latest available versions:
# apt update && apt upgrade
Step 2: Create a System User
For security reasons, we will create a new system user who will be the owner of all mailboxes.
# useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c "Virtual Mail User" vmail # mkdir -p /var/vmail # chmod -R 770 /var/vmail # chown -R vmail:mail /var/vmail
Step 3: Install MariaDB Server
PostfixAdmin supports MySQL/MariaDB, PostgreSQL, and SQLite database systems. In this tutorial, we will use MySQL/MariaDB as the database storage engine.
# apt install mariadb-server
To start the MariaDB service and enable it to start on boot, execute the following commands:
# systemctl start mariadb # systemctl enable mariadb
Now, you can skip the following step if you prefer not to have a MySQL root password.
# mysql_secure_installation
When prompted, answer the questions below by following the guide.
Enter current password for root (enter for none): Just press the [Enter] key since there is no default password Set root password? [Y/n]: Y New password: Enter password Re-enter new password: Repeat password Remove anonymous users? [Y/n]: Y Disallow root login remotely? [Y/n]: Y Remove test database and access to it? [Y/n]: Y Reload privilege tables now? [Y/n]: Y
If you followed the above step, then you would have a newly set password for MySQL root user.
Next, run this command to access the MySQL shell.
# mysql -u root -p
Remember to enter your root password if you ran the secure installation script.
Let’s proceed with creating a database for PostfixAdmin:
MariaDB [(none)]> CREATE DATABASE postfixadmin;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON postfixadmin.* TO 'postfixadmin'@'localhost' IDENTIFIED BY 'M0d1fyth15';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> \q
Make sure to replace the password for the database user to a good unique password.
Step 4: Install PHP and all Necessary PHP Modules
This is
apt install apache2 php php-mbstring php-imap php-mysql libapache2-mod-php7.0
Step 5: Install Postfix
Install Postfix with the command below:
# apt install postfix-mysql
Choose Internet Site and click on Ok to continue.
You will be asked for the system mail name, make sure this is the same with your hostname.
Once the installation is completed, we need to create configuration files:
# mkdir -p /etc/postfix/sql/
From here, several configuration files will be created. Make sure to replace any and all values that are different here to the necessary values, or your configuration may not work.
# nano /etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf
user = postfixadmin
password = M0d1fyth15
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
# nano /etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
user = postfixadmin
password = M0d1fyth15
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox,alias_domain WHERE alias_domain.alias_domain = '%d' and mailbox.username = CONCAT('%u', '@', alias_domain.target_domain) AND mailbox.active = 1 AND alias_domain.active='1'
# nano /etc/postfix/sql/mysql_virtual_alias_domain_maps.cf
user = postfixadmin
password = M0d1fyth15
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
# nano /etc/postfix/sql/mysql_virtual_alias_maps.cf
user = postfixadmin
password = M0d1fyth15
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
# nano /etc/postfix/sql/mysql_virtual_domains_maps.cf
user = postfixadmin
password = M0d1fyth15
hosts = localhost
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
# nano /etc/postfix/sql/mysql_virtual_mailbox_limit_maps.cf
user = postfixadmin
password = M0d1fyth15
hosts = localhost
dbname = postfixadmin
query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'
# nano /etc/postfix/sql/mysql_virtual_mailbox_maps.cf
user = postfixadmin
password = M0d1fyth15
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
In the configuration files above, we use ‘m0d1fyth15‘ as the password, please change it to your own password.
Now, let’s edit the main.cf
file by invoking the following commands:
postconf -e "myhostname = $(hostname -f)" postconf -e "virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf" postconf -e "virtual_alias_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf" postconf -e "virtual_mailbox_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf, proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf" postconf -e "smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem" postconf -e "smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key" postconf -e "smtpd_use_tls = yes" postconf -e "smtpd_tls_auth_only = yes" postconf -e "smtpd_sasl_type = dovecot" postconf -e "smtpd_sasl_path = private/auth" postconf -e "smtpd_sasl_auth_enable = yes" postconf -e "smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination" postconf -e "mydestination = localhost" postconf -e "mynetworks = 127.0.0.0/8" postconf -e "inet_protocols = ipv4" postconf -e "inet_interfaces = all" postconf -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"
Open the master.cf
file, find submission inet n
and smtps inet n
sections and edit as follows:
# nano /etc/postfix/master.cf
smtp inet n - y - - smtpd #smtp inet n - y - 1 postscreen #smtpd pass - - y - - smtpd #dnsblog unix - - y - 0 dnsblog #tlsproxy unix - - y - 0 tlsproxy submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes # -o smtpd_reject_unlisted_recipient=no # -o smtpd_client_restrictions=$mua_client_restrictions # -o smtpd_helo_restrictions=$mua_helo_restrictions # -o smtpd_sender_restrictions=$mua_sender_restrictions # -o smtpd_recipient_restrictions= # -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o smtpd_client_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING smtps inet n - y - - smtpd -o syslog_name=postfix/smtps # -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes # -o smtpd_reject_unlisted_recipient=no -o smtpd_client_restrictions=permit_sasl_authenticated,reject # -o smtpd_client_restrictions=$mua_client_restrictions # -o smtpd_helo_restrictions=$mua_helo_restrictions # -o smtpd_sender_restrictions=$mua_sender_restrictions # -o smtpd_recipient_restrictions= # -o smtpd_relay_restrictions=permit_sasl_authenticated,reject -o milter_macro_daemon_name=ORIGINATING
Enable and restart the Postfix service:
# systemctl enable postfix # systemctl restart postfix
Step 6: Install Dovecot
Install Dovecot using the command below:
# apt install dovecot-mysql
Open the /etc/dovecot/conf.d/10-mail.conf file and change the following values:
# nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/vmail/%d/%n mail_privileged_group = mail mail_uid = vmail mail_gid = mail first_valid_uid = 150 last_valid_uid = 150
Open the /etc/dovecot/conf.d/10-auth.conf file and change the following values:
# nano /etc/dovecot/conf.d/10-auth.conf
auth_mechanisms = plain login #!include auth-system.conf.ext !include auth-sql.conf.ext
Edit the dovecot-sql.conf.ext
file, then append these lines:
# nano /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=localhost dbname=postfixadmin user=postfixadmin password=M0d1fyth15
default_pass_scheme = MD5-CRYPT
password_query = SELECT username as user, password, '/var/vmail/%d/%n' as userdb_home, 'maildir:/var/vmail/%d/%n' as userdb_mail, 150 as userdb_uid, 8 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'
user_query = SELECT '/var/vmail/%d/%u' as home, 'maildir:/var/vmail/%d/%u' as mail, 150 AS uid, 8 AS gid, concat('dirsize:storage=', quota) AS quota FROM mailbox WHERE username = '%u' AND active = '1'
Remember to replace the password as well as any other different values here as well.
In the /etc/dovecot/conf.d/10-ssl.conf file, enable SSL support:
# nano /etc/dovecot/conf.d/10-ssl.conf
ssl = yes
Open the /etc/dovecot/conf.d/15-lda.conf file and set the postmaster_address
email address.
# nano /etc/dovecot/conf.d/15-lda.conf
postmaster_address = postmaster@yourdomain.com
Open the /etc/dovecot/conf.d/10-master.conf file, find the service lmtp section and change it to the following:
# nano /etc/dovecot/conf.d/10-master.conf
service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { mode = 0600 user = postfix group = postfix } }
find the service auth section and change it to:
service auth { unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } unix_listener auth-userdb { mode = 0600 user = vmail } user = dovecot }
Change the service auth-worker section to the following:
service auth-worker { user = vmail }
Set the permissions:
# chown -R vmail:dovecot /etc/dovecot # chmod -R o-rwx /etc/dovecot
Enable and restart the Dovecot service
# systemctl enable dovecot # systemctl restart dovecot
Step 7: Install PostfixAdmin
In this step, we will download PostfixAdmin from Github and store it in the /opt
directory.
# apt install git # cd /opt # git clone https://github.com/postfixadmin/postfixadmin.git # ln -s /opt/postfixadmin/public/ /var/www/html/mailadmin
Insert these lines to /opt/postfixadmin/config.local.php
# nano /opt/postfixadmin/config.local.php
<?php $CONF['database_type'] = 'mysqli'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = 'postfixadmin'; $CONF['database_password'] = 'M0d1fyth15'; $CONF['database_name'] = 'postfixadmin'; $CONF['configured'] = true; ?>
# mkdir /opt/postfixadmin/templates_c # chown -R www-data: /opt/postfixadmin
Connect to http://1.2.3.4/mailadmin/setup.php, making sure to replace 1.2.3.4 with your server actual IP address. If everything is okay, scroll down and create a setup password.
click on generate hash, and you will see this:
You need to paste the setup_password
hash as shown in the picture above to /opt/postfixadmin/config.local.php, it should look like this
<?php
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfixadmin';
$CONF['database_password'] = 'M0d1fyth15';
$CONF['database_name'] = 'postfixadmin';
$CONF['configured'] = true;
$CONF['setup_password'] = 'd7b5b4ed7e91d81f246d802a6f09474a:69478ddf65feb4036215cb2c6f48c3dfd815ee8c';
?>
Save the file, then you can go back to the setup page to create a PostfixAdmin admin user. The setup password in that page is the same password you used in the previous step – fill the other blanks as you wish, then click on the ‘Add admin’ button.
Now, you can go to http://1.2.3.4/mailadmin/login.php
to add your domains and create email addresses there.
That’s it! You now have PostfixAdmin set up and running on your Debian 9 server.
Of course, you don’t have to set up a mail server with PostfixAdmin on Debian 9 if you use one of our Mail Server Hosting services, in which case you can simply ask our expert Linux admins to set up a mail server for you. They are available 24×7 and will take care of your request immediately.
PS. If you liked this post on how to set up a mail server with PostfixAdmin on Debian 9, or if you found it helpful, please share it with your friends on the social networks using the share shortcuts, or simply leave a comment in the Comments Section below. Thanks.
works also on Debian 10
foolproof guide ; works flawlessly !
unfortunately no https part in this howto
I followed your guide, and I am having issues with my users on looking for mail. I perhaps missed something on my configs. Dovecot is looking for the mailbox at /var/vmail/mydomain.com/user@mydomain.com yet the mailbox is at var/vmail/mydomain.com/user. I am not sure what I did wrong in my configs:
May 6 20:29:59 serverhostname dovecot: pop3(user@mydomain.com): Debug: Effective uid=150, gid=8, home=/var/vmail/mydomain.com/user@mydomain.com
May 6 20:29:59 serverhostname dovecot: pop3(user@mydomain.com): Debug: Namespace inbox: type=private, prefix=, sep=, inbox=yes, hidden=no, list=yes, subscriptions=yes location=maildir:/var/vmail/mydomain.com/user@mydomain.com
May 6 20:29:59 serverhostname dovecot: pop3(user@mydomain.com): Debug: maildir++: root=/var/vmail/mydomain.com/user@mydomain.com, index=, indexpvt=, control=, inbox=/var/vmail/mydomain.com/user@mydomain.com, alt=
Please helps
Check the mail location set on /etc/dovecot/conf.d/10-mail.conf.
For Kazishe et al, there is a mistake in the given config for /etc/dovecot/dovecot-sql.conf.ext where password_query and user_query are using two different directory formats.
password_query is using /var/vmail/%d/%n as the maildir, but user_query is using /var/vmail/%d/%u
%n expands to “user”, where %u expands to “user@domian.tld”. This is probably why there are issues with Dovecot saving under a different directory than it is later looking for the messages in. You need to make them both the same with %n. Better yet, use /var/vmail/%Ld/%Ln so that the domain and username are lower-cased. This way if a message gets through with a uSeR@domain.tld it doesn’t get stored in a different directory from user@domain.tld.
Here is the full file:
# /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=/var/run/mysqld/mysqld.sock dbname=postfix user=postfix password=PICKAPASSWORD
default_pass_scheme = MD5-CRYPT
password_query = SELECT username as user, password, ‘/var/vmail/%Ld/%Ln’ as userdb_home, ‘maildir:/var/vmail/%Ld/%Ln’ as userdb_mail, 150 as userdb_uid, 8 as userdb_gid FROM mailbox WHERE username = ‘%u’ AND active = ‘1’
user_query = SELECT ‘/var/vmail/%Ld/%Ln’ as home, ‘maildir:/var/vmail/%Ld/%Ln’ as mail, 150 AS uid, 8 AS gid, concat(‘dirsize:storage=’, quota) AS quota FROM mailbox WHERE username = ‘%u’ AND active = ‘1’
iterate_query = SELECT username AS user FROM mailbox WHERE active = ‘1’ ORDER BY username
Hi friends,
I’m having trouble after following your guide. I configure an email account with imap and try to send an email, it tells me the following message “Your message was sent but a copy was not placed in the sent folder (Sent)”
No errors are seen from the server.
Can you help me?
Thanks
Please try to follow the steps again, and check if something is missing in the configuration files.
I’m check the dovecot.conf and have this config rules
my dovecot -n is :
# Pigeonhole version 0.5.4 ()
# OS: Linux 4.19.0-16-amd64 x86_64 Debian 10.9 ext4
# Hostname: mail.xxxxx.com
auth_debug = yes
auth_debug_passwords = yes
auth_mechanisms = plain login
auth_verbose = yes
auth_verbose_passwords = yes
debug_log_path = /var/log/dovecot-debug
log_path = /var/log/dovecot
mail_debug = yes
mail_location = maildir:/var/mail/%d/%n:INDEX=/var/mail/%d/%n/indexes
mail_privileged_group = mail
namespace inbox {
inbox = yes
location =
mailbox Drafts {
special_use = \Drafts
}
mailbox Enviados {
special_use = \Sent
}
mailbox Junk {
special_use = \Junk
}
mailbox Sent {
special_use = \Sent
}
mailbox «Sent Messages» {
special_use = \Sent
}
mailbox Trash {
special_use = \Trash
}
prefix =
separator = .
}
passdb {
args = /etc/dovecot/dovecot-mysql.conf.ext
driver = sql
}
plugin {
sieve = file:~/sieve;active=~/.dovecot.sieve
}
protocols = » imap lmtp pop3 lmtp»
service auth-worker {
user = vmail
}
service auth {
unix_listener /var/spool/postfix/private/auth {
group = postfix
mode = 0666
user = postfix
}
unix_listener auth-userdb {
mode = 0600
user = vmail
}
user = dovecot
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
group = postfix
mode = 0600
user = postfix
}
}
service stats {
unix_listener stats-reader {
group = vmail
mode = 0660
user = vmail
}
unix_listener stats-writer {
group = vmail
mode = 0660
user = vmail
}
}
ssl_cert = </etc/letsencrypt/live/mail.xxxxx.com/fullchain.pem
ssl_client_ca_dir = /etc/ssl/certs
ssl_dh = # hidden, use -P to show it
ssl_key = # hidden, use -P to show it
userdb {
args = /etc/dovecot/dovecot-mysql.conf.ext
driver = sql
}
protocol lmtp {
mail_plugins = " sieve"
}
protocol lda {
mail_plugins = " quota sieve"
postmaster_address = admin@xxxx.com
}
protocol imap {
mail_max_userip_connections = 10
}
I can't find the error
Please check your mail log for errors.
I did this and works flawless. One issue I had was the current git repository for postfixadmin, the encryption is set to phpcrypt instead of md5crypt that dovecot is using, so that causes the client to not authenticate.