Mail Server Setup With Exim, MySQL, Cyrus-Imapd, Horde Webmail On Centos 5.1 - Page 2

Want to support HowtoForge? Become a subscriber!
 
Submitted by topdog (Contact Author) (Forums) on Tue, 2008-02-19 18:32. ::

Configuration

Configure Apache

  • Enable virtual hosting and create default virtualhost, edit /etc/httpd/conf/httpd.conf and add at the end
    NameVirtualHost *:80
    <VirtualHost *:80>
        ServerAdmin webmaster@home.topdog-software.com
    </VirtualHost>
    
  • Create the virtual host for horde webmail add this under the above
    <VirtualHost *:80>
            Servername mail.home.topdog-software.com
            DocumentRoot /usr/share/horde
            ErrorLog logs/mail-error_log
            CustomLog logs/mail-access_log common
    </VirtualHost>
    
  • Enable horde security settings edit the file /etc/httpd/conf.d/horde.conf and set as below
    #Alias /horde /usr/share/horde
    <Directory /usr/share/horde>
        Options +FollowSymLinks
        php_admin_flag safe_mode off
        php_admin_flag magic_quotes_runtime off
        php_flag session.use_trans_sid off
        php_flag session.auto_start off
        php_admin_flag file_uploads on
        #php_admin_flag allow_url_fopen on
        php_value post_max_size 20M
        php_value upload_max_filesize 10M
        php_admin_value open_basedir "/usr/share/horde:/usr/share/horde/config:/usr/share/pear:/tmp"
        php_admin_flag register_globals off
    </Directory>
    <Directory /usr/share/horde/config>
        Order Deny,Allow
        Deny from all
    </Directory>
    <DirectoryMatch "^/usr/share/horde/(.*/)?(config|lib|locale|po|scripts|templates)/(.*)?">
        Order Deny,Allow
        Deny from all
    </DirectoryMatch>
    
  • Increase PHP memory limit edit /etc/php.ini and change to below
    memory_limit = 64M
    
  • Enable horde under SSL edit /etc/httpd/conf.d/ssl.conf and add the following to the default virtualhost between the <VirtualHost _default_:443><VirtualHost> tags
    Servername mail.home.topdog-software.com:443
    DocumentRoot /usr/share/horde
    

 

Configure Exim

  • Switch the MTA to exim

system-switch-mail (select exim)

Anti-virus / Sanesecurity Checks

  • Configure Exim (/etc/exim/exim.conf) to use clamav to scan incoming mail and reject virus infected email and image and pdf spam at smtp time
av_scanner = clamd:/var/run/clamav/clamd.sock

RBL's

  • Configure the RBL's under acl_check_rcpt:
    drop    message       = REJECTED because $sender_host_address is in a black list spamhaus.org
               dnslists      = zen.spamhaus.org
    drop    message       = REJECTED because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
               dnslists      = bl.spamcop.net
    drop    message       = REJECTED because $sender_host_address is in a black list at $dnslist_domain\n$dnslist_text
               dnslists      = dnsbl.sorbs.net
    

 

Anti Spam

  • If you want to reject messages from servers with no reverse dns add this under acl_check_rcpt:, it does have a exception list to which you can add domains where the acl should not be applied and trys to deliver a test message to sending address to verify if the sender is valid.
    drop  message   = REJECTED - We don't accept messages from hosts without reverse DNS
            log_message = No reverse DNS
            domains = ! lsearch;/etc/exim/checks_exempt_hosts
            !verify = reverse_host_lookup
            !verify = sender/callout=2m,defer_ok
            !condition =  ${if eq{$sender_verify_failure}{}}
    
  • To reject messages from clients that dont provide a HELO/EHLO add this to acl_check_rcpt:
    drop  message  = REFUSED - no HELO/EHLO greeting
            log_message = remote host did not present greeting
            condition = ${if def:sender_helo_name {false}{true}}
    
  • You can rate limit the connections to your server as well add this to acl_check_connect: to do so (read the exim docs on the parameters if you want to fine tune it for your site)
    deny ratelimit = 250 / 15m / strict
           message = You can only send $sender_rate per $sender_rate_period
           log_message = RATE: $sender_rate/$sender_rate_period (max $sender_rate_limit)
    accept
    
  • Stop rogue spam bots from trashing your machine
    smtp_accept_max_nonmail = 30
    smtp_max_unknown_commands = 1
    
  • Don't advertise pipelining
    pipelining_advertise_hosts = 
    
  • Enable Spamassassin checks
    spamd_address = /var/run/spamassassin/spamd.sock
    
  • Reject all messages with score above 6 at smtp time. (acl_check_data)
    accept  condition  = ${if >={$message_size}{100000} {1}}
            add_header = X-Spam-Note: SpamAssassin run bypassed due to message size
      warn    spam       = nobody/defer_ok
            add_header = X-Spam-Flag: YES
      accept  condition  = ${if !def:spam_score_int {1}}
            add_header = X-Spam-Note: SpamAssassin invocation failed
      warn    add_header = X-Spam-Score: $spam_score ($spam_bar)\n\
    #       X-Spam-Report: $spam_report
      drop    condition = ${if >{$spam_score_int}{60} {1}}
            message   = Your message scored $spam_score SpamAssassin point. Report follows:\n\
            $spam_report
    

 

