====== Mail Server Setup ====== This is how I set up my mail server on * Ubuntu Ubuntu 14.04.5 LTS * Dovecot 2.2.9 (dovecot --version) * Postfix 2.11.0 (postconf mail_version) * Postfix Admin 2.3.5 * Squirrel Mail 1.4.22 * MySQL Ver 14.14 Distrib 5.5.57 (mysql --version) * PHP 5.5.9 (php --version) * pflogsumm.pl - Produce Postfix MTA logfile summary * Fail2Ban v0.8.11 (/usr/bin/fail2ban-server --version) * [[doveadm_scripting|Automatic email processing using Doveadm]] ===== Supporting Packages to Install ===== * postfix-mysql * dovecot-core * dovecot-postfix (not valid anymore in 2022) * dovecot-mysql * dovecot-imapd * php5-mysql ===== Server configuration ===== ==== vmail user configuration ==== groupadd -g 5000 vmail useradd -d /home/vmail -g 5000 -m -s /bin/bash -u 5000 -p somepassword vmail id vmail uid=5000(vmail) gid=5000(vmail) groups=5000(vmail) ===== Postfix configuration ===== /etc/postfix/main.cf # See /usr/share/postfix/main.cf.dist for a commented, more complete version # Debian specific: Specifying a file name will cause the first # line of that file to be used as the name. The Debian default # is /etc/mailname. myorigin = /etc/mailname smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) biff = no # appending .domain is the MUAs job. append_dot_mydomain = no # Uncomment the next line to generate "delayed mail" warnings delay_warning_time = 4h readme_directory = no # TLS parameters smtpd_tls_cert_file = /etc/ssl/certs/ssl-mail.pem smtpd_tls_key_file = /etc/ssl/private/ssl-mail.key smtpd_tls_loglevel = 1 smtpd_tls_security_level = may smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache tls_random_source = dev:/dev/urandom tls_random_bytes = 32 tls_random_reseed_period = 3600s # home_mailbox = Maildir/ smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/dovecot-auth smtpd_sasl_authenticated_header = yes smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = $myhostname broken_sasl_auth_clients = yes smtpd_use_tls = yes smtpd_tls_received_header = yes smtpd_tls_mandatory_protocols = SSLv3, TLSv1 smtpd_tls_mandatory_ciphers = medium #smtpd_tls_auth_only = yes # smtp_tls_cert_file=/etc/postfix/ssl/smtpd.pem smtp_tls_key_file=$smtp_tls_cert_file smtp_tls_loglevel = 1 smtp_tls_security_level = may smtp_tls_note_starttls_offer = yes smtp_use_tls = yes # # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for # information on enabling SSL in the smtp client. myhostname = example.org alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases myorigin = /etc/mailname #mydestination = example.org, www.example.org, example.cc, www.example.cc, myserverhostname, localhost.localdomain, localhost mydestination = relayhost = smtp-server.example.com # This was commented out as it gives a "unused parameter" warning on Precise - works on Hardy #relay_domain = $mydestination mynetworks_style = subnet #mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_command = /usr/lib/dovecot/deliver -c /etc/dovecot/conf.d/01-mail-stack-delivery.conf -m "${EXTENSION}" mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = all owner_request_special = no message_size_limit = 32768000 # # Virtual Mailbox Domain Settings virtual_alias_maps = mysql:/etc/postfix/mysql/alias_maps.cf, mysql:/etc/postfix/mysql/alias_alias_maps.cf virtual_mailbox_domains = mysql:/etc/postfix/mysql/domains_maps.cf virtual_mailbox_maps = mysql:/etc/postfix/mysql/mailbox_maps.cf, mysql:/etc/postfix/mysql/mailbox_alias_maps.cf virtual_mailbox_limit = 51200000 virtual_minimum_uid = 5000 virtual_uid_maps = static:5000 virtual_gid_maps = static:5000 virtual_mailbox_base = /home/vmail virtual_transport = virtual # Additional for quota support # This was commented out as it gives a "unused parameter" warning on Precise - works on Hardy #virtual_create_maildirsize = yes #virtual_mailbox_extended = yes #virtual_mailbox_limit_maps = mysql:/etc/postfix/mysql/mailbox_limit_maps.cf #virtual_mailbox_limit_override = yes #virtual_maildir_limit_message = Sorry, the your maildir has overdrawn your diskspace quota, please free up some of spaces of your mailbox try again. #virtual_overquota_bounce = yes # # Spam reduction parameters. May be aggresive for some, but seems to work well. access_map_reject_code = 554 invalid_hostname_reject_code = 554 maps_rbl_reject_code = 554 multi_recipient_bounce_reject_code = 554 non_fqdn_reject_code = 554 plaintext_reject_code = 554 reject_code = 554 relay_domains_reject_code = 554 unknown_local_recipient_reject_code = 550 unknown_address_reject_code = 550 unknown_client_reject_code = 550 unknown_hostname_reject_code = 550 unknown_relay_recipient_reject_code = 550 unknown_virtual_alias_reject_code = 550 unknown_virtual_mailbox_reject_code = 550 unverified_recipient_reject_code = 550 unverified_sender_reject_code = 550 # default_process_limit = 20 smtpd_client_connection_count_limit = 10 # Value of 60 should translate to 1 per second limit smtpd_client_connection_rate_limit = 60 smtpd_client_message_rate_limit = 60 smtpd_client_new_tls_session_rate_limit = 60 # smtpd_helo_required = yes smtpd_delay_reject = yes address_verify_map = btree:${data_directory}/verify_cache smtpd_reject_unlisted_sender=yes # smtpd_recipient_restrictions = check_client_access hash:/etc/postfix/white_lists, permit_sasl_authenticated, permit_mynetworks, # permit_tls_clientcerts, reject_invalid_hostname, reject_non_fqdn_hostname, reject_non_fqdn_sender, reject_non_fqdn_recipient, reject_unknown_sender_domain, reject_unknown_recipient_domain, reject_unverified_sender, reject_unauth_destination, reject_rbl_client zen.spamhaus.org, reject_rbl_client cbl.abuseat.org, check_client_access hash:/etc/postfix/white_lists, permit smtpd_data_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_pipelining, permit # Added for trying to send email from PDA smtpd_client_restrictions = permit_sasl_authenticated smtpd_helo_restrictions = check_helo_access hash:/etc/postfix/check_helo_access, permit_mynetworks, permit_sasl_authenticated, reject_non_fqdn_hostname, reject_invalid_hostname, permit # /etc/postfix/mailname example.org ==== Client TLS Support ==== Follow this for [[postfix_client_tls|Postfix Client TLS Support]] setup ===== Postfix MySql (maps) configuration ===== * Create directory /etc/postfix/mysql * Please the following files under /etc/postfix/mysql user= password= dbname= table=mailbox select_field=username where_field=username hosts=127.0.0.1: user= password= dbname= table=mailbox select_field=username where_field=username hosts=127.0.0.1: user= password= dbname= table=mailbox select_field=maildir where_field=username hosts=127.0.0.1: additional_conditions = and active = 1 user= password= dbname= table=mailbox select_field=quota where_field=username hosts=127.0.0.1: additional_conditions = and active = 1 user= password= dbname= table=alias select_field=goto where_field=address hosts=127.0.0.1: additional_conditions = and active = 1 user= password= dbname= table=domain select_field=domain where_field=domain hosts=127.0.0.1: additional_conditions = and backupmx = 0 and active = 1 and transport = 'virtual' and domain = '%s' user= password= dbname= table=domain select_field=domain where_field=domain hosts=127.0.0.1: additional_conditions = and active = 1 and backupmx = 0 and transport = 'relay' and domain = '%s' The below two settings (alias_alias_maps.cf & mailbox_alias_maps.cf) are for alias domains: user= password= dbname= hosts=127.0.0.1: query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' AND alias.address=concat('%u', '@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active = 1 user= password= dbname= hosts=127.0.0.1: query = SELECT maildir FROM mailbox, alias_domain WHERE alias_domain.alias_domain = '%d' AND mailbox.username=concat('%u', '@', alias_domain.target_domain ) AND mailbox.active = 1 AND alias_domain.active = 1 ===== Dovecot Configuration ===== Change the following files at /etc/dovecot & /etc/dovecot/conf.d The files in /etc/dovecot need NO changes from default * dovecot.conf * dovecot-db.conf.ext * dovecot-dict-sql.conf.ext * dovecot-sql.conf.ext File(s) requiring change driver = mysql connect = host=127.0.0.1 port=3306 user=root password=rootpassword dbname=postfixadmindbname default_pass_scheme = CRAM-MD5 user_query = \ SELECT \ concat('/home/vmail/', maildir) as home, \ 5000 as uid, 5000 as gid \ FROM mailbox \ WHERE username = '%u' AND active = '1' password_query = \ SELECT username as user, password, \ concat('/home/vmail/', maildir) as userdb_home, \ concat('maildir:/home/vmail/', maildir) as userdb_mail, \ 5000 as userdb_uid, 5000 as userdb_gid \ FROM mailbox \ WHERE username = '%u' AND active = '1' The following files in /etc/dovecot/conf.d do NOT require change as well * 01-mail-stack-delivery.conf * 10-director.conf * 10-master.conf * 10-ssl.conf * 15-lda.conf * 20-imap.conf * 20-managesieve.conf * 20-pop3.conf * 90-acl.conf * 90-plugin.conf * 90-quota.conf * 90-sieve.conf * auth-deny.conf.ext * auth-master.conf.ext * auth-passwdfile.conf.ext * auth-static.conf.ext * auth-vpopmail.conf.ext File(s) requiring change auth_verbose = yes auth_debug = yes plugin { # Events to log. Also available: flag_change append #mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename # Available fields: uid, box, msgid, from, subject, size, vsize, flags # size and vsize are available only for expunge and copy events. #mail_log_fields = uid box msgid size } auth_mechanisms = plain cram-md5 !include auth-system.conf.ext passdb { driver = sql args = /etc/dovecot/dovecot-sql.conf.ext # [session=yes] [setcred=yes] [failure_show_msg=yes] [max_requests=] # [cache_key=] [] #args = dovecot } userdb { # driver = sql args = /etc/dovecot/dovecot-sql.conf.ext # [blocking=no] #args = } mail_location = maildir:/home/vmail/%d/%u mail_uid = vmail mail_gid = vmail maildir_copy_with_hardlinks = yes ===== Postfix Admin ===== All changes from the default go in config.local.php $CONF['postfix_admin_url'] = 'http://pfa.example.org'; $CONF['domain_path'] = 'YES'; $CONF['database_type'] = 'mysql'; $CONF['database_host'] = 'localhost'; $CONF['database_user'] = 'upostfixadmin'; $CONF['database_password'] = 'somepassword'; $CONF['database_name'] = 'postfixadmin'; $CONF['admin_email'] = 'postmaster@example.com'; $CONF['smtp_server'] = 'smtp-server.example.com'; $CONF['encrypt'] = 'dovecot:CRAM-MD5'; $CONF['dovecotpw'] = "/usr/bin/doveadm pw"; $CONF['page_size'] = '100'; $CONF['default_aliases'] = array ( 'abuse' => 'abuse@example.com', 'hostmaster' => 'hostmaster@example.com', 'postmaster' => 'postmaster@example.com', 'webmaster' => 'webmaster@example.com' ); $CONF['aliases'] = '10000'; $CONF['mailboxes'] = '10000'; $CONF['maxquota'] = '10000'; $CONF['transport'] = 'YES'; $CONF['vacation_domain'] = 'autoreply.example.com'; $CONF['user_footer_link'] = "http://example.com/"; $CONF['footer_text'] = 'Return to example.com'; $CONF['footer_link'] = 'http://example.com'; $CONF['create_mailbox_subdirs_prefix']=''; $CONF['new_quota_table'] = 'YES'; ===== Migration from Courier to Postfix ===== If you are moving to a new machine make sure that you tar and untar files to preserver permissions and most importantly timestamps. Or all your old mail will have the same date/time! ==== Resource ==== [[http://wiki.dovecot.org/Migration/Courier|Migration-Courier - Dovecot Wiki]] ==== Command ==== /home/vmail/courier-dovecot-migrate.pl --to-dovecot --recursive --convert --overwrite /home/vmail/example.org/ Sample output: Converting to Dovecot format Finding maildirs under /home/vmail/example.org/ Total: 70 mailboxes / 38 users 0 errors 46 dovecot-uidlist files written WARNING: Badly done migration will cause your IMAP and/or POP3 clients to re-download all mails. Read http://wiki.dovecot.org/Migration carefully. ==== Folder between courier and dovecot ==== One way to get the courier subfolders to show up in dovecot is to add this to the configuration: namespace private { prefix = INBOX. separator = . inbox = yes } Alternatively, I created the subfolders (from squirrel mail) and then delete the newly created folders from the Linux file folders and renamed the existing file folders to the name I just deleted. So here goes for example: mv .INBOX.SomeSubFolder/ junk mv .SomeSubFolder .INBOX.SomeSubFolder Here I moved the newly created folder to a "junk" location (an alternative to just deleting it). Then renamed the original folder to the new folder name. ===== Squirrel Mail configuration ===== Follow this [[tech:linux:sq_config|link]]. ===== Some dovecot commands ===== dovecot --build-options find /usr/lib/dovecot/modules/ doveconf -a ===== pflogsumm.pl - Produce Postfix MTA logfile summary ===== The pflogsumm.pl produces a daily summary of mail activity. Install ''pflogsumm'' at ''/usr/local/bin/pflogsumm''. Install the below script as a Daily cron. Make sure the /etc/cron.daily has the shell script above the daily ''log-rotate'' script and the Daily cron runs at midnight. To change the timing of the daily cron run, update the run time at ''/etc/crontab''. Daily cron job shell wrapper #!/bin/bash # # Daily Postfix Log report # TS=$(date +%Y%m%d_%H%M%S); LOGFILEDIR="/var/log/postfixrep" LOGFILE="$LOGFILEDIR/pfrep_$TS.txt" PFLOGSUMM="/usr/local/bin/pflogsumm" PFMAILINF="/var/log/mail.info" PFMAILINF="/var/log/mail.log" REMAIL="report@example.org" REPSUB="Postfix Report" # #$PFLOGSUMM $PFMAILINF > $LOGFILE $PFLOGSUMM --detail 10 --problems_first --verbose_msg_detail $PFMAILINF > $LOGFILE cat $LOGFILE | mailx -s "$REPSUB" $REMAIL # # Delete log files older than 40 days /usr/bin/find $LOGFILEDIR/pfrep* -mtime +40 -exec rm {} \; # exit 0 ===== Fail2ban configuration ===== Fail2ban is optional but highly recommended to reduce thrashing of the servers from brute-force attempts * Install fail2ban (and iptables) using apt-get (I use aptitude!) * Changes to ''/etc/fail2ban/jail.conf'' * Enable postfix, sasl, dovecot by setting ''enabled = true'' * Optionally also enable ''recidive'' * Enable dovecot for IMAP login attemps * Add local LAN to ''ignoreip'' (e.g. ignoreip = 127.0.0.1/8 192.168.0.0/16) * Believe you may also want to include your WAN IP as I sometimes see it in the logs * Optionally increase bantime from 60 to 3600 * Optionally increase findtime from 60 to 3600 * Optionally decrease maxretry from 3 to 2 * Set destemail to a valid email * Update Files in /etc/fail2ban/filter.d as below Notice the ''journalmatch = _SYSTEMD_UNIT=postfix@-.service'' line. The default ''journalmatch = _SYSTEMD_UNIT=postfix.service'' does not work. Not sure if this is an issue with Debian/Bookworm or fail2ban configuration. ==== SMTP Configuration ==== # Fail2Ban filter for selected Postfix SMTP rejections # # [INCLUDES] # Read common prefixes. If any customizations available -- read them from # common.local before = common.conf [Definition] _daemon = postfix/smtpd failregex = ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[\]: 554 5\.7\.1 .*$ ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[\]: 554 5\.5\.2 .*$ ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[\]: 450 4\.7\.1 : Helo command rejected: Host not found; from=<> to=<> proto=ESMTP helo= *$ ^%(__prefix_line)s\S+\: reject: RCPT from \S+\[\]: 550 5\.1\.1 <\S*>: Recipient address rejected:.*$ ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[\]: 454 4\.7\.1 <\S*>: Relay access denied;.*$ ^%(__prefix_line)swarning: \S+\[\]: SASL LOGIN authentication failed: Invalid authentication mechanism$ ^%(__prefix_line)swarning: Recipient address rate limit exceeded: \S+\ from unknown\[\] for service smtp$ ignoreregex = [Init] journalmatch = _SYSTEMD_UNIT=postfix@-.service # Fail2Ban filter for postfix authentication failures # [INCLUDES] before = common.conf [Definition] _daemon = postfix/smtpd failregex = ^%(__prefix_line)swarning: [-._\w]+\[\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?\s*$ ignoreregex = [Init] journalmatch = _SYSTEMD_UNIT=postfix@-.service ''dovecot.conf'' did not require any changes from the default install ==== Dovecot/IMAP Configuration ==== Below are the list of failures that need to be checked Jul 9 07:19:39 inthostname dovecot: imap-login: Disconnected: Too many invalid commands (no auth attempts in 0 secs): user=<>, rip=, lip=internalip, session= Jul 9 00:23:02 inthostname dovecot: imap-login: Aborted login (no auth attempts in 4 secs): user=<>, rip=, lip=internalip, TLS, session= Jul 9 07:57:35 inthostname dovecot: imap-login: Disconnected (no auth attempts in 0 secs): user=<>, rip=, lip=internalip, TLS: Disconnected, session= Jul 9 11:15:15 inthostname dovecot: imap-login: Disconnected (auth failed, 1 attempts in 2 secs): user=, method=PLAIN, rip=, lip=internalip, TLS, session= Jul 9 14:37:38 inthostname dovecot: imap-login: Disconnected (tried to use disallowed plaintext auth): user=<>, rip=, lip=internalip, session= Oct 6 23:17:35 inthostname dovecot: imap-login: Disconnected (disconnected before auth was ready, waited 0 secs): user=<>, rip=, lip=internalip, TLS handshaking: SSL_accept() failed: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol, session= Oct 5 04:33:07 inthostname dovecot: imap-login: Disconnected (tried to use unsupported auth mechanism): user=<>, method=NTLM, rip=, lip=internalip, session= Sep 25 04:55:41 inthostname dovecot: imap-login: Disconnected (client didn't finish SASL auth, waited 19 secs): user=<>, method=PLAIN, rip=, lip=internalip, TLS: SSL_read() syscall failed: Connection reset by peer, session=<9yvt9CsGOQAYNzGR> hackerip=x.x.x.x internalip=y.y.y.y ==== Testing Fail2ban configuration ==== fail2ban-regex systemd-journal /etc/fail2ban/filter.d/postfix.conf fail2ban-regex systemd-journal /etc/fail2ban/filter.d/postfix-sasl.conf ==== Other Fail2ban related configuration ==== rsyslog filters duplicate messages as ''last message repeated X times''. This causes Fail2ban to not get the actual count of failed attempts. To change the configuration: Edit ''/etc/rsyslog.conf'' to update ''$RepeatedMsgReduction'' from on to off $RepeatedMsgReduction off Restart rsyslog service rsyslog restart ==== Other Fail2ban related commands ==== == Currently banned IPs == Run as root: fail2ban-client status | grep "Jail list:" | sed "s/ //g" | awk '{split($2,a,",");for(i in a) system("fail2ban-client status " a[i])}' === Permanently ban == Refer [[senthil:tech:linux:fail2ban_maintain|here]] to permanently ban! ==== Other Fail2ban resources ==== https://www.the-art-of-web.com/system/fail2ban-howto/ ===== Post Configuration Steps ===== ==== white_lists file ==== To avoid error that there is no white list file. The ''check_helo_access'' allows helo specific white lists. For e.g. use when you an error such as ''Helo command rejected: Host not found;''. cd /etc/postfix touch white_lists postmap white_lists # touch check_helo_access postmap check_helo_access ==== Restart ==== service postfix restart service dovecot restart ===== Dovecot debug ===== To turn on auth debug in dovecot. Update ''dovecot/conf.d/10-logging.conf'' file with auth_verbose = no auth_debug = no Remember to turn if off once done. ===== /etc/aliases ===== Optionally update aliases so mail delivered to root (or someuser) at localhost can be forwarded to a remote mail user. # See man 5 aliases for format postmaster: root someuser:someuser@example.org root:someuser@example.org Run the below after changing ''/etc/aliases'' postalias /etc/aliases # Alternative to postalias you can also run 'newaliases' command service postfix restart ===== Logs ===== Update ''logrotate'' configuration at ''/etc/logrotate.d/rsyslog'' to increase the retention period. Typically mail logs have a 4 week retention period (parameter ''rotate''). Increase it to 13 weeks or more as desired. ===== Satellite hosts ===== The above setup is for Postfix smart host. For the rest of the servers in the network, it is preferred to set them up as a Satellite host and route mail through the local host. The Postfix main.cf configuration for Postfix Satellite host aka Send-only, Relay, Forwarded host is below. Note: * Replace ''your-host-name'' with your hostname * ''example.org'' with the smart-host domain name * ''mainsmtp'' with the hostname/IP of the smart-host /etc/postfix/main.cf # See /usr/share/postfix/main.cf.dist for a commented, more complete version # Debian specific: Specifying a file name will cause the first # line of that file to be used as the name. The Debian default # is /etc/mailname. myorigin = /etc/mailname smtpd_banner = $myhostname ESMTP $mail_name (Ubuntu) biff = no # appending .domain is the MUA's job. append_dot_mydomain = no # Uncomment the next line to generate "delayed mail" warnings #delay_warning_time = 4h readme_directory = no # TLS parameters smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key smtpd_use_tls=yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache # See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for # information on enabling SSL in the smtp client. smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination myhostname = your-host-name alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mydomain = example.org mydestination = $myhostname.$mydomain, localdomain, $myhostname, localhost.localdomain, localhost relayhost = mainsmtp smtp_host_lookup = native mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mailbox_size_limit = 0 recipient_delimiter = + inet_interfaces = loopback-only # Address rewriting #smtp_generic_maps = hash:/etc/postfix/generic /etc/postfix/mailname your-host-name.example.org /etc/aliases # See man 5 aliases for format postmaster: root user:system@example.org root:system@example.org ===== Related ===== * [[squirrelmail|Additional SquirrelMail Notes]] * [[setup_postfix_relay|Setup Postfix to act as Relay Host]] * [[postfix_client_tls|Postfix Client TLS Support]] * [[postfix_important_settings|Important Postfix settings]] * [[postfix_relay_on_recipient_domain|Postfix - Choose a different SMTP relay based on sender domain]]