Differences
This shows you the differences between two versions of the page.
tech:linux:mail_server_setup [2020/02/11 06:26] |
tech:linux:mail_server_setup [2023/10/19 06:33] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ====== 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 ==== | ||
+ | <code bash> | ||
+ | groupadd -g 5000 vmail | ||
+ | useradd -d /home/vmail -g 5000 -m -s /bin/bash -u 5000 -p somepassword vmail | ||
+ | id vmail | ||
+ | </code> | ||
+ | uid=5000(vmail) gid=5000(vmail) groups=5000(vmail) | ||
+ | |||
+ | ===== Postfix configuration ===== | ||
+ | /etc/postfix/main.cf | ||
+ | |||
+ | <file ini 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 | ||
+ | # | ||
+ | </file> | ||
+ | |||
+ | |||
+ | /etc/postfix/mailname | ||
+ | <file ini mailname> | ||
+ | example.org | ||
+ | </file> | ||
+ | |||
+ | ==== 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 | ||
+ | |||
+ | <file ini mysql_uid.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | table=mailbox | ||
+ | select_field=username | ||
+ | where_field=username | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | </file> | ||
+ | |||
+ | <file ini mysql_gid.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | table=mailbox | ||
+ | select_field=username | ||
+ | where_field=username | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | </file> | ||
+ | |||
+ | <file ini mailbox_maps.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | table=mailbox | ||
+ | select_field=maildir | ||
+ | where_field=username | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | additional_conditions = and active = 1 | ||
+ | </file> | ||
+ | |||
+ | <file ini mailbox_limit_maps.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | table=mailbox | ||
+ | select_field=quota | ||
+ | where_field=username | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | additional_conditions = and active = 1 | ||
+ | </file> | ||
+ | |||
+ | <file ini alias_maps.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | table=alias | ||
+ | select_field=goto | ||
+ | where_field=address | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | additional_conditions = and active = 1 | ||
+ | </file> | ||
+ | |||
+ | <file ini domains_maps.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | table=domain | ||
+ | select_field=domain | ||
+ | where_field=domain | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | additional_conditions = and backupmx = 0 and active = 1 and transport = 'virtual' and domain = '%s' | ||
+ | </file> | ||
+ | |||
+ | <file ini relay_domains.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | table=domain | ||
+ | select_field=domain | ||
+ | where_field=domain | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | additional_conditions = and active = 1 and backupmx = 0 and transport = 'relay' and domain = '%s' | ||
+ | </file> | ||
+ | |||
+ | The below two settings (alias_alias_maps.cf & mailbox_alias_maps.cf) are for alias domains: | ||
+ | <file ini alias_alias_maps.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | 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 | ||
+ | </file> | ||
+ | |||
+ | <file ini mailbox_alias_maps.cf> | ||
+ | user=<mysql_db_user> | ||
+ | password=<mysql_db_password> | ||
+ | dbname=<mysql_db_name> | ||
+ | hosts=127.0.0.1:<mysql_db_port> | ||
+ | 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 | ||
+ | </file> | ||
+ | ===== 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 | ||
+ | |||
+ | <file ini dovecot-sql.conf.ext> | ||
+ | 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' | ||
+ | </file> | ||
+ | |||
+ | |||
+ | 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 | ||
+ | |||
+ | <file ini 10-logging.conf> | ||
+ | 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 | ||
+ | } | ||
+ | |||
+ | </file> | ||
+ | |||
+ | <file ini 10-auth.conf> | ||
+ | auth_mechanisms = plain cram-md5 | ||
+ | !include auth-system.conf.ext | ||
+ | </file> | ||
+ | |||
+ | <file ini auth-system.conf.ext> | ||
+ | passdb { | ||
+ | driver = sql | ||
+ | args = /etc/dovecot/dovecot-sql.conf.ext | ||
+ | # [session=yes] [setcred=yes] [failure_show_msg=yes] [max_requests=<n>] | ||
+ | # [cache_key=<key>] [<service name>] | ||
+ | #args = dovecot | ||
+ | } | ||
+ | userdb { | ||
+ | # <doc/wiki/AuthDatabase.Passwd.txt> | ||
+ | driver = sql | ||
+ | args = /etc/dovecot/dovecot-sql.conf.ext | ||
+ | # [blocking=no] | ||
+ | #args = | ||
+ | } | ||
+ | </file> | ||
+ | |||
+ | <file ini 10-mail.conf> | ||
+ | mail_location = maildir:/home/vmail/%d/%u | ||
+ | mail_uid = vmail | ||
+ | mail_gid = vmail | ||
+ | maildir_copy_with_hardlinks = yes | ||
+ | </file> | ||
+ | |||
+ | ===== Postfix Admin ===== | ||
+ | All changes from the default go in config.local.php | ||
+ | <file ini 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'; | ||
+ | </file> | ||
+ | |||
+ | ===== 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 ==== | ||
+ | <code> | ||
+ | /home/vmail/courier-dovecot-migrate.pl --to-dovecot --recursive --convert --overwrite /home/vmail/example.org/ | ||
+ | </code> | ||
+ | Sample output: | ||
+ | <code> | ||
+ | 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. | ||
+ | </code> | ||
+ | ==== Folder between courier and dovecot ==== | ||
+ | One way to get the courier subfolders to show up in dovecot is to add this to the configuration: | ||
+ | <file ini 10-mail.conf> | ||
+ | namespace private { | ||
+ | prefix = INBOX. | ||
+ | separator = . | ||
+ | inbox = yes | ||
+ | } | ||
+ | </file> | ||
+ | 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: | ||
+ | <code> | ||
+ | mv .INBOX.SomeSubFolder/ junk | ||
+ | mv .SomeSubFolder .INBOX.SomeSubFolder | ||
+ | </code> | ||
+ | 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 ===== | ||
+ | <code> | ||
+ | dovecot --build-options | ||
+ | find /usr/lib/dovecot/modules/ | ||
+ | doveconf -a | ||
+ | </code> | ||
+ | |||
+ | ===== 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 | ||
+ | <code bash> | ||
+ | #!/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 | ||
+ | </code> | ||
+ | |||
+ | |||
+ | ===== 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 ==== | ||
+ | |||
+ | <file ini postfix.conf> | ||
+ | # 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+\[<HOST>\]: 554 5\.7\.1 .*$ | ||
+ | ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 554 5\.5\.2 .*$ | ||
+ | ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 450 4\.7\.1 : Helo command rejected: Host not found; from=<> to=<> proto=ESMTP helo= *$ | ||
+ | ^%(__prefix_line)s\S+\: reject: RCPT from \S+\[<HOST>\]: 550 5\.1\.1 <\S*>: Recipient address rejected:.*$ | ||
+ | ^%(__prefix_line)sNOQUEUE: reject: RCPT from \S+\[<HOST>\]: 454 4\.7\.1 <\S*>: Relay access denied;.*$ | ||
+ | ^%(__prefix_line)swarning: \S+\[<HOST>\]: SASL LOGIN authentication failed: Invalid authentication mechanism$ | ||
+ | ^%(__prefix_line)swarning: Recipient address rate limit exceeded: \S+\ from unknown\[<HOST>\] for service smtp$ | ||
+ | |||
+ | ignoreregex = | ||
+ | |||
+ | [Init] | ||
+ | |||
+ | journalmatch = _SYSTEMD_UNIT=postfix@-.service | ||
+ | |||
+ | </file> | ||
+ | |||
+ | |||
+ | <file ini postfix-sasl.conf> | ||
+ | # Fail2Ban filter for postfix authentication failures | ||
+ | # | ||
+ | |||
+ | [INCLUDES] | ||
+ | |||
+ | before = common.conf | ||
+ | |||
+ | [Definition] | ||
+ | |||
+ | _daemon = postfix/smtpd | ||
+ | |||
+ | failregex = ^%(__prefix_line)swarning: [-._\w]+\[<HOST>\]: SASL (?:LOGIN|PLAIN|(?:CRAM|DIGEST)-MD5) authentication failed(: [ A-Za-z0-9+/]*={0,2})?\s*$ | ||
+ | |||
+ | ignoreregex = | ||
+ | |||
+ | [Init] | ||
+ | |||
+ | journalmatch = _SYSTEMD_UNIT=postfix@-.service | ||
+ | |||
+ | </file> | ||
+ | |||
+ | ''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 | ||
+ | <code> | ||
+ | Jul 9 07:19:39 inthostname dovecot: imap-login: Disconnected: Too many invalid commands (no auth attempts in 0 secs): user=<>, rip=<hackerip>, lip=internalip, session=<MGpJ4QwAJgCn+IV+> | ||
+ | Jul 9 00:23:02 inthostname dovecot: imap-login: Aborted login (no auth attempts in 4 secs): user=<>, rip=<hackerip>, lip=internalip, TLS, session=<g2xYDwcAcwBX7LCo> | ||
+ | Jul 9 07:57:35 inthostname dovecot: imap-login: Disconnected (no auth attempts in 0 secs): user=<>, rip=<hackerip>, lip=internalip, TLS: Disconnected, session=<wqHyaA0AHgCrQ0bl> | ||
+ | Jul 9 11:15:15 inthostname dovecot: imap-login: Disconnected (auth failed, 1 attempts in 2 secs): user=<someone@example.org>, method=PLAIN, rip=<hackerip>, lip=internalip, TLS, session=<mN+5KxAACACr92MJ> | ||
+ | Jul 9 14:37:38 inthostname dovecot: imap-login: Disconnected (tried to use disallowed plaintext auth): user=<>, rip=<hackerip>, lip=internalip, session=<HXSc/xIAuAAl7S4R> | ||
+ | Oct 6 23:17:35 inthostname dovecot: imap-login: Disconnected (disconnected before auth was ready, waited 0 secs): user=<>, rip=<hackerip>, lip=internalip, TLS handshaking: SSL_accept() failed: error:140760FC:SSL routines:SSL23_GET_CLIENT_HELLO:unknown protocol, session=<HTcFoxgHmgBrquET> | ||
+ | Oct 5 04:33:07 inthostname dovecot: imap-login: Disconnected (tried to use unsupported auth mechanism): user=<>, method=NTLM, rip=<hackerip>, lip=internalip, session=<MK/Dz/QGMAClmnge> | ||
+ | Sep 25 04:55:41 inthostname dovecot: imap-login: Disconnected (client didn't finish SASL auth, waited 19 secs): user=<>, method=PLAIN, rip=<wanip>, lip=internalip, TLS: SSL_read() syscall failed: Connection reset by peer, session=<9yvt9CsGOQAYNzGR> | ||
+ | |||
+ | |||
+ | hackerip=x.x.x.x | ||
+ | internalip=y.y.y.y | ||
+ | </code> | ||
+ | |||
+ | ==== Testing Fail2ban configuration ==== | ||
+ | <code bash> | ||
+ | fail2ban-regex systemd-journal /etc/fail2ban/filter.d/postfix.conf | ||
+ | fail2ban-regex systemd-journal /etc/fail2ban/filter.d/postfix-sasl.conf | ||
+ | </code> | ||
+ | |||
+ | ==== 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 | ||
+ | <code> | ||
+ | $RepeatedMsgReduction off | ||
+ | </code> | ||
+ | |||
+ | Restart rsyslog | ||
+ | <code bash> | ||
+ | service rsyslog restart | ||
+ | </code> | ||
+ | |||
+ | ==== Other Fail2ban related commands ==== | ||
+ | == Currently banned IPs == | ||
+ | Run as root: | ||
+ | <code bash> | ||
+ | fail2ban-client status | grep "Jail list:" | sed "s/ //g" | awk '{split($2,a,",");for(i in a) system("fail2ban-client status " a[i])}' | ||
+ | </code> | ||
+ | |||
+ | === 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;''. | ||
+ | <code bash> | ||
+ | cd /etc/postfix | ||
+ | touch white_lists | ||
+ | postmap white_lists | ||
+ | # | ||
+ | touch check_helo_access | ||
+ | postmap check_helo_access | ||
+ | </code> | ||
+ | |||
+ | ==== Restart ==== | ||
+ | <code> | ||
+ | service postfix restart | ||
+ | service dovecot restart | ||
+ | </code> | ||
+ | |||
+ | ===== Dovecot debug ===== | ||
+ | To turn on auth debug in dovecot. Update ''dovecot/conf.d/10-logging.conf'' file with | ||
+ | <code> | ||
+ | auth_verbose = no | ||
+ | auth_debug = no | ||
+ | </code> | ||
+ | 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. | ||
+ | <code> | ||
+ | # See man 5 aliases for format | ||
+ | postmaster: root | ||
+ | someuser:someuser@example.org | ||
+ | root:someuser@example.org | ||
+ | </code> | ||
+ | Run the below after changing ''/etc/aliases'' | ||
+ | <code bash> | ||
+ | postalias /etc/aliases | ||
+ | # Alternative to postalias you can also run 'newaliases' command | ||
+ | service postfix restart | ||
+ | </code> | ||
+ | |||
+ | ===== 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 | ||
+ | <file ini 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 | ||
+ | </file> | ||
+ | |||
+ | /etc/postfix/mailname | ||
+ | <file ini mailname> | ||
+ | your-host-name.example.org | ||
+ | </file> | ||
+ | |||
+ | /etc/aliases | ||
+ | <file ini aliases> | ||
+ | # See man 5 aliases for format | ||
+ | postmaster: root | ||
+ | user:system@example.org | ||
+ | root:system@example.org | ||
+ | </file> | ||
+ | |||
+ | ===== 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]] |