Mail服务器:
基础准备:
postfix     发送 pop
dovect   imap 
postfixadmin  管理
MySQL    数据库
apache/nginx 
PHP
useradd -u 2000 -g 2000 apache
centos7

操作
一、解压MySQL
tar zxvf mysql-5.7.19

#tar zxf mysql-5.7.19-linux-glibc2.12-x86_64.tar
# tar zxf mysql-5.7.19-linux-glibc2.12-x86_64.tar.gz
# tar zxf mysql-test-5.7.19-linux-glibc2.12-x86_64.tar.gz
# mv mysql-5.7.19-linux-glibc2.12-x86_64 mysql
# mkdir basedata basedir
#useradd mysql
#vim /etc/my.cnf

[mysqld]
datadir=/data/basedata
basedir=/data/basedir
socket=/var/lib/mysql/mysql.sock
user=mysql
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
[mysql-client]
port = 3306
[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

# chown -R mysql.mysql basedata/
# chown -R mysql.mysql basedir/
# chown -R mysql.mysql mysql
# bin/mysqld --initialize --user=mysql --basedir=/data/basedir/ --datadir=/data/basedata/
[root@iZ88mizdnctZ mysql]# bin/mysqld_safe --user=mysql  &
2017-10-09T06:40:40.028358Z mysqld_safe Logging to '/var/log/mysqld.log'.
2017-10-09T06:40:40.049500Z mysqld_safe Starting mysqld daemon with databases from /data/basedata
2017-10-09T06:40:40.565019Z mysqld_safe mysqld from pid file /var/run/mysqld/mysqld.pid ended
[root@iZ88mizdnctZ mysql]# mkdir /var/run/mysqld
[root@iZ88mizdnctZ mysql]# chown -R mysql.mysql /var/run/mysqld/

# bin/mysql -uroot -p                                     --初始化密码
mysql>alter user 'root'@'localhost' identified by 'mysql123';
mysql>flush privileges;

# cp support-files/mysql.server /etc/init.d/mysqld

二、postfix安装
#yum -y install httpd mysql mysql-devel mysql-server php php-pecl-Fileinfo php-mcrypt php-devel php-mysql php-common php-mbstring php-gd php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc pcre pcre-devel

#vim /etc/httpd/conf/httpd.conf

AddType application/x-httpd-php .php
PHPIniDir "/etc/php.ini"

DirectoryIndex index.php index.html index.html.var

# vim /var/www/html/index.php 


#tar -zxvf postfixadmin-3.1.tar.gz  -C /var/www/html/
#mv postfixadmin-3.1/ postfixadmin
# vim config.inc.php
$CONF['configured'] = true;
$CONF['database_type'] = 'mysql';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'postfix';
$CONF['database_name'] = 'postfix';
$CONF['admin_email'] = '[email protected]';
$CONF['encrypt'] = 'dovecot:CRAM-MD5';
$CONF['dovecotpw'] = "/usr/bin/doveadm pw";
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['aliases'] = '1000';
$CONF['mailboxes'] = '1000';
$CONF['maxquota'] = '1000';
$CONF['fetchmail'] = 'NO';
$CONF['quota'] = 'YES';
$CONF['used_quotas'] = 'YES';
$CONF['new_quota_table'] = 'YES';

mysql> create database postfix;
Query OK, 1 row affected (0.00 sec)

mysql> create user postfix@localhost identified by 'postfixadmin';
Query OK, 0 rows affected (0.01 sec)

mysql> grant all privileges on postfix.* to postfix@localhost identified by 'postfixadmin';
Query OK, 0 rows affected, 1 warning (0.00 sec)

mysql> flush privileges;
Query OK, 0 rows affected (0.00 sec)

mysql> commit
        -> ;
Query OK, 0 rows affected (0.00 sec)

dns配置
# vim /etc/named.conf
options {
    listen-on port 53 { 172.24.17.62; };
    listen-on-v6 port 53 { ::1; };
    directory   "/var/named";
    dump-file   "/var/named/data/cache_dump.db";
                statistics-file "/var/named/data/named_stats.txt";
                memstatistics-file "/var/named/data/named_mem_stats.txt";
    allow-query     { any; };
    recursion yes;
    dnssec-enable yes;
    dnssec-validation yes;
    dnssec-lookaside auto;
    /* Path to ISC DLV key */
    bindkeys-file "/etc/named.iscdlv.key";
};
logging {
                channel default_debug {
                                file "data/named.run";
                                severity dynamic;
                };
};
zone "." IN {
    type hint;
    file "named.ca";
};
include "/etc/named.rfc1912.zones"

#vim /etc/named.rfc1912.zones
zone "dahan.org" IN {
    type master;
    file "dahan.org.zone";
    allow-update { none; };
};

# vim /var/named/dahan.org.zone
$TTL 1D
@   IN SOA  dahan.org. root.dahan.org. (
                    0   ; serial
                    1D  ; refresh
                    1H  ; retry
                    1W  ; expire
                    3H )    ; minimum
    IN  NS  ns.dahan.org.
    A   127.0.0.1
    AAAA    ::1
postfix IN  A   172.24.17.62
ns  IN  A   172.24.17.62
Z88a04bir7Z IN  A   172.24.17.62

postfixadmin配置

#tar -zxvf postfixadmin-3.1.tar.gz -C /var/www/html/
#cd /var/www/html
#mv postfixadmin-3.1 postfixadmin
# ll
total 32
-rwxr-xr-x  1 root   root   23834 Oct 11 15:23 config.inc.php
-rwxrwxr-x  1     48     48    20 Oct 11 14:55 index.php
drwxrwxr-x 16 apache apache  4096 Oct 13 11:06 postfixadmin

#vim /var/www/html/postfixadmin/config.inc.php
'
        Allows to add or override $PALANG interface texts.
        If you add new texts, please always prefix them with 'x_' (for example 
        $PALANG['x_mytext'] = 'foo') to avoid they clash with texts that might be
        added to languages/*.lang in future versions of PostfixAdmin.
        Please also make sure that all your added texts are included in all
        sections - that includes all 'case "XY":' sections and the 'default:'
        section (for users that don't have any of the languages specified
        in the 'case "XY":' section). 
        Usually the 'default:' section should contain english text.
        If you modify an existing text/translation, please consider to report it
        can benefit from the corrected text/translation.
        Returns: modified $PALANG array
*/
/*
function language_hook($PALANG, $language) {
        switch ($language) {
                case "de":
                        $PALANG['x_whatever'] = 'foo';
                        break;
                case "fr":
                        $PALANG['x_whatever'] = 'bar';
                        break;
                default:
                        $PALANG['x_whatever'] = 'foobar';
        }
        return $PALANG;
}
*/
$CONF['database_type'] = 'mysqli';
$CONF['database_host'] = 'localhost';
$CONF['database_user'] = 'postfix';
$CONF['database_password'] = 'postfixadmin';
$CONF['database_name'] = 'postfix';
$CONF['database_prefix'] = '';
$CONF['database_tables'] = array (
        'admin' => 'admin',
        'alias' => 'alias',
        'alias_domain' => 'alias_domain',
        'config' => 'config',
        'domain' => 'domain',
        'domain_admins' => 'domain_admins',
        'fetchmail' => 'fetchmail',
        'log' => 'log',
        'mailbox' => 'mailbox',
        'vacation' => 'vacation',
        'vacation_notification' => 'vacation_notification',
        'quota' => 'quota',
    'quota2' => 'quota2',
);
$CONF['admin_email'] = '[email protected]';
$CONF['smtp_server'] = 'localhost';
$CONF['smtp_port'] = '25';
$CONF['smtp_client'] = '';
$CONF['encrypt'] = 'dovecot:CRAM-MD5';
$CONF['authlib_default_flavor'] = 'md5raw';
$CONF['dovecotpw'] = "/usr/bin/doveadm pw";
if(file_exists('/usr/bin/doveadm')) {
        $CONF['dovecotpw'] = "/usr/bin/doveadm pw"; # debian
}
$CONF['password_validation'] = array(
        '/.{5}/'                => 'password_too_short 5',      # minimum length 5 characters
        '/([a-zA-Z].*){3}/'     => 'password_no_characters 3',  # must contain at least 3 characters
        '/([0-9].*){2}/'        => 'password_no_digits 2',      # must contain at least 2 digits
);
$CONF['generate_password'] = 'NO';
$CONF['show_password'] = 'NO';
$CONF['page_size'] = '10';
$CONF['default_aliases'] = array (
        'abuse' => '[email protected]',
        'hostmaster' => '[email protected]',
        'postmaster' => '[email protected]',
        'webmaster' => '[email protected]'
);
$CONF['domain_path'] = 'YES';
$CONF['domain_in_mailbox'] = 'NO';
$CONF['maildir_name_hook'] = 'NO';
/*
        maildir_name_hook example function

        Called when creating a mailbox if $CONF['maildir_name_hook'] == ''
        - allows for customized maildir paths determined by a custom function
        - the example below will prepend a single-character directory to the
            beginning of the maildir, splitting domains more or less evenly over
            36 directories for improved filesystem performance with large numbers
            of domains.
        Returns: maildir path
        ie. I/example.com/user/
*/
/*
function maildir_name_hook($domain, $user) {
        $chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $dir_index = hexdec(substr(md5($domain), 28)) % strlen($chars);
        $dir = substr($chars, $dir_index, 1);
        return sprintf("%s/%s/%s/", $dir, $domain, $user);
}
*/
/*  
        *_struct_hook - change, add or remove fields
        If you need additional fields or want to change or remove existing fields,
        you can write a hook function to modify $struct in the *Handler classes. 
        The edit form will automatically be updated according to the modified
        $struct. The list page is not yet updated automatically.
        You can define one hook function per class, named like the primary database
        table of that class.
        The hook function is called with $struct as parameter and must return the
        modified $struct. 
        Note: Adding a field to $struct adds the handling of this field in
        PostfixAdmin, but it does not create it in the database. You have to do
        that yourself. 
        Please follow the naming policy for custom database fields and tables on
        to avoid clashes with future versions of PostfixAdmin.
        See initStruct() in the *Handler class for the default $struct.
        See pacol() in functions.inc.php for the available flags on each column.

        Example:
        function x_struct_admin_modify($struct) {
                $struct['superadmin']['editable'] = 0;          # make the 'superadmin' flag read-only
                $struct['superadmin']['display_in_form'] = 0;   # don't display the 'superadmin' flag in edit form
                $struct['x_newfield'] = pacol( [...] );        # additional field 'x_newfield'
                return $struct; # important!
        }
        $CONF['admin_struct_hook'] = 'x_struct_admin_modify';
*/
$CONF['admin_struct_hook']          = '';
$CONF['domain_struct_hook']         = '';
$CONF['alias_struct_hook']          = '';
$CONF['mailbox_struct_hook']        = '';
$CONF['alias_domain_struct_hook']   = '';
$CONF['fetchmail_struct_hook']      = '';
$CONF['aliases'] = '1000';
$CONF['mailboxes'] = '1000';
$CONF['maxquota'] = '1000';
$CONF['domain_quota_default'] = '2048';
$CONF['quota'] = 'YES';
$CONF['domain_quota'] = 'YES';
$CONF['quota_multiplier'] = '1024000';
$CONF['transport'] = 'NO';
$CONF['transport_options'] = array (
);
$CONF['transport_default'] = 'virtual';
$CONF['vacation'] = 'NO';
$CONF['vacation_domain'] = 'autoreply.change-this-to-your.domain.tld';
$CONF['vacation_control'] ='YES';
$CONF['vacation_control_admin'] = 'YES';
$CONF['vacation_choice_of_reply'] = array (
     # considered annoying - only send a reply on every mail if you really need it
);
$CONF['alias_control'] = 'YES';
$CONF['alias_control_admin'] = 'YES';
$CONF['special_alias_control'] = 'NO';
$CONF['alias_goto_limit'] = '0';
$CONF['alias_domain'] = 'YES';
$CONF['backup'] = 'NO';
$CONF['sendmail'] = 'YES';
$CONF['sendmail_all_admins'] = 'NO';
$CONF['logging'] = 'YES';
$CONF['fetchmail'] = 'NO';
$CONF['fetchmail_extra_options'] = 'NO';
$CONF['show_header_text'] = 'NO';
$CONF['header_text'] = ':: Postfix Admin ::';
$CONF['show_footer_text'] = 'YES';
$CONF['footer_text'] = 'Return to change-this-to-your.domain.tld';
$CONF['motd_user'] = '';
$CONF['motd_admin'] = '';
$CONF['motd_superadmin'] = '';
$CONF['welcome_text'] = <<