===== Requisits =====
==== Firsts remarks ====
- By initial choice, user mail directories are composed like this : /data/vmail/domainname/username/
- You must have a valid FQDN with the corresponding reverse DNS.
- You must have SSL/TLS certificates.
- Postfix configuration here is not suited to high traffic servers (ISP), for this target, see : hash_queue_depth and http://www.postfix.org/TUNING_README.html
==== Variables ====
RQ : change the 3 usernames and their passwords, the mail domain and the server hostname
# for postfixadmin
export PFADBNAME="db_pfadmin"
export PFADBUSER="pfadmin"
export PFADBPW="PASS1_CHANGEME"
export PFARODBNAME="db_pfadmin"
export PFARODBUSER="pfa_ro"
export PFARODBPW="PASS2_CHANGEME"
export PFARWDBNAME="db_pfadmin"
export PFARWDBUSER="pfa_rw"
export PFARWDBPW="PASS3_CHANGEME"
export DEFAULT_MAIL_DOMAIN=""
export MAIL_SERVER_HOSTNAME=""
export MAIL_SERVER_FQDN="${MAIL_SERVER_HOSTNAME}.${DEFAULT_MAIL_DOMAIN}"
==== Begin safely ====
Server update and resolvconf installation :
apt-get update
apt-get upgrade
apt-get install resolvconf
==== Network interfaces :====
vi /etc/network/interfaces
Verify/add : "dns-nameservers 127.0.0.1 "
vi /etc/hosts
127.0.0.1 localhost
==== DNS cache ====
apt-get install bind9
cp -a /etc/bind/named.conf.local /etc/bind/named.conf.local_
sed -i "s/\/\/include \"\/etc\/bind\/zones\.rfc1918\"\;/include \"\/etc\/bind\/zones\.rfc1918\"\;/g" /etc/bind/named.conf.local
/etc/init.d/bind9 stop
/etc/init.d/bind9 start
IF NO IPV6 (RQ bug on jessie : https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=767798)
cp -a /etc/default/bind9 /etc/default/bind9_
sed -i "s/RESOLVCONF=no/RESOLVCONF=yes/g" /etc/default/bind9
sed -i "s/OPTIONS=\"-u bind\"/OPTIONS=\"-4 -u bind\"/g" /etc/default/bind9
/etc/init.d/bind9 stop
/etc/init.d/bind9 start
sleep 3
rndc flush
==== Network restart ====
/etc/init.d/networking stop ; /etc/init.d/networking start
Rq : if the FQDN was changed, restart the server.
==== mysql-server installation ====
apt-get install mysql-server
# New mysql superuser password : enter and keep safely somwhere (ex : keepass)
apt-get install dbconfig-common
===== postfixadmin / postfix / dovecot installation =====
==== DBs configuration ====
DBs and users creation for postfixadmin
echo "create database $PFADBNAME;" > /opt/create_db_pfa
echo "grant usage on *.* to $PFADBUSER@localhost identified by '$PFADBPW';" >> /opt/create_db_pfa
echo "grant all privileges on $PFADBNAME.* to $PFADBUSER@localhost ;" >> /opt/create_db_pfa
echo "grant usage on *.* to $PFARODBUSER@localhost identified by '$PFARODBPW';" >> /opt/create_db_pfa
echo "GRANT SELECT ON $PFARODBNAME.* TO $PFARODBUSER@localhost;" >> /opt/create_db_pfa
echo "grant usage on *.* to $PFARWDBUSER@localhost identified by '$PFARWDBPW';" >> /opt/create_db_pfa
echo "GRANT SELECT,UPDATE,INSERT ON $PFARWDBNAME.* TO $PFARWDBUSER@localhost;" >> /opt/create_db_pfa
cat /opt/create_db_pfa | mysql --defaults-extra-file=/etc/mysql/debian.cnf
rm /opt/create_db_pfa
dbconfig preconfiguration for postfixadmin :
cat << 'EOF' > /etc/dbconfig-common/postfixadmin.conf
dbc_install='true'
dbc_upgrade='true'
dbc_remove=''
dbc_dbtype='mysql'
dbc_dbuser=''
dbc_dbpass=''
dbc_dbserver=''
dbc_dbport=''
dbc_dbname=''
dbc_dbadmin='root'
dbc_basepath=''
dbc_ssl=''
dbc_authmethod_admin=''
dbc_authmethod_user=''
EOF
sed -i "s/dbc_dbname='.*$/dbc_dbname='$PFADBNAME'/g" /etc/dbconfig-common/postfixadmin.conf
sed -i "s/dbc_dbuser='.*$/dbc_dbuser='$PFADBUSER'/g" /etc/dbconfig-common/postfixadmin.conf
sed -i "s/dbc_dbpass='.*$/dbc_dbpass='$PFADBPW'/g" /etc/dbconfig-common/postfixadmin.conf
==== postfixadmin installation ====
apt-get install postfixadmin
# auto reconfigure : apache2
# reconfigure postfixadmin with dbconfig-common ? yes
# DB server to use with postfixadmin : mysql
# DB admin password : enter mysql superadmin password
# choose to install the package maintainer configuration file
==== postfix installation ====
if [ -e /var/log/exim4/paniclog ]; then rm /var/log/exim4/paniclog; fi
apt-get install postfix postfix-mysql dovecot-common
# mail server conf type : internet site
# mailserver name : entrer the public FQDN of the mailserver
apt-get remove --purge exim4 exim4-base exim4-config exim4-daemon-heavy exim4-daemon-light exim4-config-2 exim4-localscanapi-1.0 exim4-localscanapi-1.1
rm -rf /etc/exim4
==== dovecot installation ====
apt-get install dovecot-mysql dovecot-sieve dovecot-imapd dovecot-lmtpd dovecot-managesieved
==== Apache initial configuration ====
see corresponding howto
==== postfixadmin configuration ====
cp -a /etc/apache2/conf-available/postfixadmin.conf /etc/apache2/conf-available/postfixadmin.conf_
sed -i "s/Alias \/postfixadmin .*$/Alias \/admin_pfa \/usr\/share\/postfixadmin/g" /etc/apache2/conf-available/postfixadmin.conf
cp -a /etc/postfixadmin/dbconfig.inc.php /etc/postfixadmin/dbconfig.inc.php_
sed -i "s|\$dbtype=.*|\$dbtype='mysqli';|g" /etc/postfixadmin/dbconfig.inc.php
/etc/init.d/apache2 stop
/etc/init.d/apache2 start
# verify that the webserver is responding : http://fqdn/admin_pfa
vi /etc/postfixadmin/config.inc.php
# change these fields :
XXX
#$CONF['postfix_admin_url'] = '/postfixadmin';
$CONF['postfix_admin_url'] = '/admin_pfa';
$CONF['default_language'] = 'fr';
$CONF['admin_email'] = 'postmaster@';
$CONF['default_aliases'] = array (
'abuse' => 'admin@',
'hostmaster' => 'admin@',
'postmaster' => 'admin@',
'webmaster' => 'admin@',
'admin' => 'admin@'
);
$CONF['aliases'] = '0';
$CONF['mailboxes'] = '0';
$CONF['maxquota'] = '1000';
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
** Todo by hand :**
* RQ : if you need to use hook scripts, you have to configure a sudoer : "wwwrun ALL = (courier) NOPASSWD: /usr/local/bin/postfixadmin-mailbox-postcreation.sh"
* go to postfixadmin web interface : http://fqdn/admin_pfa/setup.php
* generate a new admin password, and keep it safely somewhere, click on "generate passwork hash"
* the web interface proposes to modify the conf file : /etc/postfixadmin/config.inc.php - modify line : $CONF['setup_password'] = 'changeme';
* the web interface proposes to create a new superadmin, do it and keep safely password somewhere
* verify the installation by going to : http://fqdn/admin_pfa/
==== postfix configuration ====
service postfix stop
=== virtual mappings with mysql===
# initial backup
cd /etc/postfix
mkdir origin
cp -ar ./* origin
# postfixadmin compatible mysql queries for postfix
# RQ : we need exported variables we created before for mysql configuration
mkdir /etc/postfix/sql
export PFXSQLCONFDIR=/etc/postfix/sql
echo "# mysql_virtual_alias_maps
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
query = SELECT goto FROM alias WHERE address='%s' AND active = '1'
#expansion_limit = 100
" > $PFXSQLCONFDIR/mysql_virtual_alias_maps.cf
echo "# mysql_virtual_alias_domain_maps
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
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'
" > $PFXSQLCONFDIR/mysql_virtual_alias_domain_maps.cf
echo "# mysql_virtual_alias_domain_catchall_maps
# handles catch-all settings of target-domain
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
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'
" > $PFXSQLCONFDIR/mysql_virtual_alias_domain_catchall_maps.cf
echo "# mysql_virtual_domains_maps
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
query = SELECT domain FROM domain WHERE domain='%s' AND active = '1'
#query = SELECT domain FROM domain WHERE domain='%s'
#optional query to use when relaying for backup MX
#query = SELECT domain FROM domain WHERE domain='%s' AND backupmx = '0' AND active = '1'
#expansion_limit = 100
" > $PFXSQLCONFDIR/mysql_virtual_domains_maps.cf
echo "# mysql_virtual_mailbox_maps
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
query = SELECT maildir FROM mailbox WHERE username='%s' AND active = '1'
#expansion_limit = 100
" > $PFXSQLCONFDIR/mysql_virtual_mailbox_maps.cf
echo "# mysql_virtual_alias_domain_mailbox_maps
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
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'
" > $PFXSQLCONFDIR/mysql_virtual_alias_domain_mailbox_maps.cf
echo "# mysql_virtual_mailbox_limit_maps
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
query = SELECT quota FROM mailbox WHERE username='%s' AND active = '1'
" > $PFXSQLCONFDIR/mysql_virtual_mailbox_limit_maps.cf
echo "# mysql_virtual_sasl-sender-check
user = $PFARODBUSER
password = $PFARODBPW
hosts = localhost
dbname = $PFARODBNAME
query = SELECT goto FROM alias WHERE address='%s' AND active="1"
" > $PFXSQLCONFDIR/mysql_virtual_sasl-sender-check.cf
chown -R root:postfix /etc/postfix/sql
chmod -R 640 /etc/postfix/sql
chmod 750 /etc/postfix/sql
=== Remove mail sender IP ===
cat << '__EOF__' >> /etc/postfix/postfix_header-checks.cf
/^received: / IGNORE
/^X-Sender: / IGNORE
__EOF__
chown root:postfix /etc/postfix/sql
chmod 640 /etc/postfix/postfix_header-checks.cf
=== Custom error messages - french ===
cat << '__EOF__' >> /etc/postfix/bounce.cf.fr
# The failure template is used when mail is returned to the sender;
# either the destination rejected the message, or the destination
# could not be reached before the message expired in the queue.
failure_template = <
Cleanup the safe run postfix environment :
rm /var/lib/postfix/*
=== main.cf file ===
vi /etc/postfix/main.cf
# See /usr/share/postfix/main.cf.dist for a commented, more complete version
#################################################
# Main domain & conf
#
myhostname = _MAIL_SERVER_FQDN_
mydomain = _DEFAULT_MAIL_DOMAIN_
myorigin = /etc/mailname
mydestination = _MAIL_SERVER_FQDN_, localhost._DEFAULT_MAIL_DOMAIN_, localhost
relayhost =
inet_interfaces = all
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
# Recipient delimiter : + is often refused, _ is more accepted
recipient_delimiter = _
# Strict address format in addresses
strict_rfc821_envelopes = yes
# Maximum postmaster notifications
notify_classes = bounce, 2bounce, delay, policy, protocol, resource, software
# Mail maximum size in Bytes
message_size_limit = 67108864
mailbox_size_limit = 0
################################################################################
# SSL/TLS
# TLS parameters
smtpd_tls_cert_file=/etc/ssl/certs/
smtpd_tls_key_file=/etc/ssl/private/
smtpd_use_tls=yes
smtpd_tls_auth_only = yes
################################################################################
# Sender restrictions
# Only registered users can send emails
smtpd_sender_login_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_sasl-sender-check.cf
smtpd_reject_unlisted_sender = yes
# Have a look : http://www.postfix.org/SMTPD_ACCESS_README.html
smtpd_client_restrictions =
smtpd_sender_restrictions = permit_sasl_authenticated
smtpd_recipient_restrictions = permit_mynetworks
permit_sasl_authenticated
reject_unverified_recipient
reject_non_fqdn_recipient
## reject_non_fqdn_sender
reject_non_fqdn_helo_hostname
reject_invalid_helo_hostname
## reject_unknown_sender_domain
reject_unknown_recipient_domain
reject_unlisted_recipient
reject_unlisted_sender
reject_unauth_destination
reject_unlisted_sender
reject_unauth_destination
reject_rbl_client bl.spamcop.net
reject_rbl_client zen.spamhaus.org
permit
smtpd_data_restrictions = reject_unauth_pipelining
reject_multi_recipient_bounce
permit
# hide the sender IP
header_checks = regexp:/etc/postfix/postfix_header-checks.cf
################################################################################
# SASL Auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =
smtpd_sasl_authenticated_header = yes
broken_sasl_auth_clients = yes
################################################################################
# mail delivery
#mailbox_transport = dovecot
#mailbox_command = procmail -a "$EXTENSION"
#mailbox_command = /usr/lib/dovecot/deliver -n -m "$EXTENSION"
#mailbox_size_limit = 0
#dovecot_destination_recipient_limit = 1
virtual_transport = lmtp:unix:private/dovecot-lmtp
################################################
# Virtual mailboxes
virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf
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
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
################################################################################
# misc config
# No local user, no need to notify them.
biff = no
# Appending .domain is the MUA's job.
append_dot_mydomain = no
# messages d'erreur (bounces) en français :
bounce_template_file = /etc/postfix/bounce.cf.fr
# warn the user of non distributed mail after 24h of tries (but keep trying during 5 days)
delay_warning_time = 24h
# No need for documentation
readme_directory = no
# HELO Stuff
smtpd_banner = $myhostname ESMTP $mail_name
smtpd_helo_required = yes
################################################
# Proxy
# Proxy service feeding (important because of the chrooted environment in Debian)
proxy_read_maps = $local_recipient_maps
$mydestination
$mynetworks
$virtual_alias_maps
$virtual_alias_domains
$virtual_mailbox_maps
$virtual_mailbox_domains
$relay_recipient_maps
$relay_domains
$canonical_maps
$sender_canonical_maps
$recipient_canonical_maps
$relocated_maps
$transport_maps
$smtpd_sender_login_maps
proxy_write_maps = $smtp_sasl_auth_cache_name
$smtp_tls_session_cache_database
$smtpd_tls_session_cache_database
$lmtp_sasl_auth_cache_name
$address_verify_map
$postscreen_cache_map
smtp_sasl_auth_cache_name = proxy:btree:${data_directory}/smtp_sasl_auth_cache_name
smtp_tls_session_cache_database = proxy:btree:${data_directory}/smtp_tls_session_cache_database
smtpd_tls_session_cache_database = proxy:btree:${data_directory}/smtpd_tls_session_cache_database
lmtp_sasl_auth_cache_name = proxy:btree:${data_directory}/lmtp_sasl_auth_cache_name
address_verify_map = proxy:btree:${data_directory}/address_verify_map
postscreen_cache_map = proxy:btree:${data_directory}/postscreen_cache_map
sed -i "s/_DEFAULT_MAIL_DOMAIN_/${DEFAULT_MAIL_DOMAIN}/g" /etc/postfix/main.cf
sed -i "s/_MAIL_SERVER_HOSTNAME_/${MAIL_SERVER_HOSTNAME}/g" /etc/postfix/main.cf
sed -i "s/_MAIL_SERVER_FQDN_/${MAIL_SERVER_FQDN}/g" /etc/postfix/main.cf
=== master.cf file ===
vi /etc/postfix/master.cf
add :
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
-o smtpd_sasl_auth_enable=yes
-o smtpd_sasl_type=dovecot
-o smtpd_sasl_path=private/auth
-o smtpd_sasl_security_options=noanonymous
-o smtpd_sasl_local_domain=$myhostname
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o smtpd_sender_restrictions=reject_sender_login_mismatch
-o smtpd_recipient_restrictions=reject_non_fqdn_recipient,reject_unknown_recipient_domain,permit_sasl_authenticated,reject
==== dovecot configuration ====
=== mysql / postfixadmin ===
cd /etc/dovecot
mkdir origin
cp -aR ./* origin
echo "
# postfixadmin database queries
driver = mysql
connect = host=localhost dbname=$PFARODBNAME user=$PFARODBUSER password=$PFARODBPW
default_pass_scheme = MD5-CRYPT
user_query = SELECT concat('/data/vmail/', maildir) AS home, 500 AS uid, 500 AS gid FROM mailbox WHERE username = '%u'
password_query = SELECT username as user, password, concat('/data/vmail/', maildir) as userdb_home, 500 as userdb_uid, 500 as userdb_gid, CONCAT('dirsize:storage=', ROUND(quota / 1024) ) AS quota FROM mailbox WHERE username = '%u' AND active=1
" >> /etc/dovecot/dovecot-sql.conf.ext
sed -i "s/#disable_plaintext_auth = yes/disable_plaintext_auth = yes/g" /etc/dovecot/conf.d/10-auth.conf
sed -i "s/\!include auth-system.conf.ext/#\!include auth-system.conf.ext/g" /etc/dovecot/conf.d/10-auth.conf
sed -i "s/#\!include auth-sql.conf.ext/\!include auth-sql.conf.ext/g" /etc/dovecot/conf.d/10-auth.conf
sed -i "s/mail_location =.*$/mail_location = maildir:%h/g" /etc/dovecot/conf.d/10-mail.conf
sed -i "s/#mail_privileged_group =/mail_privileged_group = mail/g" /etc/dovecot/conf.d/10-mail.conf
#sed -i "s/#port = 993/port = 993/g" /etc/dovecot/conf.d/10-master.conf
sed -i "s/unix_listener lmtp {/unix_listener \/var\/spool\/postfix\/private\/dovecot-lmtp {\n user = postfix\n group = postfix\n mode = 0600/g" /etc/dovecot/conf.d/10-master.conf
sed -i "s/unix_listener auth-userdb {/unix_listener auth-userdb {\n user = vmail/g" /etc/dovecot/conf.d/10-master.conf
sed -i "s/# Postfix smtp-auth/# Postfix smtp-auth\n unix_listener \/var\/spool\/postfix\/private\/auth {\n mode = 0666\n }/g" /etc/dovecot/conf.d/10-master.conf
sed -i "s/service auth-worker {/service auth-worker {\n user = \$default_internal_user/g" /etc/dovecot/conf.d/10-master.conf
sed -i "s/ssl = no/ssl=required/g" /etc/dovecot/conf.d/10-ssl.conf
sed -i 's/#ssl_protocols = !SSLv2/ssl_protocols = !SSLv2/g' /etc/dovecot/conf.d/10-ssl.conf
sed -i 's/#ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL/ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL/g' /etc/dovecot/conf.d/10-ssl.conf
#sed -i "s/#postmaster_address =/postmaster_address = postmaster@/g" /etc/dovecot/conf.d/15-lda.conf
#sed -i "s/#recipient_delimiter = +/#recipient_delimiter = +\nrecipient_delimiter = _/g" /etc/dovecot/conf.d/15-lda.conf
sed -i "s/protocol lmtp {/protocol lmtp {\n postmaster_address = postmaster@\n mail_plugins = \$mail_plugins quota sieve /g" /etc/dovecot/conf.d/20-lmtp.conf
sed -i "s/#recipient_delimiter = +/#recipient_delimiter = +\n recipient_delimiter = _/g" /etc/dovecot/conf.d/90-sieve.conf
mkdir -p /data/vmail
chmod 770 /data/vmail
groupadd --gid 500 vmail
useradd --system --uid 500 --gid 500 --home-dir /data/vmail --shell /sbin/nologin --comment "Virtual mailbox" vmail
chown vmail:vmail /data/vmail
===== At the end... =====
**Do by hand :**
* Edit /etc/postfix/main.cf and change certificates files paths
* Edit /etc/dovecot/conf.d/10-ssl.conf and change certificates files paths
* Edit /etc/dovecot/conf.d/15-lda.conf and /etc/dovecot/conf.d/20-lmtp.conf in order to change postmaster address
# (re)start services
tail -f /var/log/syslog &
service dovecot stop
service dovecot start
service postfix start
fg
Add www-data alias
echo "www-data: root" >> /etc/aliases
echo "root: admin_@" >> /etc/aliases
newaliases
Final verification (all the chain)
# stop mail services
for SERVICE_ in postfix dovecot ; do service $SERVICE_ stop; done
# start mail services
for SERVICE_ in dovecot postfix; do service $SERVICE_ start; done
===== Not included for the moment : ====
* quota : table quota2 dans postfixadmin + option
* group mailbox
* lucene/solr
* logging mysql