Nastavení mail serveru: Porovnání verzí

Z ZděchovNET
Skočit na navigaci Skočit na vyhledávání
Bez shrnutí editace
Bez shrnutí editace
Řádek 10: Řádek 10:
=Instalační skript=
=Instalační skript=


Většina návodů je udělána jako dlouhý popis postupu s útržkovými částmi příkazů, které je potřeba provést. To je zdlouhavý proces kopírovat jednotlivé části povelů a po částech je provádět. Místo toho bychom rádi měli jednoduchou instalaci, kterou prostě spustíme, chvíli počkáme a máme hotovo. Zde je předložen skript, který se toto dle jednoho návodu snaží docílit.
Většina návodů je provedena jako dlouhý popis postupu s mnoha útržkovými částmi příkazů, které je potřeba provést. To je zdlouhavý proces kopírovat jednotlivé části povelů a po částech je provádět. Místo toho bychom rádi měli jednoduchou instalaci, kterou prostě spustíme, chvíli počkáme a máme hotovo. Zde je předložen skript, který se toto dle jednoho návodu snaží docílit.


<source lang="php">
<pre>
<?php
#!/bin/bash


$MysqlRootPassword = 'MysqlRootPassword';
ROOT_PASSWORD=mysql_root_passwod
$MysqlUserPassword = 'MysqlUserPassword';
PASSWORD=mail_admin_password
$PostfixAdminName = 'PostfixAdminName';
$PostfixSetupPassword = 'PostfixSetupPassword';
$DomainName = 'domain.com';
$ServerDomain = 'mail.'.$DomainName;


function Execute($Command)
# LAMP web server
{
apt-get update
echo('Executing: '.$Command."\n");
apt-get upgrade --assume-yes
passthru($Command);
apt-get install --assume-yes lamp-server^
}


function InstallPackages()
apt-get install --assume-yes \
{
// LAMP web server
Execute('apt-get update');
Execute('apt-get upgrade --assume-yes');
Execute('apt-get install --assume-yes lamp-server^');

Execute('apt-get install --assume-yes \
php-apc \
php-apc \
php5-mcrypt \
php5-mcrypt \
Řádek 29: Řádek 41:
php5-curl \
php5-curl \
php5-gd \
php5-gd \
php-xml-parser
php-xml-parser');


ln -sf ../../mods-available/mcrypt.ini /etc/php5/apache2/conf.d/20-mcrypt.ini
Execute('ln -sf ../../mods-available/mcrypt.ini /etc/php5/apache2/conf.d/20-mcrypt.ini');


# Configure apache
// Configure apache
a2enmod rewrite ssl
Execute('a2enmod rewrite ssl');
a2ensite default-ssl
Execute('a2ensite default-ssl');


service apache2 restart
Execute('service apache2 restart');


# Memcached
// Memcached
apt-get install --assume-yes memcached
Execute('apt-get install --assume-yes memcached');
// Mail packages
Execute('apt-get install --assume-yes mail-server^');


Execute('apt-get install --assume-yes \
# Mail packages
apt-get install --assume-yes mail-server^

apt-get install --assume-yes \
postfix-mysql \
postfix-mysql \
dovecot-mysql \
dovecot-mysql \
Řádek 53: Řádek 65:
clamav-daemon \
clamav-daemon \
spamassassin \
spamassassin \
php5-imap
php5-imap');


ln -sf ../../mods-available/imap.ini /etc/php5/apache2/conf.d/20-imap.ini
Execute('ln -sf ../../mods-available/imap.ini /etc/php5/apache2/conf.d/20-imap.ini');


service apache2 restart
Execute('service apache2 restart');


apt-get install --assume-yes \
Execute('apt-get install --assume-yes \
pyzor \
pyzor \
razor \
razor \
Řádek 73: Řádek 85:
unrar-free \
unrar-free \
zip \
zip \
zoo
zoo');
}

function PrepareDatabase()
{
global $MysqlUserPassword, $MysqlRootPassword;
// Mail database

Execute('mysql -uroot -p'.$MysqlRootPassword.' -Bse \
"drop database mail; create database mail;
grant all on mail.* to \'mail\'@\'localhost\' identified by \''.$MysqlUserPassword.'\';"');
}

function UpdatePHPConfigFile($FileName, $BaseVariable, $Parameters)
{
if(!file_exists($FileName.'_backup'))
file_put_contents($FileName.'_backup', file_get_contents($FileName));
$Content = explode("\n", file_get_contents($FileName.'_backup'));
foreach($Parameters as $Parameter)
{
if(is_array($Parameter['name'])) {
foreach($Content as $Num => $Line)
{
$Needle = '$'.$BaseVariable.'['."'".$Parameter['name'][0]."'] = array (";
if(substr($Line, 0, strlen($Needle)) == $Needle)
{
echo('Found group: '.$Parameter['name'][0]."\n");
$Needle = " '".$Parameter['name'][1]."' => ";
$I = 1;
while((($Num + $I) < count($Content)) and ($Content[$Num + $I] != ');'))
{
if(substr($Content[$Num + $I], 0, strlen($Needle)) == $Needle) {
echo('Found group: '.$Parameter['name'][1]."\n");
$Content[$Num + $I] = $Needle.$Parameter['value'].',';
}
$I++;
}
}
}
} else {
foreach($Content as $Num => $Line)
{
$Needle = '$'.$BaseVariable.'['."'".$Parameter['name']."'] = ";
if(substr($Line, 0, strlen($Needle)) == $Needle)
{
echo('Found: '.$Parameter['name']."\n");
$Content[$Num] = $Needle.$Parameter['value'].';';
}
}
}
}
file_put_contents($FileName, implode("\n", $Content));
}

function generate_setup_password_salt()
{
$salt = time().'*'.mt_rand(0,60000);
$salt = md5($salt);
return $salt;
}

function encrypt_setup_password($password, $salt)
{
return $salt . ':' . sha1($salt . ':' . $password);
}

function InstallPostfixAdmin()
{
global $ServerDomain, $PostfixAdminName, $MysqlUserPassword, $PostfixSetupPassword, $DomainName;
Execute('wget "http://downloads.sourceforge.net/project/postfixadmin/postfixadmin/'.
$PostfixAdminName.'/'.$PostfixAdminName.'.tar.gz?r=&ts=1417890779&use_mirror=netcologne" -O '.
$PostfixAdminName.'.tar.gz');
Execute('tar -xf '.$PostfixAdminName.'.tar.gz');
Execute('rm -f '.$PostfixAdminName.'.tar.gz');
Execute('mv '.$PostfixAdminName.' /var/www/html/postfixadmin');
Execute('chown -R www-data:www-data /var/www/html/postfixadmin');

UpdatePHPConfigFile('/var/www/html/postfixadmin/config.inc.php', 'CONF', array(
array('name' => 'setup_password', 'value' => "'".encrypt_setup_password($PostfixSetupPassword, generate_setup_password_salt())."'"),
array('name' => 'configured', 'value' => 'true'),
array('name' => 'postfix_admin_url', 'value' => "'https://".$ServerDomain."/postfixadmin'"),
array('name' => 'database_type', 'value' => "'mysql'"),
array('name' => 'database_host', 'value' => "'localhost'"),
array('name' => 'database_user', 'value' => "'mail'"),
array('name' => 'database_password', 'value' => "'".$MysqlUserPassword."'"),
array('name' => 'database_name', 'value' => "'mail'"),
array('name' => 'admin_email', 'value' => "'admin@".$DomainName."'"),
array('name' => 'user_footer_link', 'value' => "'https://".$ServerDomain."/main.php'"),
array('name' => 'show_footer_text', 'value' => "'YES'"),
array('name' => 'footer_text', 'value' => "'Return to ".$ServerDomain."'"),
array('name' => 'footer_link', 'value' => "'https://".$ServerDomain."'"),
array('name' => array('default_aliases', 'abuse'), 'value' => "'abuse@".$DomainName."'"),
array('name' => array('default_aliases', 'hostmaster'), 'value' => "'hostmaster@".$DomainName."'"),
array('name' => array('default_aliases', 'postmaster'), 'value' => "'postmaster@".$DomainName."'"),
array('name' => array('default_aliases', 'webmaster'), 'value' => "'webmaster@".$DomainName."'"),
));

}

function VirtualMailUser()
{
Execute('useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c "Virtual maildir handler" vmail');
Execute('mkdir /var/vmail');
Execute('chmod 770 /var/vmail');
Execute('chown vmail:mail /var/vmail');
}

function UpdateDovecotConfigFile($FileName, $Parameters)
{
if(!file_exists($FileName.'_backup'))
file_put_contents($FileName.'_backup', file_get_contents($FileName));
$Content = explode("\n", file_get_contents($FileName.'_backup'));
foreach($Parameters as $Parameter)
{
if(!is_array($Parameter['name']))
$Parameter['name'] = array($Parameter['name']);
// First find subgroup
$Num = 0;
$NestingLevel = 0;
while(count($Parameter['name']) > 1)
{
$Found = false;
$Needle = '#'.array_values($Parameter['name'])[0].' {';
$I = 0;
$StartNestingLevel = $NestingLevel;
while((($Num + $I) < count($Content)) and ($NestingLevel >= $StartNestingLevel))
{
if(substr(trim($Content[$Num + $I]), -1, 1) == '{') $NestingLevel++;
if(substr(trim($Content[$Num + $I]), -1, 1) == '}') $NestingLevel--;
if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
or (trim(substr(trim($Content[$Num + $I]), 0, strlen(substr($Needle, 1)))) == substr($Needle, 1)))
{
$Content[$Num + $I] = array_values($Parameter['name'])[0].' {';
$Num = $Num + $I + 1;
$Found = true;
echo('Found group: '.array_values($Parameter['name'])[0]."\n");
array_shift($Parameter['name']);
break;
}
$I++;
}
if(!$Found) break;
}
// Find and replace value
if(count($Parameter['name']) == 1)
{
if(!array_key_exists('value', $Parameter))
{
$Needle = array_values($Parameter['name'])[0];
$Parameter['value'] = '';
} else
$Needle = array_values($Parameter['name'])[0]." =";
$I = 0;
$StartNestingLevel = $NestingLevel;
$Found = false;
while((($Num + $I) < count($Content)) and ($NestingLevel >= $StartNestingLevel))
{
if(substr(trim($Content[$Num + $I]), -1, 1) == '{') $NestingLevel++;
if(substr(trim($Content[$Num + $I]), -1, 1) == '}')
{
if($NestingLevel == $StartNestingLevel) $Content[$Num + $I] = '}';
$NestingLevel--;
}
if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
or ((substr(trim($Content[$Num + $I]), 0, 1) == '#') and (substr(trim(substr(trim($Content[$Num + $I]), 1)), 0, strlen($Needle)) == $Needle)))
{
echo('Found: '.array_values($Parameter['name'])[0]."\n");
$Content[$Num + $I] = $Needle.' '.$Parameter['value'];
$Found = true;
break;
}
$I++;
}
// If not found then add new value
if($Found == false)
{
echo('Added new: '.array_values($Parameter['name'])[0]."\n");
array_splice($Content, $Num + $I - 1, 0, $Needle.' '.$Parameter['value']);
}
}
}
file_put_contents($FileName, implode("\n", $Content));
}

function ConfigureDovecot()
{
global $MysqlUserPassword, $DomainName;
UpdateDovecotConfigFile('/etc/dovecot/dovecot-sql.conf.ext', array(
array('name' => 'driver', 'value' => 'mysql'),
array('name' => 'connect', 'value' => 'host=localhost dbname=mail user=mail password='.$MysqlUserPassword),
array('name' => 'default_pass_scheme', 'value' => 'MD5-CRYPT'),
array('name' => 'password_query', 'value' => "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'"),
array('name' => 'user_query', 'value' => "SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n' as mail, \\
150 AS uid, 8 AS gid, concat('dirsize:storage=', quota) AS quota \\
FROM mailbox WHERE username = '%u' AND active = '1'"),
));
UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-auth.conf', array(
array('name' => 'disable_plaintext_auth', 'value' => 'yes'),
array('name' => 'auth_mechanisms', 'value' => 'plain login'),
array('name' => '!include auth-sql.conf.ext'),
));
UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-mail.conf', array(
array('name' => 'mail_location', 'value' => 'maildir:/var/vmail/%d/%n'),
array('name' => 'mail_uid', 'value' => 'vmail'),
array('name' => 'mail_gid', 'value' => 'mail'),
array('name' => 'first_valid_uid', 'value' => '150'),
array('name' => 'last_valid_uid', 'value' => '150'),
));
UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-ssl.conf', array(
array('name' => 'ssl_cert', 'value' => '</etc/ssl/certs/'.$DomainName.'.crt'),
array('name' => 'ssl_key', 'value' => '</etc/ssl/private/'.$DomainName.'.key'),
array('name' => 'ssl_ca', 'value' => '</etc/ssl/certs/ca-bundle.crt'),
array('name' => 'ssl_cipher_list', 'value' => 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS'),
));
UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-master.conf', array(
array('name' => array('service auth', 'unix_listener auth-userdb', 'mode'), 'value' => '0666'),
array('name' => array('service auth', 'unix_listener auth-userdb', 'user'), 'value' => 'vmail'),
array('name' => array('service auth', 'unix_listener auth-userdb', 'group'), 'value' => 'mail'),
array('name' => array('service auth', 'unix_listener /var/spool/postfix/private/auth', 'mode'), 'value' => '0666'),
array('name' => array('service auth', 'unix_listener /var/spool/postfix/private/auth', 'user'), 'value' => 'postfix'),
array('name' => array('service auth', 'unix_listener /var/spool/postfix/private/auth', 'group'), 'value' => 'postfix'),
));
UpdateDovecotConfigFile('/etc/dovecot/conf.d/15-lda.conf', array(
array('name' => 'postmaster_address', 'value' => 'postmaster@'.$DomainName),
));
Execute('chown -R vmail:dovecot /etc/dovecot');
Execute('chmod -R o-rwx /etc/dovecot');
}

