almost human fully human

SOLUSIPSE

/var/log

Secure semi-automatic Postfix config

Setting Postfix isn’t especially hard, but for sure is tedious. To make this process less inconvinient, I created a simple shell script for Debian 7 that takes care of basic system configuration. After some minor changes it should be usable for other Linux distributions.

That configuration supports most secure solutions: SMTPS with STARTTLS on port 587 and SSL secured IMAP on port 993. I also decided to use PostgreSQL instead of MySQL which is used in most configurations you can find on the Internet. So this is virtual mail system based on Dovecot, managed by Postfix Admin, with web frontend Roundcube.

Complete script is available here: gitsts.github.com.

To start it, follow these steps:

wget https://gist.githubusercontent.com/solusipse/7ed8e1da104baaee3f05/raw/dd11da572636fb239a4f786c3182d614880f605e/02_postfix.sh
chmod a+x 02_postfix.sh
./02_postfix.sh

It was tested on fresh install of Debian 7 on Digital Ocean. Here, I’ll explain what it does.

Adding user (and its group) for handling mails.

For security reasons, emails will be stored in vmail user’s home directory:

groupadd -g 5000 vmail
useradd -u 5000 -g vmail -s /usr/bin/nologin -d /home/vmail -m vmail

Installing software

These are all you’ll need during whole process:

apt-get install postfix dovecot-core dovecot-imapd postgresql postfix-pgsql dovecot-lmtpd dovecot-pgsql php5-fpm php5-imap php5-pgsql

Preparing database

This part of the script is used for creating user for virtual mail system:

:::bash
DBPASS=$(date | md5sum | head -c 32)
CREATEUSER="CREATE USER postfix_user WITH PASSWORD '${DBPASS}';"
CREATEDB="CREATE DATABASE postfix_db;"
PERMISSDB="GRANT ALL PRIVILEGES ON DATABASE postfix_db TO postfix_user;"

sudo -u postgres psql -c "${CREATEUSER}"
sudo -u postgres psql -c "${CREATEDB}"
sudo -u postgres psql -c "${PERMISSDB}"

Note that ${DBPASS} will be used later in some configuration files.

Creating config files

Many of these contains ${DBPASS} variable. If you set your password manually, remember to replace ${DBPASS} with it.

/etc/postfix/main.cf
relay_domains =
virtual_alias_maps = proxy:pgsql:/etc/postfix/virtual_alias_maps.cf
virtual_mailbox_domains = proxy:pgsql:/etc/postfix/virtual_mailbox_domains.cf
virtual_mailbox_maps = proxy:pgsql:/etc/postfix/virtual_mailbox_maps.cf
virtual_mailbox_base = /home/vmail
virtual_mailbox_limit = 512000000
virtual_minimum_uid = 5000
virtual_transport = virtual
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
local_transport = virtual
local_recipient_maps = $virtual_mailbox_maps
transport_maps = hash:/etc/postfix/transport

smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
smtpd_sasl_security_options = noanonymous
smtpd_sasl_tls_security_options = $smtpd_sasl_security_options
smtpd_tls_auth_only = yes
smtpd_tls_cert_file = /etc/ssl/private/server.crt
smtpd_tls_key_file = /etc/ssl/private/server.key
smtpd_sasl_local_domain = $mydomain
broken_sasl_auth_clients = yes
smtpd_tls_loglevel = 1
html_directory = /usr/share/doc/postfix/html
queue_directory = /var/spool/postfix
mydestination = localhost

/etc/postfix/master.cf
smtp      inet  n       -       -       -       -       smtpd
submission inet n       -       -       -       -       smtpd
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
smtps     inet  n       -       -       -       -       smtpd
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
pickup    fifo  n       -       -       60      1       pickup
cleanup   unix  n       -       -       -       0       cleanup
qmgr      fifo  n       -       n       300     1       qmgr
#qmgr     fifo  n       -       n       300     1       oqmgr
tlsmgr    unix  -       -       -       1000?   1       tlsmgr
rewrite   unix  -       -       -       -       -       trivial-rewrite
bounce    unix  -       -       -       -       0       bounce
defer     unix  -       -       -       -       0       bounce
trace     unix  -       -       -       -       0       bounce
verify    unix  -       -       -       -       1       verify
flush     unix  n       -       -       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       -       -       -       smtp
relay     unix  -       -       -       -       -       smtp
showq     unix  n       -       -       -       -       showq
error     unix  -       -       -       -       -       error
retry     unix  -       -       -       -       -       error
discard   unix  -       -       -       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       -       -       -       lmtp
anvil     unix  -       -       -       -       1       anvil
scache    unix  -       -       -       -       1       scache
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
ifmail    unix  -       n       n       -       -       pipe
  flags=F user=ftn argv=/usr/lib/ifmail/ifmail -r $nexthop ($recipient)
