In this article we will walk you through the installation and configuration of a mail server with virtual domains and users using Postfix, Dovecot and OpenDKIM on an Ubuntu VPS. By using virtual domains and users, you can set up unlimited email accounts without creating system users. This should work on other Linux VPS systems as well but was tested and written for Ubuntu.
Set the Hostname & FQDN
To check the existing FQDN, run the following command
hostname -f
which should display something like localhost or host.domain.com If you see localhost, proceed with the following steps:
- Add your FQDN to the /etc/hosts file
- Add your FQDN to the /etc/hostname file and run
service hostname start
Install all the necessary packages
debconf-set-selections <<< "postfix postfix/mailname string $(hostname -f)" debconf-set-selections <<< "postfix postfix/main_mailer_type string 'Internet Site'" apt-get update apt-get install -y procmail postfix dovecot-core dovecot-pop3d dovecot-imapd opendkim opendkim-tools
Create a Virtual Email user
groupadd -g 5000 vmail useradd -u 5000 -g vmail -s /sbin/nologin -d /home/vmail -m vmail usermod -aG vmail postfix usermod -aG vmail dovecot DOMAIN="yourDomain.com" mkdir -p /var/mail/vhosts/${DOMAIN} chown -R vmail:vmail /var/mail/vhosts chmod -R 775 /var/mail/vhosts
Generate SSL Certificate
SSL_DIR="/etc/dovecot/ssl" # Certificate details; replace items in angle brackets with your own info SUBJ=" C=US ST=New York O=${DOMAIN} localityName=NYC commonName=${DOMAIN} organizationalUnitName=IT emailAddress=admin@${DOMAIN} " # Empty passphrase PASSPHRASE="" # Makedir for certs mkdir -p ${SSL_DIR} # Generate the server private key openssl genrsa -out "${SSL_DIR}/${DOMAIN}.key" 2048 # Generate the CSR openssl req \ -new \ -batch \ -subj "$(echo -n "$SUBJ" | tr "\n" "/")" \ -key "${SSL_DIR}/${DOMAIN}.key" \ -out "${SSL_DIR}/${DOMAIN}.csr" \ -passin env:PASSPHRASE # Generate the cert (good for 10 years) openssl x509 -req -days 3650 -in "${SSL_DIR}/${DOMAIN}.csr" -signkey "${SSL_DIR}/${DOMAIN}.key" -out "${SSL_DIR}/${DOMAIN}.crt"
Configure OpenDKIM
OPENDKIM_DIR="/etc/opendkim/keys/" # MY_IP MY_IP=$(ip route get 8.8.8.8 | awk '/8.8.8.8/ {print $NF}') mkdir -p ${OPENDKIM_DIR}/${DOMAIN} opendkim-genkey -r -s default -d ${DOMAIN} -D ${OPENDKIM_DIR}/${DOMAIN} cat > /etc/opendkim.conf <<EOF AutoRestart Yes UMask 002 Syslog yes AutoRestartRate 10/1h Canonicalization relaxed/simple ExternalIgnoreList refile:/etc/opendkim/TrustedHosts InternalHosts refile:/etc/opendkim/TrustedHosts KeyTable refile:/etc/opendkim/KeyTable LogWhy Yes Mode sv PidFile /var/run/opendkim/opendkim.pid SignatureAlgorithm rsa-sha256 SigningTable refile:/etc/opendkim/SigningTable Socket inet:8891@localhost SyslogSuccess Yes TemporaryDirectory /var/tmp UserID opendkim:opendkim EOF cat > /etc/opendkim/TrustedHosts <<EOF 127.0.0.1 localhost ${DOMAIN} ${MY_IP} EOF cat > /etc/opendkim/SigningTable <<EOF *@${DOMAIN} default._domainkey.${DOMAIN} EOF cat > /etc/opendkim/KeyTable <<EOF default._domainkey.${DOMAIN} ${DOMAIN}:default:/etc/opendkim/keys/${DOMAIN}/default.private EOF chown -R opendkim: /etc/opendkim
Configure Postfix
# Configure postfix main.cf postconf -e "smtpd_banner = \$myhostname ESMTP" postconf -e "mydomain = ${DOMAIN}" postconf -e "myorigin = \$mydomain" postconf -e "mydestination = localhost, localhost.localdomain, $(hostname -f)" postconf -e "virtual_mailbox_domains = /etc/postfix/virtual_domains" postconf -e "virtual_mailbox_base = /var/mail/vhosts" postconf -e "virtual_mailbox_maps = hash:/etc/postfix/vmailbox" postconf -e "virtual_alias_maps = hash:/etc/postfix/virtual_alias" postconf -e "virtual_minimum_uid = 100" postconf -e "virtual_uid_maps = static:5000" postconf -e "virtual_gid_maps = static:5000" postconf -e "virtual_transport = virtual" postconf -e "dovecot_destination_recipient_limit = 1" postconf -e "smtpd_sasl_auth_enable = yes" postconf -e "smtpd_sasl_type = dovecot" postconf -e "smtpd_sasl_path = private/auth" postconf -e "smtpd_sasl_security_options = noanonymous" postconf -e "smtpd_sasl_local_domain = \$mydomain" postconf -e "broken_sasl_auth_clients = yes" postconf -e "smtpd_tls_security_level = may" postconf -e "smtpd_tls_auth_only = no" postconf -e "smtpd_tls_cert_file=${SSL_DIR}/${DOMAIN}.crt" postconf -e "smtpd_tls_key_file=${SSL_DIR}/${DOMAIN}.key" postconf -e "smtpd_tls_received_header = yes" postconf -e "tls_random_source = dev:/dev/urandom" postconf -e "smtpd_tls_security_level = may" postconf -e "smtp_tls_security_level = may" postconf -e "smtpd_client_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_invalid_hostname, reject_unknown_client, reject_rbl_client sbl-xbl.spamhaus.org" postconf -e "smtpd_sender_restrictions = permit_mynetworks, reject_unknown_address, reject_unknown_sender_domain, reject_non_fqdn_sender" postconf -e "smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination" postconf -e "smtpd_recipient_limit = 250" postconf -e "milter_default_action = accept" postconf -e "milter_protocol = 6" postconf -e "smtpd_milters = inet:127.0.0.1:8891" postconf -e "non_smtpd_milters = inet:127.0.0.1:8891" # Configure postfix master.cf sed -i '/^#smtpd.*/ s/^#//' /etc/postfix/master.cf vi /etc/postfix/master.cf # Add the following lines at the end: dovecot unix - n n - - pipe flags=DRhu user=vmail:vmail argv=/usr/lib/dovecot/deliver -f ${sender} -d ${recipient} cat > /etc/postfix/virtual_alias <<EOF # Example # @${DOMAIN} admin@${DOMAIN} EOF postmap /etc/postfix/virtual_alias cat > /etc/postfix/virtual_domains <<EOF ${DOMAIN} OK EOF postmap /etc/postfix/virtual_domains touch /etc/postfix/vmailbox postmap /etc/postfix/vmailbox
Configure Dovecot
cat > /etc/dovecot/dovecot.conf <<EOF auth_mechanisms = plain login disable_plaintext_auth = no log_path = /var/log/dovecot mail_location = maildir:/var/mail/vhosts/%d/%n passdb { args = /var/mail/vhosts/%d/shadow driver = passwd-file } protocols = imap pop3 service auth { unix_listener /var/spool/postfix/private/auth { group = vmail mode = 0660 user = postfix } unix_listener auth-master { group = vmail mode = 0600 user = vmail } } ssl_cert = <${SSL_DIR}/${DOMAIN}.crt ssl_key = <${SSL_DIR}/${DOMAIN}.key userdb { args = /var/mail/vhosts/%d/passwd driver = passwd-file } protocol lda { auth_socket_path = /var/run/dovecot/auth-master hostname = $(hostname -f) mail_plugin_dir = /usr/lib/dovecot/modules mail_plugins = sieve postmaster_address = postmaster@${DOMAIN} } EOF touch /var/log/dovecot chgrp vmail /var/log/dovecot chmod 660 /var/log/dovecot
Restart all services
service dovecot restart service postfix restart service opendkim restart
That’s it! If you followed all steps correctly, your email server should be fully functional.
Adding new email accounts
You can use the following script to add a new email account. Save the script as ‘add_new_account’, use chmod to make it executable and then run it passing two parameters:
./add_new_account <email@account> <password>
#!/bin/bash # sudo ./add_new_account <email@account> <password> # Functions ok() { echo -e '\e[32m'${1}'\e[m'; } # Green die() { echo -e '\e[1;31m'${1}'\e[m'; exit 1; } # Red # Sanity check [ $(id -g) != "0" ] && die "Script must be run as root." [ $# != "2" ] && die "Usage: $(basename $0) email@account password" [ ! -f /usr/sbin/postfix ] && die "Postfix is not installed" [ ! -f /usr/bin/doveadm ] && die "Dovecot is not installed" # Variables VMAIL=vmail VMAIL_UID=5000 VMAIL_GUID=5000 ADDRESS=${1} PASSWD=${2} USERNAME=${ADDRESS%@*} DOMAIN=${ADDRESS##*@} # Get the Mailbox Base Directory BASEDIR=$(postconf virtual_mailbox_base) BASEDIR=${BASEDIR#*= } # Get the Mailbox Maps File MAPSFILE=$(postconf virtual_mailbox_maps) MAPSFILE=${MAPSFILE#*:} # Check if account exist if grep -wq "^${ADDRESS}" ${MAPSFILE} then die "The mail address ${ADDRESS} already exist" fi if [[ ( -f ${MAPSFILE} && -d ${BASEDIR} ) ]]; then echo "$ADDRESS $DOMAIN/$USERNAME/" >> ${MAPSFILE} postmap ${MAPSFILE} if [[ $? -eq 0 ]]; then echo ${ADDRESS}::${VMAIL_UID}:${VMAIL_GUID}::${BASEDIR}/${DOMAIN}/${ADDRESS} >> ${BASEDIR}/${DOMAIN}/passwd echo ${ADDRESS}":"$(doveadm pw -p $PASSWD) >> ${BASEDIR}/${DOMAIN}/shadow chown ${VMAIL}: $BASEDIR/${DOMAIN}/{passwd,shadow} chmod 775 ${BASEDIR}/${DOMAIN}/{passwd,shadow} service postfix reload ok "The email account has been addedd" fi else die "Mailbox maps file or mailbox base directory doesn't exist" fi
Of course you don’t have to do any of this if you use one of our Linux VPS Hosting services, in which case you can simply ask our expert Linux admins to setup this for you. They are available 24×7 and will take care of your request immediately.
PS. If you liked this post please share it with your friends on the social networks using the buttons on the left or simply leave a reply below. Thanks.
Following your instructions, I’m not able to login to the smtp using Thunderbird. Also postfix sends emails via root@DOMAIN instead of the created user.
Please help.
Please follow the instructions closely. Make sure you change ${DOMAIN} with your actual domain name.
I can send but cannot receive email, what going on? Inbox always empty
Make sure the mail_location and directory permissions are correct. You should also check the log files for error messages.
Should/can the ‘group = postfix’ rather than ‘vmail’ under ‘unix_listener /var/spool/postfix/private/auth {‘.
Does ‘service auth {‘ section require ‘user = dovecot’ or ‘root’?
If possible, it would be helpful to know why the following are required and at what point each helps in the mail receipt or delivery process:
usermod -aG vmail postfix
usermod -aG vmail dovecot
Appreciate the post.
Postfix and Dovecot are added to the vmail group because it is essential for the email server to work due to the vmail ownership of the files responsible for email handling.
How to use imap and pop3 for OUTLOOK?
Can you reply or upload another post?
Thank a lot ;)
I’ve a doubt, what are all the ports that i have to open to internet? i’ve opened 143, 465, 587, 993, there is another one that i MUST to open?
best regards.
I have successfully installed virtual domain postfix with dovecot. email is working fine. my server supports regexp, but i am unable to write rule for following
abc.mydomain.com should send/receive email to/from abc.mydomain.com only
xyz.mydomain.com should send/receive email to/from xyz.mydomain.com only
abc.blahdomain.com should send/receive email to/from abc.blahdomain.com only
it didnt work with my regex, Please guide.
i used trasnport
mydomain.com . :
.mydomain.com :
* error: you can send email to only your domain