function UpdateAmavisConfigFile($FileName, $Parameters)
{
if(!file_exists($FileName.'_backup'))
file_put_contents($FileName.'_backup', file_get_contents($FileName));
$Content = explode("\n", file_get_contents($FileName.'_backup'));
if(count($Content) > 0)
{
// Remove ending part
$I = count($Content) - 1;
while(($I >= 0))
{
if($Content[$I] != '#------------ Do not modify anything below this line -------------')
array_pop($Content);
else {
array_pop($Content);
break;
}
$I--;
}
}
foreach($Parameters as $Parameter)
{
$Parameter['name'] = array($Parameter['name']);
$Num = 0;
if(!array_key_exists('value', $Parameter))
{
$Needle = array_values($Parameter['name'])[0];
$Parameter['value'] = '';
} else
$Needle = array_values($Parameter['name'])[0]." =";
$I = 0;
$Found = false;
while((($Num + $I) < count($Content)))
{
if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
or ((substr(trim($Content[$Num + $I]), 0, 1) == '#') and (substr(trim(substr(trim($Content[$Num + $I]), 1)), 0, strlen($Needle)) == $Needle)))
{
echo('Found: '.array_values($Parameter['name'])[0]."\n");
$Content[$Num + $I] = $Needle.' '.$Parameter['value'];
$Found = true;
break;
}
$I++;
}
// If not found then add new value
if($Found == false)
{
echo('Added new: '.array_values($Parameter['name'])[0]."\n");
array_splice($Content, $Num + $I - 1, 0, $Needle.' '.$Parameter['value']);
}
}
$Content[] = '#------------ Do not modify anything below this line -------------';
$Content[] = '1; # ensure a defined return';
file_put_contents($FileName, implode("\n", $Content));
}

function UpdateDefaultConfigFile($FileName, $Parameters)
{
if(!file_exists($FileName.'_backup'))
file_put_contents($FileName.'_backup', file_get_contents($FileName));
$Content = explode("\n", file_get_contents($FileName.'_backup'));
foreach($Parameters as $Parameter)
{
if(!is_array($Parameter['name']))
$Parameter['name'] = array($Parameter['name']);
$Num = 0;
// Find and replace value
if(count($Parameter['name']) == 1)
{
if(!array_key_exists('value', $Parameter))
{
$Needle = array_values($Parameter['name'])[0];
$Parameter['value'] = '';
} else
$Needle = array_values($Parameter['name'])[0]."=";
$I = 0;
$Found = false;
while((($Num + $I) < count($Content)))
{
if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
or ((substr(trim($Content[$Num + $I]), 0, 1) == '#') and (substr(trim(substr(trim($Content[$Num + $I]), 1)), 0, strlen($Needle)) == $Needle)))
{
echo('Found: '.array_values($Parameter['name'])[0]."\n");
$Content[$Num + $I] = $Needle.$Parameter['value'];
$Found = true;
break;
}
$I++;
}
// If not found then add new value
if($Found == false)
{
echo('Added new: '.array_values($Parameter['name'])[0]."\n");
array_splice($Content, $Num + $I - 1, 0, $Needle.' '.$Parameter['value']);
}
}
}
file_put_contents($FileName, implode("\n", $Content));
}