Mail routing

  • Enable access to Mysql database
    hide mysql_servers = localhost/horde/horde/hordepassword
    
  • Modify the local delivery router to deliver to cyrus but verify the email address of user before delivery (in routers section of exim.conf)
    localuser:
      driver = accept
      local_parts = ${lookup mysql {SELECT REPLACE(user_uid,'${quote_mysql:@$domain}','') \
             as user FROM horde_users WHERE user_uid='${quote_mysql:$local_part@$domain}'}{$value}}
      transport = local_delivery
      cannot_route_message = Unknown user
    
  • Create a transport to deliver to cyrus via lmtp socket
    local_delivery:
      driver = lmtp
      socket = /var/lib/imap/socket/lmtp
      batch_max = 50
      user = cyrus
    

 

SMTP Authentication

  • Add the following to the authentication section of /etc/exim/exim.conf
    plain:
      driver = plaintext
      public_name = PLAIN
      server_prompts = :
      server_set_id = $2
      server_condition = ${if saslauthd{{$2}{$3}{pop}}{1}{0}}
      server_advertise_condition = true
    login:
      driver = plaintext
      public_name = LOGIN
      server_prompts = "Username:: : Password::"
      server_condition = ${if saslauthd{{$1}{$2}{pop}}{1}{0}}
      server_set_id = $1
      server_advertise_condition = true
    

 

Full sample configuration

Download the full configuration file here.

 

Configure Mysql

  • Disable TCP networking edit /etc/my.cnf and the following in the mysqld section
    skip-networking
    
  • Set root password

    /usr/bin/mysqladmin -u root password 'new-password'
    /usr/bin/mysqladmin -u root -h your_host_name password 'new-password' -p

 

Configure Horde

  • Edit the sql file and change the mysql password for the horde user

    cp /usr/share/horde/scripts/sql/create.mysql.sql .
    vi create.mysql.sql

    REPLACE INTO user (host, user, password)
        VALUES (
            'localhost',
            'horde',
    -- IMPORTANT: Change this password!
            PASSWORD('hordepassword')
    );
    
  • Create the user and populate the horde database

    mysql -p < create.mysql.sql

  • Create the tables for turba (Address book)

    mysql -p horde < /usr/share/horde/turba/scripts/sql/turba_objects.mysql.sql

  • Create the tables for kronolith (calendering)

    mysql -p horde < /usr/share/horde/kronolith/scripts/sql/kronolith.mysql.sql

 