bsmtp     unix  -       n       n       -       -       pipe
  flags=Fq. user=bsmtp argv=/usr/lib/bsmtp/bsmtp -t$nexthop -f$sender $recipient
scalemail-backend unix  -   n   n   -   2   pipe
  flags=R user=scalemail argv=/usr/lib/scalemail/bin/scalemail-store ${nexthop} ${user} ${extension}
mailman   unix  -       n       n       -       -       pipe
  flags=FR user=list argv=/usr/lib/mailman/bin/postfix-to-mailman.py
  ${nexthop} ${user}
cleanup   unix  n       -       -       -       0       cleanup
subcleanup unix n       -       -       -       0       cleanup
 -o header_checks=regexp:/etc/postfix/submission_header_checks

/etc/postfix/submission_header_checks
/^Received:/ IGNORE
/^User-Agent:/ IGNORE" > /etc/postfix/submission_header_checks

/etc/postfix/virtual_alias_maps.cf
user = postfix_user
password = ${DBPASS}
hosts = localhost
dbname = postfix_db
query = SELECT goto FROM alias WHERE address='%s' AND active = true

/etc/postfix/virtual_mailbox_domains.cf
user = postfix_user
password = ${DBPASS}
hosts = localhost
dbname = postfix_db
query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = false AND active = true

/etc/postfix/virtual_mailbox_maps.cf
user = postfix_user
password = ${DBPASS}
hosts = localhost
dbname = postfix_db
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = true

/etc/dovecot/dovecot.conf
protocols = imap
auth_mechanisms = plain
passdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}
userdb {
    driver = sql
    args = /etc/dovecot/dovecot-sql.conf
}
service auth {
    unix_listener /var/spool/postfix/private/auth {
        group = postfix
        mode = 0660
        user = postfix
    }
    user = root
}
mail_home = /home/vmail/%d/%u
mail_location = maildir:~
ssl_cert = </etc/ssl/private/server.crt
ssl_key = </etc/ssl/private/server.key

/etc/dovecot/dovecot-sql.conf
driver = pgsql
connect = host=localhost dbname=postfix_db user=postfix_user password=${DBPASS}
default_pass_scheme = MD5-CRYPT
user_query = SELECT '/home/vmail/%d/%u' as home, 'maildir:/home/vmail/%d/%u' as mail, 5000 AS uid, 5000 AS gid, concat('dirsize:storage=',  quota) AS quota FROM mailbox WHERE username = '%u' AND active = '1'
password_query = SELECT username as user, password, '/home/vmail/%d/%u' as userdb_home, 'maildir:/home/vmail/%d/%u' as userdb_mail, 5000 as  userdb_uid, 5000 as userdb_gid FROM mailbox WHERE username = '%u' AND active = '1'

Create certificate

cd /etc/ssl/private/
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out server.key
chmod 400 server.key

openssl req -new -key server.key -out server.csr
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
chmod 444 server.crt

Creating postmap, starting services

Let’s create postmap:

touch /etc/postfix/transport
postmap /etc/postfix/transport

Make sure that all services we’ll need are running:

/etc/init.d/postfix restart
/etc/init.d/dovecot restart
/etc/init.d/php5-fpm restart

Postfix Admin

To complete this setup, you need working webserver with php support. I used nginx. After you’ll configure it, download Postfix Admin:

wget -O postfixadmin.tar.gz http://sourceforge.net/projects/postfixadmin/files/latest/download

Unpack it to location that is served by webserver. Now you need to modify config.inc.php to match your settings. Change tese values:

:::php
$CONF['configured'] = true;
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'YES';
$CONF['database_type'] = 'pgsql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix_user';
$CONF['database_password'] = 'PASSWORD FROM INSTALLER SCRIPT';
$CONF['database_name'] = 'postfix_db';

Then, follow installer’s instructions. After creating admin account, you’ll need to create at least one domain and one user.

Roundcube

Now you’re ready to download and install Roundcube. It’s quite easy, so i won’t describe the whole process. Just remember to create an user and database for it:

:::sql
su postgres
psql
postgres=# CREATE USER roundcube WITH PASSWORD 'PASSWORD FROM INSTALLER SCRIPT';
postgres=# CREATE DATABASE roundcubemail;
postgres=# GRANT ALL PRIVILEGES ON DATABASE roundcubemail TO roundcube;

Now follow the installer’s instructions. Your email server is now fully configured. Don’t forget to set things like iptables.