function SpamVirus()
{
Execute('adduser clamav amavis');
Execute('adduser amavis clamav');
UpdateAmavisConfigFile('/etc/amavis/conf.d/15-content_filter_mode', array(
array('name' => '@bypass_virus_checks_maps', 'value' => '(\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);'),
array('name' => '@bypass_spam_checks_maps', 'value' => '(\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);'),
));
UpdateDefaultConfigFile('/etc/default/spamassassin', array(
array('name' => 'ENABLED', 'value' => '1'),
array('name' => 'CRON', 'value' => '1'),
));
UpdateAmavisConfigFile('/etc/amavis/conf.d/50-user', array(
array('name' => '$max_servers', 'value' => '3;'),
array('name' => '$sa_tag_level_deflt', 'value' => '-9999;'),
array('name' => '@lookup_sql_dsn', 'value' => "(
['DBI:mysql:database=mail;host=127.0.0.1;port=3306',
'mail',
'mailpassword']);"),
array('name' => '$sql_select_policy', 'value' => "'SELECT domain from domain WHERE CONCAT(\"@\",domain) IN (%k)';"),
));
Execute('freshclam');
Execute('service clamav-daemon restart');
Execute('service amavis restart');
Execute('service spamassassin restart');
}

function ConfigurePostfix()
{
file_put_contents('/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf',
"user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
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");
file_put_contents('/etc/postfix/mysql_virtual_alias_maps.cf',
"user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
table = alias
select_field = goto
where_field = address
additional_conditions = and active = '1'");
file_put_contents('/etc/postfix/mysql_virtual_domains_maps.cf',
"user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
table = domain
select_field = domain
where_field = domain
additional_conditions = and backupmx = '0' and active = '1'");
file_put_contents('/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf',
"user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
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");
file_put_contents('/etc/postfix/mysql_virtual_mailbox_maps.cf',
"user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
table = mailbox
select_field = CONCAT(domain, '/', local_part)
where_field = username
additional_conditions = and active = '1'");
file_put_contents('/etc/postfix/header_checks',
"/^Received:/ IGNORE
/^User-Agent:/ IGNORE
/^X-Mailer:/ IGNORE
/^X-Originating-IP:/ IGNORE
/^x-cr-[a-z]*:/ IGNORE
/^Thread-Index:/
IGNORE");
if(!file_exists('/etc/postfix/main.cf_backup'))
file_put_contents('/etc/postfix/main.cf_backup', file_get_contents('/etc/postfix/main.cf'));
file_put_contents('/etc/postfix/main.cf',
'# See /usr/share/postfix/main.cf.dist for a commented, more complete version
# The first text sent to a connecting process.
smtpd_banner = $myhostname ESMTP $mail_name
biff = no
# appending .domain is the MUA\'s job.
append_dot_mydomain = no
readme_directory = no
# SASL parameters
# ---------------------------------
# Use Dovecot to authenticate.
smtpd_sasl_type = dovecot
# Referring to /var/spool/postfix/private/auth
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =
smtpd_sasl_authenticated_header = yes
# TLS parameters
# ---------------------------------
# The default snakeoil certificate. Comment if using a purchased
# SSL certificate.
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
# Uncomment if using a purchased SSL certificate.
# smtpd_tls_cert_file=/etc/ssl/certs/example.com.crt
# smtpd_tls_key_file=/etc/ssl/private/example.com.key
# The snakeoil self-signed certificate has no need for a CA file. But
# if you are using your own SSL certificate, then you probably have
# a CA certificate bundle from your provider. The path to that goes
# here.
# smtpd_tls_CAfile=/etc/ssl/certs/ca-bundle.crt
# Ensure we\'re not using no-longer-secure protocols.
smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3
smtp_tls_note_starttls_offer = yes
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# Note that forcing use of TLS is going to cause breakage - most mail servers
# don\'t offer it and so delivery will fail, both incoming and outgoing. This is
# unfortunate given what various governmental agencies are up to these days.
#
# Enable (but don\'t force) all incoming smtp connections to use TLS.
smtpd_tls_security_level = may
# Enable (but don\'t force) all outgoing smtp connections to use TLS.
smtp_tls_security_level = may
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.
# SMTPD parameters
# ---------------------------------
# Uncomment the next line to generate \"delayed mail\" warnings
#delay_warning_time = 4h
# will it be a permanent error or temporary
unknown_local_recipient_reject_code = 450
# how long to keep message on queue before return as failed.
# some have 3 days, I have 16 days as I am backup server for some people
# whom go on holiday with their server switched off.
maximal_queue_lifetime = 7d
# max and min time in seconds between retries if connection failed
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
# how long to wait when servers connect before receiving rest of data
smtp_helo_timeout = 60s
# how many address can be used in one message.
# effective stopper to mass spammers, accidental copy in whole address list
# but may restrict intentional mail shots.
smtpd_recipient_limit = 16
# how many error before back off.
smtpd_soft_error_limit = 3
# how many max errors before blocking it.
smtpd_hard_error_limit = 12
# This next set are important for determining who can send mail and relay mail
# to other servers. It is very important to get this right - accidentally producing
# an open relay that allows unauthenticated sending of mail is a Very Bad Thing.
#
# You are encouraged to read up on what exactly each of these options accomplish.
# Requirements for the HELO statement
smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit
# Requirements for the sender details
smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit
# Requirements for the connecting server
smtpd_client_restrictions = reject_rbl_client sbl.spamhaus.org, reject_rbl_client blackholes.easynet.nl, reject_rbl_client dnsbl.njabl.org
# Requirement for the recipient address. Note that the entry for
# \"check_policy_service inet:127.0.0.1:10023\" enables Postgrey.
smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service inet:127.0.0.1:10023, permit
smtpd_data_restrictions = reject_unauth_pipelining
# This is a new option as of Postfix 2.10, and is required in addition to
# smtpd_recipient_restrictions for things to work properly in this setup.
smtpd_relay_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service inet:127.0.0.1:10023, permit
# require proper helo at connections
smtpd_helo_required = yes
# waste spammers time before rejecting them
smtpd_delay_reject = yes
disable_vrfy_command = yes
# General host and delivery info
# ----------------------------------
myhostname = mail.example.com
myorigin = /etc/hostname
# Some people see issues when setting mydestination explicitly to the server
# subdomain, while leaving it empty generally doesn\'t hurt. So it is left empty here.
# mydestination = mail.example.com, localhost
mydestination =
# If you have a separate web server that sends outgoing mail through this
# mailserver, you may want to add its IP address to the space-delimited list in
# mynetworks, e.g. as 10.10.10.10/32.
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
mynetworks_style = host
# This specifies where the virtual mailbox folders will be located.
virtual_mailbox_base = /var/vmail
# This is for the mailbox location for each user. The domainaliases
# map allows us to make use of Postfix Admin\'s domain alias feature.
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf, mysql:/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf
# and their user id
virtual_uid_maps = static:150
# and group id
virtual_gid_maps = static:8
# This is for aliases. The domainaliases map allows us to make
# use of Postfix Admin\'s domain alias feature.
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf, mysql:/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf
# This is for domain lookups.
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf
# Integration with other packages
# ---------------------------------------
# Tell postfix to hand off mail to the definition for dovecot in master.cf
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
# Use amavis for virus and spam scanning
content_filter = amavis:[127.0.0.1]:10024
# Header manipulation
# --------------------------------------
# Getting rid of unwanted headers. See: https://posluns.com/guides/header-removal/
header_checks = regexp:/etc/postfix/header_checks
# getting rid of x-original-to
enable_original_recipient = no');

if(!file_exists('/etc/postfix/master.cf_backup'))
file_put_contents('/etc/postfix/master.cf_backup', file_get_contents('/etc/postfix/master.cf'));
file_put_contents('/etc/postfix/master.cf',
'#
# Postfix master process configuration file. For details on the format
# of the file, see the master(5) manual page (command: \"man 5 master\").
#
# Do not forget to execute \"postfix reload\" after editing this file.
#
# ==========================================================================
# service type private unpriv chroot wakeup maxproc command + args
# (yes) (yes) (yes) (never) (100)
# ==========================================================================
# SMTP on port 25, unencrypted.
smtp inet n - - - - smtpd
#smtp inet n - - - 1 postscreen
#smtpd pass - - - - - smtpd
#dnsblog unix - - - - 0 dnsblog
#tlsproxy unix - - - - 0 tlsproxy
# SMTP with TLS on port 587. Currently commented.
#submission inet n - - - - smtpd
# -o syslog_name=postfix/submission
# -o smtpd_tls_security_level=encrypt
# -o smtpd_sasl_auth_enable=yes
# -o smtpd_enforce_tls=yes
# -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
# -o smtpd_sasl_tls_security_options=noanonymous
# SMTP over SSL on port 465.
smtps inet n - - - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
-o smtpd_sasl_auth_enable=yes
-o smtpd_tls_auth_only=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
-o smtpd_sasl_security_options=noanonymous,noplaintext
-o smtpd_sasl_tls_security_options=noanonymous
#628 inet n - - - - qmqpd
pickup fifo n - - 60 1 pickup
-o content_filter=
-o receive_override_options=no_header_body_checks
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
# -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
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
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent. See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop unix - n n - - pipe
flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# ====================================================================
#
# Recent Cyrus versions can use the existing \"lmtp\" master.cf entry.
#
# Specify in cyrus.conf:
# lmtp cmd=\"lmtpd -a\" listen=\"localhost:lmtp\" proto=tcp4
#
# Specify in main.cf one or more of the following:
# mailbox_transport = lmtp:inet:localhost
# virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus unix - n n - - pipe
# user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#
# ====================================================================
# Old example of delivery via Cyrus.
#
#old-cyrus unix - n n - - pipe
# flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
uucp unix - n n - - pipe
flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#/var/www/html/.htaccess
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}
# The next two entries integrate with Amavis for anti-virus/spam checks.
amavis unix - - - - 3 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
-o max_use=20
127.0.0.1:10025 inet n - - - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_delay_reject=no
-o smtpd_client_restrictions=permit_mynetworks,reject
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o smtpd_data_restrictions=reject_unauth_pipelining
-o smtpd_end_of_data_restrictions=
-o mynetworks=127.0.0.0/8
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
-o smtpd_client_connection_count_limit=0
-o smtpd_client_connection_rate_limit=0
-o receive_override_options=no_header_body_checks,no_unknown_recipient_checks
# Integration with Dovecot - hand mail over to it for local delivery, and
# run the process under the vmail user and mail group.
dovecot unix - n n - - pipe
flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -d $(recipient)');
}


function RestartAll()
# Mail database
{
Execute('service postfix restart');
Execute('service spamassassin restart');
Execute('service clamav-daemon restart');
Execute('service amavis restart');
Execute('service dovecot restart');
}


function InstallRoundCube()
mysql -uroot -p${ROOT_PASSWORD} -Bse \
{
"create database mail;
Execute('apt-get install --assume-yes \
grant all on mail.* to 'mail'@'localhost' identified by 'mailpassword';"
roundcube \
roundcube-plugins \
roundcube-plugins-extra');
UpdatePHPConfigFile('/etc/roundcube/main.inc.php', 'rcmail_config', array(
array('name' => 'default_host', 'value' => "'localhost'"),
array('name' => 'force_https', 'value' => 'true'),
array('name' => 'imap_cache', 'value' => "'memcache'"),
array('name' => 'session_storage', 'value' => "'memcache'"),
array('name' => 'memcache_hosts', 'value' => "array('localhost:11211')"),
));
Execute('ln -s /var/lib/roundcube /var/www/html/roundcube');
if(file_exists('/var/www/html/index.html'))
Execute('mv /var/www/html/index.html /var/www/html/index.bak.html');
file_put_contents('/var/www/html/.htaccess', 'RewriteEngine On
# Redirect all HTTP traffic to HTTPS.
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
# Send / to /roundcube.
RewriteRule ^/?$ /roundcube [L]');
}


function InstallMonit()
# Postfix
{
Execute('apt-get install --assume-yes monit');
file_put_contents('/etc/monit/conf.d/amavis',
'check process amavisd with pidfile /var/run/amavis/amavisd.pid
every 5 cycles
group mail
start program = "/etc/init.d/amavis start"
stop program = "/etc/init.d/amavis stop"
if failed port 10024 protocol smtp then restart
if 5 restarts within 25 cycles then timeout');
file_put_contents('/etc/monit/conf.d/apache2',
'check process apache2 with pidfile /var/run/apache2/apache2.pid
group www
start program = "/etc/init.d/apache2 start"
stop program = "/etc/init.d/apache2 stop"
if failed host localhost port 80 protocol http
with timeout 10 seconds
then restart
if 5 restarts within 5 cycles then timeout');
file_put_contents('/etc/monit/conf.d/dovecot',
'check process dovecot with pidfile /var/run/dovecot/master.pid
group mail
start program = "/sbin/start dovecot"
stop program = "/sbin/stop dovecot"
group mail
# We\'d like to use this line, but see:
# http://serverfault.com/questions/610976/monit-failing-to-connect-to-dovecot-over-ssl-imap
#if failed port 993 type tcpssl sslauto protocol imap for 5 cycles then restart
if failed port 993 for 5 cycles then restart
if 5 restarts within 25 cycles then timeout');
file_put_contents('/etc/monit/conf.d/mysql',
'check process mysqld with pidfile /var/run/mysqld/mysqld.pid
group database
start program = "/etc/init.d/mysql start"
stop program = "/etc/init.d/mysql stop"
if failed host localhost port 3306 protocol mysql then restart
if 5 restarts within 5 cycles then timeout');
file_put_contents('/etc/monit/conf.d/memcached',
'check process memcached with pidfile /var/run/memcached.pid
group www
start program = "/etc/init.d/memcached start"
stop program = "/etc/init.d/memcached stop"
if failed host localhost port 11211 then restart
if 5 restarts within 5 cycles then timeout');
file_put_contents('/etc/monit/conf.d/postfix',
'check process postfix with pidfile /var/spool/postfix/pid/master.pid
group mail
start program = "/etc/init.d/postfix start"
stop program = "/etc/init.d/postfix stop"
if failed port 25 protocol smtp then restart
if 5 restarts within 5 cycles then timeout');
file_put_contents('/etc/monit/conf.d/spamassassin',
'check process spamassassin with pidfile /var/run/spamd.pid
group mail
start program = "/etc/init.d/spamassassin start"
stop program = "/etc/init.d/spamassassin stop"
if 5 restarts within 5 cycles then timeout');
file_put_contents('/etc/monit/conf.d/sshd',
'check process sshd with pidfile /var/run/sshd.pid
start program "/etc/init.d/ssh start"
stop program "/etc/init.d/ssh stop"
if failed host 127.0.0.1 port 22 protocol ssh then restart
if 5 restarts within 5 cycles then timeout');
Execute('service monit restart');
}


InstallPackages();
wget http://downloads.sourceforge.net/project/postfixadmin/postfixadmin/postfixadmin-2.3.7/postfixadmin-2.3.7.tar.gz
PrepareDatabase();
tar -xf postfixadmin-2.3.7.tar.gz
InstallPostfixAdmin();
rm -f postfixadmin-2.3.7.tar.gz
VirtualMailUser();
mv postfixadmin-2.3.7 /var/www/html/postfixadmin
ConfigureDovecot();
chown -R www-data:www-data /var/www/html/postfixadmin
SpamVirus();
ConfigurePostfix();
RestartAll();
InstallMonit();
InstallRoundCube();


</pre>
</source>





Verze z 9. 12. 2014, 00:18

Návod popisuje instalace poštovního serveru s virtuálními účty v MySQL databázi.

  • Budou použity následují komponenty:
    • postfix - SMTP server
    • dovecot - IMAP server
    • roundcubemail - web mail klient
    • postfixadmin - správa schránek


Instalační skript

Většina návodů je provedena jako dlouhý popis postupu s mnoha útržkovými částmi příkazů, které je potřeba provést. To je zdlouhavý proces kopírovat jednotlivé části povelů a po částech je provádět. Místo toho bychom rádi měli jednoduchou instalaci, kterou prostě spustíme, chvíli počkáme a máme hotovo. Zde je předložen skript, který se toto dle jednoho návodu snaží docílit.

<?php

$MysqlRootPassword = 'MysqlRootPassword';
$MysqlUserPassword = 'MysqlUserPassword';
$PostfixAdminName = 'PostfixAdminName';
$PostfixSetupPassword = 'PostfixSetupPassword';
$DomainName = 'domain.com';
$ServerDomain = 'mail.'.$DomainName;

function Execute($Command)
{
  echo('Executing: '.$Command."\n");
  passthru($Command);
}

function InstallPackages()
{
  // LAMP web server
  Execute('apt-get update');
  Execute('apt-get upgrade --assume-yes');
  Execute('apt-get install --assume-yes lamp-server^');

  Execute('apt-get install --assume-yes \
  php-apc \
  php5-mcrypt \
  php5-memcache \
  php5-curl \
  php5-gd \
  php-xml-parser');

  Execute('ln -sf ../../mods-available/mcrypt.ini /etc/php5/apache2/conf.d/20-mcrypt.ini');

  // Configure apache
  Execute('a2enmod rewrite ssl');
  Execute('a2ensite default-ssl');

  Execute('service apache2 restart');

  // Memcached
  Execute('apt-get install --assume-yes memcached');
 
  // Mail packages
  Execute('apt-get install --assume-yes mail-server^');

  Execute('apt-get install --assume-yes \
  postfix-mysql \
  dovecot-mysql \
  postgrey \
  amavis \
  clamav \
  clamav-daemon \
  spamassassin \
  php5-imap');

  Execute('ln -sf ../../mods-available/imap.ini /etc/php5/apache2/conf.d/20-imap.ini');

  Execute('service apache2 restart');

  Execute('apt-get install --assume-yes \
  pyzor \
  razor \
  arj \
  cabextract \
  lzop \
  nomarch \
  p7zip-full \
  ripole \
  rpm2cpio \
  tnef \
  unzip \
  unrar-free \
  zip \
  zoo');
}

function PrepareDatabase()
{
  global $MysqlUserPassword, $MysqlRootPassword;
  // Mail database

  Execute('mysql -uroot -p'.$MysqlRootPassword.' -Bse \
"drop database mail; create database mail;
grant all on mail.* to \'mail\'@\'localhost\' identified by \''.$MysqlUserPassword.'\';"');
}

function UpdatePHPConfigFile($FileName, $BaseVariable, $Parameters)
{
  if(!file_exists($FileName.'_backup'))
    file_put_contents($FileName.'_backup', file_get_contents($FileName));    
  $Content = explode("\n", file_get_contents($FileName.'_backup'));
  foreach($Parameters as $Parameter)
  {
    
    if(is_array($Parameter['name'])) {      
      foreach($Content as $Num => $Line)
      {
        $Needle = '$'.$BaseVariable.'['."'".$Parameter['name'][0]."'] = array (";      
        if(substr($Line, 0, strlen($Needle)) == $Needle)
        {          
          echo('Found group: '.$Parameter['name'][0]."\n");
          $Needle = "    '".$Parameter['name'][1]."' => ";      
          $I = 1;
          while((($Num + $I) < count($Content)) and ($Content[$Num + $I] != ');')) 
          {
            if(substr($Content[$Num + $I], 0, strlen($Needle)) == $Needle) {   
              echo('Found group: '.$Parameter['name'][1]."\n");
              $Content[$Num + $I] = $Needle.$Parameter['value'].',';              
            }
            $I++;
          }
        }
      }
    } else {
      foreach($Content as $Num => $Line)
      {
        $Needle = '$'.$BaseVariable.'['."'".$Parameter['name']."'] = ";      
        if(substr($Line, 0, strlen($Needle)) == $Needle)
        {
          echo('Found: '.$Parameter['name']."\n");
          $Content[$Num] = $Needle.$Parameter['value'].';';
        }
      }
    }
  }
  file_put_contents($FileName, implode("\n", $Content));
  
}

function generate_setup_password_salt() 
{
  $salt = time().'*'.mt_rand(0,60000);
  $salt = md5($salt);
  return $salt;
}

function encrypt_setup_password($password, $salt) 
{
  return $salt . ':' . sha1($salt . ':' . $password);
}

function InstallPostfixAdmin()
{
  global $ServerDomain, $PostfixAdminName, $MysqlUserPassword, $PostfixSetupPassword, $DomainName;
  
  Execute('wget "http://downloads.sourceforge.net/project/postfixadmin/postfixadmin/'.
    $PostfixAdminName.'/'.$PostfixAdminName.'.tar.gz?r=&ts=1417890779&use_mirror=netcologne" -O '.
    $PostfixAdminName.'.tar.gz');
  Execute('tar -xf '.$PostfixAdminName.'.tar.gz');
  Execute('rm -f '.$PostfixAdminName.'.tar.gz');
  Execute('mv '.$PostfixAdminName.' /var/www/html/postfixadmin');
  Execute('chown -R www-data:www-data /var/www/html/postfixadmin');

  UpdatePHPConfigFile('/var/www/html/postfixadmin/config.inc.php', 'CONF', array(
    array('name' => 'setup_password', 'value' => "'".encrypt_setup_password($PostfixSetupPassword, generate_setup_password_salt())."'"),
    array('name' => 'configured', 'value' => 'true'),
    array('name' => 'postfix_admin_url', 'value' => "'https://".$ServerDomain."/postfixadmin'"),
    array('name' => 'database_type', 'value' => "'mysql'"),
    array('name' => 'database_host', 'value' => "'localhost'"),
    array('name' => 'database_user', 'value' => "'mail'"),
    array('name' => 'database_password', 'value' => "'".$MysqlUserPassword."'"),
    array('name' => 'database_name', 'value' => "'mail'"),
    array('name' => 'admin_email', 'value' => "'admin@".$DomainName."'"),
    array('name' => 'user_footer_link', 'value' =>  "'https://".$ServerDomain."/main.php'"),
    array('name' => 'show_footer_text', 'value' => "'YES'"),
    array('name' => 'footer_text', 'value' => "'Return to ".$ServerDomain."'"),
    array('name' => 'footer_link', 'value' => "'https://".$ServerDomain."'"),
    array('name' => array('default_aliases', 'abuse'), 'value'  => "'abuse@".$DomainName."'"),
    array('name' => array('default_aliases', 'hostmaster'), 'value' => "'hostmaster@".$DomainName."'"),
    array('name' => array('default_aliases', 'postmaster'), 'value' => "'postmaster@".$DomainName."'"),
    array('name' => array('default_aliases', 'webmaster'), 'value' => "'webmaster@".$DomainName."'"),
  ));

}

function VirtualMailUser()
{
  Execute('useradd -r -u 150 -g mail -d /var/vmail -s /sbin/nologin -c "Virtual maildir handler" vmail');
  Execute('mkdir /var/vmail');
  Execute('chmod 770 /var/vmail');
  Execute('chown vmail:mail /var/vmail');
}

function UpdateDovecotConfigFile($FileName, $Parameters)
{
  if(!file_exists($FileName.'_backup'))
    file_put_contents($FileName.'_backup', file_get_contents($FileName));    
  $Content = explode("\n", file_get_contents($FileName.'_backup'));
  foreach($Parameters as $Parameter)
  { 
    if(!is_array($Parameter['name'])) 
      $Parameter['name'] = array($Parameter['name']);
    // First find subgroup
    $Num = 0;
    $NestingLevel = 0;
    while(count($Parameter['name']) > 1)  
    {
      $Found = false;
      $Needle = '#'.array_values($Parameter['name'])[0].' {';
      $I = 0;
      $StartNestingLevel = $NestingLevel;     
      while((($Num + $I) < count($Content)) and ($NestingLevel >= $StartNestingLevel)) 
      {
        if(substr(trim($Content[$Num + $I]), -1, 1) == '{') $NestingLevel++;
        if(substr(trim($Content[$Num + $I]), -1, 1) == '}') $NestingLevel--;
        if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
        or (trim(substr(trim($Content[$Num + $I]), 0, strlen(substr($Needle, 1)))) == substr($Needle, 1)))
        {
          $Content[$Num + $I] = array_values($Parameter['name'])[0].' {';
          $Num = $Num + $I + 1;
          $Found = true;
          echo('Found group: '.array_values($Parameter['name'])[0]."\n");
          array_shift($Parameter['name']);
          break;
        }
        $I++;
      }
      if(!$Found) break;
    } 
    // Find and replace value
    if(count($Parameter['name']) == 1)
    {
      if(!array_key_exists('value', $Parameter)) 
      {
        $Needle = array_values($Parameter['name'])[0];      
        $Parameter['value'] = '';
      } else 
        $Needle = array_values($Parameter['name'])[0]." =";      
      $I = 0;
      $StartNestingLevel = $NestingLevel;
      $Found = false;
      while((($Num + $I) < count($Content)) and ($NestingLevel >= $StartNestingLevel))
      {
        if(substr(trim($Content[$Num + $I]), -1, 1) == '{') $NestingLevel++;
        if(substr(trim($Content[$Num + $I]), -1, 1) == '}')
        {
          if($NestingLevel == $StartNestingLevel) $Content[$Num + $I] = '}';
          $NestingLevel--;
        }
        if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
        or ((substr(trim($Content[$Num + $I]), 0, 1) == '#') and (substr(trim(substr(trim($Content[$Num + $I]), 1)), 0, strlen($Needle)) == $Needle)))
        {
          echo('Found: '.array_values($Parameter['name'])[0]."\n");
          $Content[$Num + $I] = $Needle.' '.$Parameter['value'];
          $Found = true;
          break;
        }
        $I++;
      }
      // If not found then add new value
      if($Found == false)
      {
        echo('Added new: '.array_values($Parameter['name'])[0]."\n");
        array_splice($Content, $Num + $I - 1, 0, $Needle.' '.$Parameter['value']);
      }
    }
  }
  file_put_contents($FileName, implode("\n", $Content));
}

function ConfigureDovecot()
{
  global $MysqlUserPassword, $DomainName;
  
  UpdateDovecotConfigFile('/etc/dovecot/dovecot-sql.conf.ext', array(
    array('name' => 'driver', 'value' => 'mysql'),
    array('name' => 'connect', 'value' => 'host=localhost dbname=mail user=mail password='.$MysqlUserPassword),
    array('name' => 'default_pass_scheme', 'value' => 'MD5-CRYPT'),
    array('name' => 'password_query', 'value' => "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'"),
    array('name' => 'user_query', 'value' => "SELECT '/var/vmail/%d/%n' as home, 'maildir:/var/vmail/%d/%n' as mail, \\
  150 AS uid, 8 AS gid, concat('dirsize:storage=', quota) AS quota \\
  FROM mailbox WHERE username = '%u' AND active = '1'"),
  ));
  UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-auth.conf', array(
    array('name' => 'disable_plaintext_auth', 'value' => 'yes'),
    array('name' => 'auth_mechanisms', 'value' => 'plain login'),
    array('name' => '!include auth-sql.conf.ext'),
  ));
  UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-mail.conf', array(
    array('name' => 'mail_location', 'value' => 'maildir:/var/vmail/%d/%n'),
    array('name' => 'mail_uid', 'value' => 'vmail'),
    array('name' => 'mail_gid', 'value' => 'mail'),
    array('name' => 'first_valid_uid', 'value' => '150'),
    array('name' => 'last_valid_uid', 'value' => '150'),
  ));
  UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-ssl.conf', array(
    array('name' => 'ssl_cert', 'value' => '</etc/ssl/certs/'.$DomainName.'.crt'),
    array('name' => 'ssl_key', 'value' => '</etc/ssl/private/'.$DomainName.'.key'),
    array('name' => 'ssl_ca', 'value' => '</etc/ssl/certs/ca-bundle.crt'),
    array('name' => 'ssl_cipher_list', 'value' => 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS'),
  ));
  UpdateDovecotConfigFile('/etc/dovecot/conf.d/10-master.conf', array(
    array('name' => array('service auth', 'unix_listener auth-userdb', 'mode'), 'value' => '0666'),
    array('name' => array('service auth', 'unix_listener auth-userdb', 'user'), 'value' => 'vmail'),
    array('name' => array('service auth', 'unix_listener auth-userdb', 'group'), 'value' => 'mail'),
    array('name' => array('service auth', 'unix_listener /var/spool/postfix/private/auth', 'mode'), 'value' => '0666'),
    array('name' => array('service auth', 'unix_listener /var/spool/postfix/private/auth', 'user'), 'value' => 'postfix'),
    array('name' => array('service auth', 'unix_listener /var/spool/postfix/private/auth', 'group'), 'value' => 'postfix'),
  ));
  UpdateDovecotConfigFile('/etc/dovecot/conf.d/15-lda.conf', array(
    array('name' => 'postmaster_address', 'value' => 'postmaster@'.$DomainName),
  ));
  
  Execute('chown -R vmail:dovecot /etc/dovecot');
  Execute('chmod -R o-rwx /etc/dovecot');
}

function UpdateAmavisConfigFile($FileName, $Parameters)
{
  if(!file_exists($FileName.'_backup'))
    file_put_contents($FileName.'_backup', file_get_contents($FileName));    
  $Content = explode("\n", file_get_contents($FileName.'_backup'));
  if(count($Content) > 0)
  {
    // Remove ending part
    $I = count($Content) - 1;
    while(($I >= 0))
    {  
      if($Content[$I] != '#------------ Do not modify anything below this line -------------')
        array_pop($Content);
        else {
          array_pop($Content);
          break;
        }
      $I--;
    }
  }
  
  foreach($Parameters as $Parameter)
  { 
    $Parameter['name'] = array($Parameter['name']);
    $Num = 0;
    if(!array_key_exists('value', $Parameter)) 
    {
      $Needle = array_values($Parameter['name'])[0];      
      $Parameter['value'] = '';
    } else 
      $Needle = array_values($Parameter['name'])[0]." =";      
    $I = 0;
    $Found = false;
    while((($Num + $I) < count($Content)))
    {
      if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
      or ((substr(trim($Content[$Num + $I]), 0, 1) == '#') and (substr(trim(substr(trim($Content[$Num + $I]), 1)), 0, strlen($Needle)) == $Needle)))
      {
        echo('Found: '.array_values($Parameter['name'])[0]."\n");
        $Content[$Num + $I] = $Needle.' '.$Parameter['value'];
        $Found = true;
        break;
      }
      $I++;
    }
    // If not found then add new value
    if($Found == false)
    {
      echo('Added new: '.array_values($Parameter['name'])[0]."\n");
      array_splice($Content, $Num + $I - 1, 0, $Needle.' '.$Parameter['value']);
    }  
  }
  $Content[] = '#------------ Do not modify anything below this line -------------';
  $Content[] = '1;  # ensure a defined return';
  file_put_contents($FileName, implode("\n", $Content));
}

function UpdateDefaultConfigFile($FileName, $Parameters)
{
  if(!file_exists($FileName.'_backup'))
    file_put_contents($FileName.'_backup', file_get_contents($FileName));    
  $Content = explode("\n", file_get_contents($FileName.'_backup'));
  foreach($Parameters as $Parameter)
  { 
    if(!is_array($Parameter['name'])) 
      $Parameter['name'] = array($Parameter['name']);
    $Num = 0;
    // Find and replace value
    if(count($Parameter['name']) == 1)
    {
      if(!array_key_exists('value', $Parameter)) 
      {
        $Needle = array_values($Parameter['name'])[0];      
        $Parameter['value'] = '';
      } else 
        $Needle = array_values($Parameter['name'])[0]."=";
      $I = 0;
      $Found = false;
      while((($Num + $I) < count($Content)))
      {
        if((trim(substr(trim($Content[$Num + $I]), 0, strlen($Needle))) == $Needle)
        or ((substr(trim($Content[$Num + $I]), 0, 1) == '#') and (substr(trim(substr(trim($Content[$Num + $I]), 1)), 0, strlen($Needle)) == $Needle)))
        {
          echo('Found: '.array_values($Parameter['name'])[0]."\n");
          $Content[$Num + $I] = $Needle.$Parameter['value'];
          $Found = true;
          break;
        }
        $I++;
      }
      // If not found then add new value
      if($Found == false)
      {
        echo('Added new: '.array_values($Parameter['name'])[0]."\n");
        array_splice($Content, $Num + $I - 1, 0, $Needle.' '.$Parameter['value']);
      }
    }
  }
  file_put_contents($FileName, implode("\n", $Content));  
}

function SpamVirus()
{
  Execute('adduser clamav amavis');
  Execute('adduser amavis clamav');
  UpdateAmavisConfigFile('/etc/amavis/conf.d/15-content_filter_mode', array(
    array('name' => '@bypass_virus_checks_maps', 'value' => '(\%bypass_virus_checks, \@bypass_virus_checks_acl, \$bypass_virus_checks_re);'),
    array('name' => '@bypass_spam_checks_maps', 'value' => '(\%bypass_spam_checks, \@bypass_spam_checks_acl, \$bypass_spam_checks_re);'),
  ));
  UpdateDefaultConfigFile('/etc/default/spamassassin', array(
    array('name' => 'ENABLED', 'value' => '1'),
    array('name' => 'CRON', 'value' => '1'),
  ));
  UpdateAmavisConfigFile('/etc/amavis/conf.d/50-user', array(
    array('name' => '$max_servers', 'value' => '3;'),
    array('name' => '$sa_tag_level_deflt', 'value' => '-9999;'),
    array('name' => '@lookup_sql_dsn', 'value' => "(
    ['DBI:mysql:database=mail;host=127.0.0.1;port=3306',
     'mail',
     'mailpassword']);"),     
    array('name' => '$sql_select_policy', 'value' => "'SELECT domain from domain WHERE CONCAT(\"@\",domain) IN (%k)';"),
  ));
  Execute('freshclam');
  Execute('service clamav-daemon restart');
  Execute('service amavis restart');
  Execute('service spamassassin restart');  
}

function ConfigurePostfix()
{
  file_put_contents('/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf', 
  "user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
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");
  file_put_contents('/etc/postfix/mysql_virtual_alias_maps.cf', 
  "user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
table = alias
select_field = goto
where_field = address
additional_conditions = and active = '1'");
  file_put_contents('/etc/postfix/mysql_virtual_domains_maps.cf', 
  "user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
table = domain
select_field = domain
where_field = domain
additional_conditions = and backupmx = '0' and active = '1'");
  file_put_contents('/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf',
  "user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
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");
  file_put_contents('/etc/postfix/mysql_virtual_mailbox_maps.cf',
  "user = mail
password = mailpassword
hosts = 127.0.0.1
dbname = mail
table = mailbox
select_field = CONCAT(domain, '/', local_part)
where_field = username
additional_conditions = and active = '1'");
  file_put_contents('/etc/postfix/header_checks',
  "/^Received:/                 IGNORE
/^User-Agent:/               IGNORE
/^X-Mailer:/                 IGNORE
/^X-Originating-IP:/         IGNORE
/^x-cr-[a-z]*:/              IGNORE
/^Thread-Index:/     
        IGNORE");
  if(!file_exists('/etc/postfix/main.cf_backup'))
    file_put_contents('/etc/postfix/main.cf_backup', file_get_contents('/etc/postfix/main.cf'));
  file_put_contents('/etc/postfix/main.cf',
  '# See /usr/share/postfix/main.cf.dist for a commented, more complete version
 
# The first text sent to a connecting process.
smtpd_banner = $myhostname ESMTP $mail_name
biff = no
# appending .domain is the MUA\'s job.
append_dot_mydomain = no
readme_directory = no
 
# SASL parameters
# ---------------------------------
 
# Use Dovecot to authenticate.
smtpd_sasl_type = dovecot
# Referring to /var/spool/postfix/private/auth
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
broken_sasl_auth_clients = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain =
smtpd_sasl_authenticated_header = yes
 
# TLS parameters
# ---------------------------------
 
# The default snakeoil certificate. Comment if using a purchased
# SSL certificate.
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
 
# Uncomment if using a purchased SSL certificate.
# smtpd_tls_cert_file=/etc/ssl/certs/example.com.crt
# smtpd_tls_key_file=/etc/ssl/private/example.com.key
 
# The snakeoil self-signed certificate has no need for a CA file. But
# if you are using your own SSL certificate, then you probably have
# a CA certificate bundle from your provider. The path to that goes
# here.
# smtpd_tls_CAfile=/etc/ssl/certs/ca-bundle.crt
 
# Ensure we\'re not using no-longer-secure protocols.
smtpd_tls_mandatory_protocols=!SSLv2,!SSLv3
 
smtp_tls_note_starttls_offer = yes
smtpd_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
tls_random_source = dev:/dev/urandom
#smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
#smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
 
# Note that forcing use of TLS is going to cause breakage - most mail servers
# don\'t offer it and so delivery will fail, both incoming and outgoing. This is
# unfortunate given what various governmental agencies are up to these days.
#
# Enable (but don\'t force) all incoming smtp connections to use TLS.
smtpd_tls_security_level = may
# Enable (but don\'t force) all outgoing smtp connections to use TLS.
smtp_tls_security_level = may
 
# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.
 
# SMTPD parameters
# ---------------------------------
 
# Uncomment the next line to generate \"delayed mail\" warnings
#delay_warning_time = 4h
# will it be a permanent error or temporary
unknown_local_recipient_reject_code = 450
# how long to keep message on queue before return as failed.
# some have 3 days, I have 16 days as I am backup server for some people
# whom go on holiday with their server switched off.
maximal_queue_lifetime = 7d
# max and min time in seconds between retries if connection failed
minimal_backoff_time = 1000s
maximal_backoff_time = 8000s
# how long to wait when servers connect before receiving rest of data
smtp_helo_timeout = 60s
# how many address can be used in one message.
# effective stopper to mass spammers, accidental copy in whole address list
# but may restrict intentional mail shots.
smtpd_recipient_limit = 16
# how many error before back off.
smtpd_soft_error_limit = 3
# how many max errors before blocking it.
smtpd_hard_error_limit = 12
 
# This next set are important for determining who can send mail and relay mail
# to other servers. It is very important to get this right - accidentally producing
# an open relay that allows unauthenticated sending of mail is a Very Bad Thing.
#
# You are encouraged to read up on what exactly each of these options accomplish.
 
# Requirements for the HELO statement
smtpd_helo_restrictions = permit_mynetworks, warn_if_reject reject_non_fqdn_hostname, reject_invalid_hostname, permit
# Requirements for the sender details
smtpd_sender_restrictions = permit_sasl_authenticated, permit_mynetworks, warn_if_reject reject_non_fqdn_sender, reject_unknown_sender_domain, reject_unauth_pipelining, permit
# Requirements for the connecting server
smtpd_client_restrictions = reject_rbl_client sbl.spamhaus.org, reject_rbl_client blackholes.easynet.nl, reject_rbl_client dnsbl.njabl.org
# Requirement for the recipient address. Note that the entry for
# \"check_policy_service inet:127.0.0.1:10023\" enables Postgrey.
smtpd_recipient_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service inet:127.0.0.1:10023, permit
smtpd_data_restrictions = reject_unauth_pipelining
# This is a new option as of Postfix 2.10, and is required in addition to
# smtpd_recipient_restrictions for things to work properly in this setup.
smtpd_relay_restrictions = reject_unauth_pipelining, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_recipient, reject_unknown_recipient_domain, reject_unauth_destination, check_policy_service inet:127.0.0.1:10023, permit
 
# require proper helo at connections
smtpd_helo_required = yes
# waste spammers time before rejecting them
smtpd_delay_reject = yes
disable_vrfy_command = yes
 
# General host and delivery info
# ----------------------------------
 
myhostname = mail.example.com
myorigin = /etc/hostname
# Some people see issues when setting mydestination explicitly to the server
# subdomain, while leaving it empty generally doesn\'t hurt. So it is left empty here.
# mydestination = mail.example.com, localhost
mydestination =
# If you have a separate web server that sends outgoing mail through this
# mailserver, you may want to add its IP address to the space-delimited list in
# mynetworks, e.g. as 10.10.10.10/32.
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
mynetworks_style = host
 
# This specifies where the virtual mailbox folders will be located.
virtual_mailbox_base = /var/vmail
# This is for the mailbox location for each user. The domainaliases
# map allows us to make use of Postfix Admin\'s domain alias feature.
virtual_mailbox_maps = mysql:/etc/postfix/mysql_virtual_mailbox_maps.cf, mysql:/etc/postfix/mysql_virtual_mailbox_domainaliases_maps.cf
# and their user id
virtual_uid_maps = static:150
# and group id
virtual_gid_maps = static:8
# This is for aliases. The domainaliases map allows us to make
# use of Postfix Admin\'s domain alias feature.
virtual_alias_maps = mysql:/etc/postfix/mysql_virtual_alias_maps.cf, mysql:/etc/postfix/mysql_virtual_alias_domainaliases_maps.cf
# This is for domain lookups.
virtual_mailbox_domains = mysql:/etc/postfix/mysql_virtual_domains_maps.cf
 
# Integration with other packages
# ---------------------------------------
 
# Tell postfix to hand off mail to the definition for dovecot in master.cf
virtual_transport = dovecot
dovecot_destination_recipient_limit = 1
 
# Use amavis for virus and spam scanning
content_filter = amavis:[127.0.0.1]:10024
 
# Header manipulation
# --------------------------------------
 
# Getting rid of unwanted headers. See: https://posluns.com/guides/header-removal/
header_checks = regexp:/etc/postfix/header_checks
# getting rid of x-original-to
enable_original_recipient = no');

  if(!file_exists('/etc/postfix/master.cf_backup'))
    file_put_contents('/etc/postfix/master.cf_backup', file_get_contents('/etc/postfix/master.cf'));
  file_put_contents('/etc/postfix/master.cf', 
  '#
# Postfix master process configuration file.  For details on the format
# of the file, see the master(5) manual page (command: \"man 5 master\").
#
# Do not forget to execute \"postfix reload\" after editing this file.
#
# ==========================================================================
# service type  private unpriv  chroot  wakeup  maxproc command + args
#               (yes)   (yes)   (yes)   (never) (100)
# ==========================================================================
 
# SMTP on port 25, unencrypted.
smtp      inet  n       -       -       -       -       smtpd
#smtp      inet  n       -       -       -       1       postscreen
#smtpd     pass  -       -       -       -       -       smtpd
#dnsblog   unix  -       -       -       -       0       dnsblog
#tlsproxy  unix  -       -       -       -       0       tlsproxy
 
# SMTP with TLS on port 587. Currently commented.
#submission inet n       -       -       -       -       smtpd
#  -o syslog_name=postfix/submission
#  -o smtpd_tls_security_level=encrypt
#  -o smtpd_sasl_auth_enable=yes
#  -o smtpd_enforce_tls=yes
#  -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
#  -o smtpd_sasl_tls_security_options=noanonymous
 
# SMTP over SSL on port 465.
smtps     inet  n       -       -       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject_unauth_destination,reject
  -o smtpd_sasl_security_options=noanonymous,noplaintext
  -o smtpd_sasl_tls_security_options=noanonymous
 
#628       inet  n       -       -       -       -       qmqpd
pickup    fifo  n       -       -       60      1       pickup
  -o content_filter=
  -o receive_override_options=no_header_body_checks
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
#       -o smtp_helo_timeout=5 -o smtp_connect_timeout=5
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
#
# ====================================================================
# Interfaces to non-Postfix software. Be sure to examine the manual
# pages of the non-Postfix software to find out what options it wants.
#
# Many of the following services use the Postfix pipe(8) delivery
# agent.  See the pipe(8) man page for information about ${recipient}
# and other message envelope options.
# ====================================================================
#
# maildrop. See the Postfix MAILDROP_README file for details.
# Also specify in main.cf: maildrop_destination_recipient_limit=1
#
maildrop  unix  -       n       n       -       -       pipe
  flags=DRhu user=vmail argv=/usr/bin/maildrop -d ${recipient}
#
# ====================================================================
#
# Recent Cyrus versions can use the existing \"lmtp\" master.cf entry.
#
# Specify in cyrus.conf:
#   lmtp    cmd=\"lmtpd -a\" listen=\"localhost:lmtp\" proto=tcp4
#
# Specify in main.cf one or more of the following:
#  mailbox_transport = lmtp:inet:localhost
#  virtual_transport = lmtp:inet:localhost
#
# ====================================================================
#
# Cyrus 2.1.5 (Amos Gouaux)
# Also specify in main.cf: cyrus_destination_recipient_limit=1
#
#cyrus     unix  -       n       n       -       -       pipe
#  user=cyrus argv=/cyrus/bin/deliver -e -r ${sender} -m ${extension} ${user}
#
# ====================================================================
# Old example of delivery via Cyrus.
#
#old-cyrus unix  -       n       n       -       -       pipe
#  flags=R user=cyrus argv=/cyrus/bin/deliver -e -m ${extension} ${user}
#
# ====================================================================
#
# See the Postfix UUCP_README file for configuration details.
#
uucp      unix  -       n       n       -       -       pipe
  flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
#
# Other external delivery methods.
#/var/www/html/.htaccess
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}
 
# The next two entries integrate with Amavis for anti-virus/spam checks.
amavis      unix    -       -       -       -       3       smtp
  -o smtp_data_done_timeout=1200
  -o smtp_send_xforward_command=yes
  -o disable_dns_lookups=yes
  -o max_use=20
127.0.0.1:10025 inet    n       -       -       -       -       smtpd
  -o content_filter=
  -o local_recipient_maps=
  -o relay_recipient_maps=
  -o smtpd_restriction_classes=
  -o smtpd_delay_reject=no
  -o smtpd_client_restrictions=permit_mynetworks,reject
  -o smtpd_helo_restrictions=
  -o smtpd_sender_restrictions=
  -o smtpd_recipient_restrictions=permit_mynetworks,reject
  -o smtpd_data_restrictions=reject_unauth_pipelining
  -o smtpd_end_of_data_restrictions=
  -o mynetworks=127.0.0.0/8
  -o smtpd_error_sleep_time=0
  -o smtpd_soft_error_limit=1001
  -o smtpd_hard_error_limit=1000
  -o smtpd_client_connection_count_limit=0
  -o smtpd_client_connection_rate_limit=0
  -o receive_override_options=no_header_body_checks,no_unknown_recipient_checks
 
# Integration with Dovecot - hand mail over to it for local delivery, and
# run the process under the vmail user and mail group.
dovecot      unix   -        n      n       -       -   pipe
  flags=DRhu user=vmail:mail argv=/usr/lib/dovecot/dovecot-lda -d $(recipient)');
}

function RestartAll()
{
  Execute('service postfix restart');
  Execute('service spamassassin restart');
  Execute('service clamav-daemon restart');
  Execute('service amavis restart');
  Execute('service dovecot restart');
}

function InstallRoundCube()
{
  Execute('apt-get install --assume-yes \
  roundcube \
  roundcube-plugins \
  roundcube-plugins-extra');
  UpdatePHPConfigFile('/etc/roundcube/main.inc.php', 'rcmail_config', array(
    array('name' => 'default_host', 'value' => "'localhost'"),
    array('name' => 'force_https', 'value' => 'true'),
    array('name' => 'imap_cache', 'value' => "'memcache'"),
    array('name' => 'session_storage', 'value' => "'memcache'"),
    array('name' => 'memcache_hosts', 'value' => "array('localhost:11211')"),
  ));
  Execute('ln -s /var/lib/roundcube /var/www/html/roundcube');
  if(file_exists('/var/www/html/index.html'))
    Execute('mv /var/www/html/index.html /var/www/html/index.bak.html');
  file_put_contents('/var/www/html/.htaccess', 'RewriteEngine On
 
# Redirect all HTTP traffic to HTTPS.
RewriteCond %{HTTPS} !=on
RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
 
# Send / to /roundcube.
RewriteRule ^/?$ /roundcube [L]');
}

function InstallMonit()
{
  Execute('apt-get install --assume-yes monit');
  file_put_contents('/etc/monit/conf.d/amavis', 
  'check process amavisd with pidfile /var/run/amavis/amavisd.pid
  every 5 cycles
  group mail
  start program = "/etc/init.d/amavis start"
  stop  program = "/etc/init.d/amavis stop"
  if failed port 10024 protocol smtp then restart
  if 5 restarts within 25 cycles then timeout');
  file_put_contents('/etc/monit/conf.d/apache2', 
  'check process apache2 with pidfile /var/run/apache2/apache2.pid
  group www
  start program = "/etc/init.d/apache2 start"
  stop program = "/etc/init.d/apache2 stop"
  if failed host localhost port 80 protocol http
    with timeout 10 seconds
    then restart
  if 5 restarts within 5 cycles then timeout');
  file_put_contents('/etc/monit/conf.d/dovecot',
  'check process dovecot with pidfile /var/run/dovecot/master.pid
  group mail
  start program = "/sbin/start dovecot"
  stop program = "/sbin/stop dovecot"
  group mail
  # We\'d like to use this line, but see:
  # http://serverfault.com/questions/610976/monit-failing-to-connect-to-dovecot-over-ssl-imap
  #if failed port 993 type tcpssl sslauto protocol imap for 5 cycles then restart
  if failed port 993 for 5 cycles then restart
  if 5 restarts within 25 cycles then timeout');
  file_put_contents('/etc/monit/conf.d/mysql',
  'check process mysqld with pidfile /var/run/mysqld/mysqld.pid
  group database
  start program = "/etc/init.d/mysql start"
  stop program = "/etc/init.d/mysql stop"
  if failed host localhost port 3306 protocol mysql then restart
  if 5 restarts within 5 cycles then timeout');
  file_put_contents('/etc/monit/conf.d/memcached',
  'check process memcached with pidfile /var/run/memcached.pid
  group www
  start program = "/etc/init.d/memcached start"
  stop program = "/etc/init.d/memcached stop"
  if failed host localhost port 11211 then restart
  if 5 restarts within 5 cycles then timeout');
  file_put_contents('/etc/monit/conf.d/postfix',
  'check process postfix with pidfile /var/spool/postfix/pid/master.pid
  group mail
  start program = "/etc/init.d/postfix start"
  stop  program = "/etc/init.d/postfix stop"
  if failed port 25 protocol smtp then restart
  if 5 restarts within 5 cycles then timeout');
  file_put_contents('/etc/monit/conf.d/spamassassin',
  'check process spamassassin with pidfile /var/run/spamd.pid
  group mail
  start program = "/etc/init.d/spamassassin start"
  stop  program = "/etc/init.d/spamassassin stop"
  if 5 restarts within 5 cycles then timeout');
  file_put_contents('/etc/monit/conf.d/sshd',
  'check process sshd with pidfile /var/run/sshd.pid
  start program "/etc/init.d/ssh start"
  stop program "/etc/init.d/ssh stop"
  if failed host 127.0.0.1 port 22 protocol ssh then restart
   if 5 restarts within 5 cycles then timeout');
  Execute('service monit restart');
}

InstallPackages();
PrepareDatabase();
InstallPostfixAdmin();
VirtualMailUser();
ConfigureDovecot();
SpamVirus();
ConfigurePostfix();
RestartAll();
InstallMonit();
InstallRoundCube();


Vnější odkazy