Horde Configuration

  • Create horde base configuration /usr/share/horde/config/conf.php
    <?php
    $conf['debug_level'] = E_ALL;
    $conf['max_exec_time'] = 0;
    $conf['compress_pages'] = true;
    $conf['umask'] = 077;
    $conf['use_ssl'] = 2;
    $conf['server']['name'] = $_SERVER['SERVER_NAME'];
    $conf['server']['port'] = $_SERVER['SERVER_PORT'];
    $conf['session']['name'] = 'Horde';
    $conf['session']['use_only_cookies'] = true;
    $conf['session']['cache_limiter'] = 'nocache';
    $conf['session']['timeout'] = 0;
    $conf['cookie']['domain'] = $_SERVER['SERVER_NAME'];
    $conf['cookie']['path'] = '/';
    $conf['sql']['username'] = 'horde';
    $conf['sql']['password'] = 'hordepassword';
    $conf['sql']['socket'] = '/var/lib/mysql/mysql.sock';
    $conf['sql']['protocol'] = 'unix';
    $conf['sql']['database'] = 'horde';
    $conf['sql']['charset'] = 'iso-8859-1';
    $conf['sql']['phptype'] = 'mysqli';
    $conf['auth']['admins'] = array('Administrator', 'andrew@home.topdog-software.com');
    $conf['auth']['checkip'] = true;
    $conf['auth']['checkbrowser'] = true;
    $conf['auth']['alternate_login'] = false;
    $conf['auth']['redirect_on_logout'] = false;
    $conf['auth']['params']['driverconfig'] = 'horde';
    $conf['auth']['params']['table'] = 'horde_users';
    $conf['auth']['params']['username_field'] = 'user_uid';
    $conf['auth']['params']['password_field'] = 'user_pass';
    $conf['auth']['params']['encryption'] = 'md5-hex';
    $conf['auth']['params']['show_encryption'] = false;
    $conf['auth']['driver'] = 'sql';
    $conf['signup']['allow'] = false;
    $conf['log']['priority'] = PEAR_LOG_NOTICE;
    $conf['log']['ident'] = 'HORDE';
    $conf['log']['params'] = array();
    $conf['log']['name'] = '/tmp/horde.log';
    $conf['log']['params']['append'] = true;
    $conf['log']['type'] = 'file';
    $conf['log']['enabled'] = true;
    $conf['log_accesskeys'] = false;
    $conf['prefs']['params']['driverconfig'] = 'horde';
    $conf['prefs']['driver'] = 'sql';
    $conf['datatree']['params']['driverconfig'] = 'horde';
    $conf['datatree']['driver'] = 'sql';
    $conf['group']['driver'] = 'datatree';
    $conf['cache']['default_lifetime'] = 1800;
    $conf['cache']['params']['dir'] = Horde::getTempDir();
    $conf['cache']['params']['gc'] = 86400;
    $conf['cache']['driver'] = 'file';
    $conf['token']['driver'] = 'none';
    $conf['mailer']['params']['auth'] = '0';
    $conf['mailer']['type'] = 'smtp';
    $conf['vfs']['params']['driverconfig'] = 'horde';
    $conf['vfs']['type'] = 'sql';
    $conf['sessionhandler']['params']['persistent'] = false;
    $conf['sessionhandler']['params']['rowlocking'] = true;
    $conf['sessionhandler']['params']['socket'] = '/var/lib/mysql/mysql.sock';
    $conf['sessionhandler']['params']['protocol'] = 'unix';
    $conf['sessionhandler']['params']['hostspec'] = 'localhost';
    $conf['sessionhandler']['params']['username'] = 'horde';
    $conf['sessionhandler']['params']['password'] = 'hordepassword';
    $conf['sessionhandler']['params']['database'] = 'horde';
    $conf['sessionhandler']['type'] = 'mysql';
    $conf['problems']['email'] = 'webmaster@home.topdog-software.com';
    $conf['problems']['maildomain'] = 'home.topdog-software.com';
    $conf['problems']['tickets'] = false;
    $conf['menu']['apps'] = array();
    $conf['menu']['always'] = true;
    $conf['menu']['links']['help'] = 'authenticated';
    $conf['menu']['links']['help_about'] = true;
    $conf['menu']['links']['options'] = 'authenticated';
    $conf['menu']['links']['problem'] = 'never';
    $conf['menu']['links']['login'] = 'all';
    $conf['menu']['links']['logout'] = 'authenticated';
    $conf['hooks']['permsdenied'] = false;
    $conf['hooks']['username'] = false;
    $conf['hooks']['preauthenticate'] = false;
    $conf['hooks']['postauthenticate'] = false;
    $conf['hooks']['authldap'] = false;
    $conf['portal']['fixed_blocks'] = array();
    $conf['accounts']['driver'] = 'null';
    $conf['imsp']['enabled'] = false;
    $conf['kolab']['enabled'] = false;
    
  • Set horde preferences to make web mail the default application on logging in. Edit the file /usr/share/horde/config/prefs.php and modify $_prefs['initial_application'] to look as below
    $_prefs['initial_application'] = array(
        'value' => 'imp',
        'locked' => true,
        'shared' => true,
        'type' => 'select',
        'desc' => sprintf(_("What application should %s display after login?"), $GLOBALS['registry']->get('name'))
    );
    
  • Make horde work from within the default root of the web servers, edit /usr/share/horde/config/registry.php and modify $this→applications['horde'] as below
    $this->applications['horde'] = array(
        'fileroot' => dirname(__FILE__) . '/..',
        'webroot' => '',
        'initial_page' => 'login.php',
        'name' => _("Horde"),
        'status' => 'active',
        'templates' => dirname(__FILE__) . '/../templates',
        'provides' => 'horde'
    );
    

Please do not use the comment function to ask for help! If you need help, please use our forum.
Comments will be published after administrator approval.
Submitted by ask2me007 (registered user) on Fri, 2009-09-18 08:04.

The full configuration file of Exim listed in your how to is  in .gz format and is not readable after unzipping.Pls recheck  whether the file is in correct format.Other wise how can i open in a readable format??

Thank you

Submitted by Parabellum (registered user) on Thu, 2008-08-28 15:30.

I believe the correct blacklist for spamhaus.org is:

zen.spamhaus.org

not xen.  xen is the virtual host hypervisor thingy.  If you use the incorrect host name for that DNSBL, spamhaus will give you an answer for every query.  That means you will reject every single IP address.

Other than that, excellent article!

Submitted by topdog (registered user) on Fri, 2008-08-29 10:31.
Well sported, it has been fixed.