How to Set Up a Mail Server with Postfix, Dovecot and PostfixAdmin on Debian 11
Here I will document building a new mail server to replace my existing server. I will install this in a virtual server on my ProxMox server. My hardware requirements are very minimal. I will create a container with a 100GB drive capacity, 8GB of ram and 4 CPU cores.
The server OS will be Debian 11. I will be using Postfix as my MTA, Dovecot as my client authentication server for both IMAP and Pop3. The DB will be MariaDB. I will use PostfixAdmin to manage the entire install.
Prerequisites
Log in to your Debian 11 Server through SSH as a root user or as a regular user that has sudo privileges.
ssh user@hostname
To update the system, you can run this command:
sudo apt update
sudo apt upgrade
You would need to create a DNS A record for your hostname because the server hostname should be an FQDN. For example, we will create debian11.yourdomain.com as the server hostname, let’s run this command:
sudo hostnamectl set-hostname debian11.yourdomain.com
The above command is just an example, you would need to use your own registered domain name to create a hostname.
Now, let’s install the webserver, database server, and PHP
sudo apt install apache2 mariadb-server php-{xml,pear,imap,intl,common,json,curl,mbstring,mysql,gd,imagick,zip,opcache,sqlite3} libapache2-mod-php
When creating the system user be mindfull of the available space the users partition is going to be created on. Make sure you have enough space to house the volumn of email that will be received by all mail recipents. Personally, I chose /home as my base. /home is normally one of the first secondary partitions I create when installing a new system.
Let’s run the following commands to create a system user called ‘vmail’ and create a directory and give the proper permission.
sudo useradd -r -u 150 -g mail -d /home/vmail -s /sbin/nologin -c "Virtual Mail User" vmail
sudo mkdir -p /home/vmail
sudo chmod -R 770 /home/vmail
sudo chown -R vmail:mail /home/vmail
If your MySQL root user does not have a password, you can run this command to log in to the MySQL shell.
sudo mysql
If a password is required to log in to MySQL shell, then run this command:
mysql -u root -p
Once logged in, let’s run the following commands:
MariaDB [(none)]> CREATE DATABASE postfixadmin;
MariaDB [(none)]> GRANT ALL PRIVILEGES ON postfixadmin.* TO 'pfadmin'@'localhost' IDENTIFIED BY 'Pa$$W0rd';
MariaDB [(none)]> FLUSH PRIVILEGES;
MariaDB [(none)]> \q
Install Postfix mail server with this command:
sudo apt install postfix-mysql
Once executes, you will see the following set up a mail server with PostfixAdmin on Debian 11
Choose Internet Site then hit Ok to continue
In this step, you will be asked for the system mail name, make sure the system mail name is the same as your Debian 11 hostname. We set the system hostname at the beginning of this tutorial.
Once completed we need to create several configuration files for Postfix to communicate with the database.
sudo mkdir -p /etc/postfix/sql
Let’s create the files, make sure to replace the password, database name, database user with the ones you created earlier.
sudo nano /etc/postfix/sql/mysql_virtual_alias_maps.cf
user = pfadmin
password = Pa$$W0rd
hosts = localhost
dbname = postfixadmin
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
sudo nano /etc/postfix/sql/mysql_virtual_domains_maps.cf
user = pfadmin
password = Pa$$W0rd
hosts = localhost
dbname = postfixadmin
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
sudo nano /etc/postfix/sql/mysql_virtual_mailbox_maps.cf
user = pfadmin
password = Pa$$W0rd
hosts = localhost
dbname = postfixadmin
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_maps.cf
user = pfadmin
password = Pa$$W0rd
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'
sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf
user = pfadmin
password = Pa$$W0rd
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'
sudo nano /etc/postfix/sql/mysql_virtual_mailbox_limit_maps.cf
user = pfadmin
password = Pa$$W0rd
hosts = localhost
dbname = postfixadmin
query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'
sudo nano /etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf
user = pfadmin
password = Pa$$W0rd
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'
Let us now proceed with editing /etc/postfix/main.cf file, we can run the following commands:
sudo postconf -e "myhostname = $(hostname -f)"
sudo postconf -e "mydestination = localhost"
sudo postconf -e "mynetworks = 127.0.0.0/8"
sudo postconf -e "inet_protocols = ipv4"
sudo postconf -e "inet_interfaces = all"
sudo postconf -e "smtpd_tls_cert_file = /etc/ssl/certs/ssl-cert-snakeoil.pem"
sudo postconf -e "smtpd_tls_key_file = /etc/ssl/private/ssl-cert-snakeoil.key"
sudo postconf -e "smtpd_use_tls = yes"
sudo postconf -e "smtpd_tls_auth_only = yes"
sudo postconf -e "smtpd_sasl_type = dovecot"
sudo postconf -e "smtpd_sasl_path = private/auth"
sudo postconf -e "smtpd_sasl_auth_enable = yes"
sudo postconf -e "smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination"
sudo postconf -e "virtual_transport = lmtp:unix:private/dovecot-lmtp"
sudo postconf -e "virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf"
sudo 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"
sudo 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"
Once completed, we can continue and edit /etc/postfix/master.cf file:
sudo nano /etc/postfix/master.cf
Modify or add the following lines to the file.
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
Save the changes then exit.
sudo apt install dovecot-mysql dovecot-imapd dovecot-pop3d dovecot-lmtpd
Once dovecot is installed, we need to edit some configuration files.
Open the /etc/dovecot/conf.d/10-auth.conf file
$ sudo nano /etc/dovecot/conf.d/10-auth.conf
Then find this line
auth_mechanisms = plain
replace it with this line:
auth_mechanisms = plain login
Then, comment !include auth-system.conf.ext and uncomment #!include auth-sql.conf.ext
It should look like this:
#!include auth-system.conf.ext
!include auth-sql.conf.ext
In the 10-auth.conf file, we include auth-sql.conf.ext. So, let’s edit the file
$ sudo nano /etc/dovecot/dovecot-sql.conf.ext
then append these lines:
driver = mysql
connect = host=localhost dbname=postfixadmin user=pfadmin password=Pa$$W0rd
default_pass_scheme = MD5-CRYPT
password_query = SELECT username as user, password, '/home/vmail/%d/%n' as userdb_home, 'maildir:/home/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 '/home/vmail/%d/%u' as home, 'maildir:/home/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'
The lines above contain the database credentials, make sure they match the ones you created in the previous step.
Save the file and exit
Next, open the /etc/dovecot/conf.d/10-mail.conf file and modify the following values:
$ sudo nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/home/vmail/%d/%n
mail_uid = vmail
mail_gid = mail
mail_privileged_group = mail
first_valid_uid = 150
last_valid_uid = 150
By default, dovecot SSL support in Debian 11 is enabled. You can verify it by checking the file /etc/dovecot/conf.d/10-ssl.conf, make sure it has this line:
ssl = yes
If you want to edit the postmaster email address, you can edit the file /etc/dovecot/conf.d/15-lda.conf and find the postmaster_address line. By default, the postmaster email address would be postmaster@yourdomain.com. So, if you want to receive the postmaster email at admin@yourdomain.com, then you need to add this line:
postmaster_address = admin@yourdomain.com
Now, let’s proceed with editing other dovecot configuration files.
sudo nano /etc/dovecot/conf.d/10-master.conf
There are several changes you need to make to this file.
Find the service lmtp section and change it to the following:
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
}
Do not forget to save the file then exit
Before restarting Dovecot, we need to change the permissions.
sudo chown -R vmail:dovecot /etc/dovecot
sudo chmod -R o-rwx /etc/dovecot
sudo systemctl restart postfix dovecot
In this final step, we will download PostfixAdmin from Github and store it in the /opt directory.
sudo apt install git
cd /opt
sudo git clone https://github.com/postfixadmin/postfixadmin.git
cd /opt/postfixadmin
sudo ./install.sh
sudo chown -R www-data. /opt/postfixadmin
We are not going to use a subdomain to access PostfixAdmin through a web browser, we will use an Apache alias instead.
sudo nano /etc/apache2/conf-enabled/postfixadmin.conf
Paste the following into the file then reload apache.
Alias /postfixadmin /opt/postfixadmin/public
<Directory "/opt/postfixadmin/public">
AllowOverride All
Options +FollowSymLinks
Require all granted
</Directory>
sudo systemctl reload apache2
Create config.local.php and insert the following lines
sudo nano /opt/postfixadmin/config.local.php
<?php
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'pfadmin';
$CONF['database_password'] = 'Pa$$W0rd';
$CONF['database_name'] = 'postfixadmin';
$CONF['configured'] = true;
?>
Go to http://YOUR_SERVER_IP_ADDRESS/postfixadmin/setup.php and create a setup password. If you already have a website on your server, you can also access PostfixAdmin at http://yourdomain.com/postfixadmin/setup.php
Type your setup password twice and click on the ‘Generate setup_password hash’ button.
You will see a line containing a setup password like this:
$CONF['setup_password'] = '$2y$10$xlKkztMcpu6C3//ZqPZM1.pTGjGD5oEn0KtBlbSl9VFDycxPNH1M2';
and you need to copy it to config.local.php
<?php
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'pfadmin';
$CONF['database_password'] = 'Pa$$W0rd';
$CONF['database_name'] = 'postfixadmin';
$CONF['configured'] = true;
$CONF['setup_password'] = '$2y$10$xlKkztMcpu6C3//ZqPZM1.pTGjGD5oEn0KtBlbSl9VFDycxPNH1M2';
?>
After adding the line to config.local.php file, you can refresh the page to log in and create a superadmin.
That’s it, after successfully adding a superadmin, you can use the credentials to log in to http://YOUR_SERVER_IP_ADDRESS/postfixadmin/login.php to add domains, email accounts, and any other email management tasks there.