Introduction
This page describes how Alexis Huxley installed and configured various mail services.
Warning: Postfix’s chroot environment
Postfix’s chroot environment contains copies of system files, which are not updated when using the postfix command to control the service. Therefore always using the systemctl command, otherwise a lot of head scratching ensues!
Prologue
- On the firewall close the mail related ports.
- Shutdown the existing mail server, if there is one.
- Rsync over users’ mail directories from old storage to new storage.
Certificates
Acquiring proper certificates is outside the scope of this procedure.
- In order to use SSL/TLS, create a self-signed certificate by running:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/ssl/private/mail.key -out /etc/ssl/certs/mail.pem
and answer the questions. E.g.:
Country Name (2 letter code) [AU]:DE State or Province Name (full name) [Some-State]:Bayern Locality Name (eg, city) []:Ismaning Organization Name (eg, company) [Internet Widgits Pty Ltd]:pasta.net Organizational Unit Name (eg, section) []: network Common Name (e.g. server FQDN or YOUR name) []: <fqdn-mail-clients-use-to-connect-to-mail-server> Email Address []:<my-personal-email-address>
You can set the organisation name and unit name to yourself instead, if you want, e.g.:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Alexis Huxley Organizational Unit Name (eg, section) []: person
If the common name does not match the name that clients use to connect to the mail server then mutt will complain:
WARNING: Server hostname does not match certificate
- Make sure the key is readable only by root by running:
ls -ld /etc/ssl/private
Expect output like this:
drwx--x--- 2 root ssl-cert 4096 Nov 2 14:39 /etc/ssl/private
- If clients on the internet will use MX records to identify the mail server for your domain, then configure your DNS accordingly.
- If you have followed this procedure in order to regenerate a certificate then restart the dovecot service.
Dovecot
We set up Dovecot first because it provides user information to Postfix.
- Run:
apt-get install dovecot-core dovecot-imapd
- Stop dovecot with:
service dovecot stop
- Entirely replace /etc/dovecot/dovecot.conf with the following:
# Don't listen on IPv6 listen = * # Encryption ssl = required ssl_cert = </etc/ssl/certs/mail.pem ssl_key = </etc/ssl/private/mail.key disable_plaintext_auth = no # Services provided to other programs service auth { unix_listener /var/spool/postfix/private/auth { group = postfix mode = 0660 user = postfix } } # Protocols protocols = " imap" # Misc mail_privileged_group = mail mail_location = maildir:/var/mail/maildir/%u:INDEX=/var/mail/indexes/%u
- If you want to store mail on NFS but indexes on local disk in an environment where only one machine will access the NFS mount (I do!):
- Add the following to /etc/dovecot/dovecot.conf:
# single-server NFS setup mmap_disable = yes mail_fsync = always mail_nfs_storage = no mail_nfs_index = no
- NFS mount the /var/mail/maildir. For me, this meant:
- on the storage server, add an entry to /etc/exports and run exportfs -av
- on the LDAP server, add a suitable entry to the auto.staging map (see here for details)
- on the mail server, replace /var/mail/maildir with a symlink to ../../staging/mail/maildir.
- Verify that the maildir and indexes directories exist and have permissions:
# ls -lL /var/mail/ drwxrwsrwt 3 root mail 4096 Jul 15 16:29 indexes drwxrwsrwt 5 root mail 45 Sep 1 2018 maildir #
- Add the following to /etc/dovecot/dovecot.conf:
- If you want to have Dovecot automatically add a Trash and Sent folder to mailboxes (I don’t!) then add the following to /etc/dovecot/dovecot.conf:
protocol imap { mail_plugins = " autocreate" } plugin { autocreate = Trash autosubscribe = Trash autocreate2 = Sent autosubscribe2 = Sent }
- If you want to have Dovecot authenticate users and for Dovecot’s LDA to get their home directories from /etc/passwd or from NIS (I did but not any longer) then:
- Add the following to /etc/dovecot/dovecot.conf:
# User and home directory lookup from files/NIS userdb { driver = passwd } # Authenticate via /etc/pam.d/dovecot, which will read files/NIS passdb { driver = pam args = dovecot }
- Add the following to /etc/dovecot/dovecot.conf:
- If you want to have Dovecot authenticate users and for Dovecot’s LDA to get their home directories from LDAP (I do!) then:
- Add the following to /etc/dovecot/dovecot.conf:
# User and home directory lookup from LDAP userdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf } # Authenticate via LDAP passdb { driver = ldap args = /etc/dovecot/dovecot-ldap.conf }
- Create /etc/dovecot/dovecot-ldap.conf containing:
# Without these two, dovecot will log messages complaining # explicitly about these two base = ou=Users,dc=pasta,dc=net uris = ldap://192.168.1.21/ # Without these two, dovecot syslogs "dovecot: imap-login: # Aborted login (auth failed, ...): user=, method=PLAIN, # rip=..., lip=..., TLS, session=" auth_bind = yes auth_bind_userdn = uid=%u,ou=Users,dc=pasta,dc=net # If you want to set any additional user-specific attributes # (e.g. mail quota) then set ALL NEEDED user-specific # attributes plus the additional ones. user_attrs = homeDirectory=home,uidNumber=uid,gidNumber=gid
- If the mail directories are to be automounted, then make sure there is a suitable entry in the automounter map; see here for details.
- Add the following to /etc/dovecot/dovecot.conf:
- Stop systemd managing the sockets:
systemctl mask dovecot.socket
- Restart stuff:
service dovecot restart
- From a machine on the same network check that you can read your mail via IMAP.
- From a machine outside the network check that you can read your mail via IMAP.
Postfix
- Run:
apt-get --purge install postfix postgrey service postfix stop
- marille: Set some environment variables that will be used later in this procedure:
MY_FQHN=$(hostname -f) MY_ROOTRCPT=alexis@pasta.net MY_OTHERNAMES="mail.pasta.freemyip.com,pasta.freemyip.com" # Note comma-separated RELAY_HOSTNAME=smtp.gmail.com RELAY_AUTHENTICATE=yes RELAY_LOGIN=alexishuxley RELAY_PASSWD=<my-gmail-password>
- Edit /etc/postfix/main.cf and insert the following basic configuration:
###################################################################### # # WHO AM I AND WHAT INTERFACES DO I LISTEN ON? # ###################################################################### # myhostname is mainly used to derive other stuff myhostname = MY_FQHN # myhostname must be set and cannot be derived from $myorigin. On # the other hand, myorigin defaults to $myhostname. Therefore set # myhostname explicitly and leave myorigin unset. mydomain defaults # to the last parts of $myhostname. #myorigin = ... #mydomain = ... # Which interfaces to listen on for incoming mails. inet_interfaces = all ###################################################################### # # FROM WHOM DO WE ACCEPT MAILS? # ###################################################################### # http://jimsun.linxnet.com/misc/restriction_order_prelim-03.txt says: # # It was noted earlier that a match stops further processing of # an access list, and of the restriction stage that "called" it. # But what does a restriction return when there's no match? # Well, it returns "DUNNO." ("I don't know, somebody else # decide.") # # and earlier says: # # Postfix' restriction stages are as follows, and are processed # in the following order: # # smtpd_client_restrictions # smtpd_helo_restrictions # smtpd_sender_restrictions # smtpd_recipient_restrictions # smtpd_data_restrictions # # regardless of the order in which they're listed in main.cf. # # ... # # Each restriction stage must evaluate to "OK" or "DUNNO" for # processing to continue with the next stage. # # So we're going to define a series of *_restrictions, which will be # applied according to the above rules. # # In fact, we need only one restriction: smtpd_recipient_restrictions. # Later we say that we accept mails from clients connecting to us from # $mynetworks. Let that be derived from our interfaces' CIDRs. mynetworks_style = subnet # Later we say that we accept mails from clients that do SASL # authentication. Let us allow clients to authenticate this way # (this still doesn't mean we'll accept their mails, only that we # allow them to authenticate) and say how we validate their attempts # to authenticate. smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth # In addition, we can perform some simple checks on the client's # self-introducing 'HELO'. From what I've read, 'HELO' seems pretty # pointless but at the same time a lot of spammers either omit this # or set it to the that name of the server the client is connecting # *to*! I'm going to try commenting this out to see what happens! It # seems to be not very clear what happens when a client doesn't match # any of the restrictions. More info at # http://www.unixwiz.net/techtips/postfix-HELO.html. #smtpd_helo_required = yes #smtpd_helo_restrictions = permit_sasl_authenticated # And finally here is the list of who we will accept mails from smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination, reject_rbl_client zen.spamhaus.org, reject_rbl_client bl.spamcop.net, check_policy_service inet:127.0.0.1:10023, permit ###################################################################### # # IN-BOUND ENCRYPTION # ###################################################################### smtpd_use_tls = yes # Offer encryption, but do not require it (requiring would contravene # RFC2487) smtpd_tls_security_level = may smtpd_tls_cert_file = /etc/ssl/certs/mail.pem smtpd_tls_key_file = /etc/ssl/private/mail.key smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache # Poodle protection smtpd_tls_mandatory_protocols = !SSLv2 !SSLv3 smtpd_tls_protocols = !SSLv2 !SSLv3 ###################################################################### # # OUT-BOUND ENCRYPTION # ###################################################################### # Gmail requires next two lines; others probably don't care smtp_use_tls = yes smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache # Poodle protection smtp_tls_mandatory_protocols = !SSLv2 !SSLv3 smtp_tls_protocols = !SSLv2 !SSLv3 # Our relay (gmail.com) requires us to to SASL authwenticate. smtp_sasl_auth_enable = yes smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd smtp_sasl_security_options = ###################################################################### # # ADDRESS REWRITING # ###################################################################### # If an address matches *.$mydomain then change it to $mydomain. masquerade_domains = $mydomain # Which addresses to we masquerade? masquerade_classes = envelope_sender, header_sender, header_recipient, envelope_recipient # Adjust incomplete addresses for mails generated locally. local_header_rewrite_clients = permit_mynetworks # Mail redirection for mail we've not yet decided is remote or local # (alias_maps is only for mail we've decided is for local delivery). virtual_alias_maps = hash:/etc/postfix/virtual ###################################################################### # # WHICH DOMAINS ARE REMOTE AND WHICH ARE LOCAL? # ###################################################################### # Local is localhost, our private domain name and various public # names we might be known as. mydestination = localhost, $mydomain, MY_OTHERNAMES ###################################################################### # # HOW TO DO REMOTE DELIVERY # ###################################################################### relayhost = RELAY_HOSTNAME # why? smtp_host_lookup = native ###################################################################### # # HOW TO DO LOCAL DELIVERY # ###################################################################### # Note aliases are consulted by LDA (so never consulted if everything # relayed) alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases mailbox_size_limit = 0 mailbox_size_limit = 0 mailbox_command = /usr/lib/dovecot/deliver ###################################################################### # # MISCELLANEOUS # ###################################################################### recipient_delimiter = + inet_protocols = ipv4 append_dot_mydomain = no compatibility_level = 2 #debug_peer_level = 10 #debug_peer_list = 80.187.84.82
- Run:
rm -f /etc/mailname echo "root: MY_ROOTRCPT" > /etc/aliases > /etc/postfix/virtual > /etc/postfix/sasl_passwd [ $RELAY_AUTHENTICATE = yes ] && \ echo "RELAY_HOSTNAME RELAY_LOGIN:RELAY_PASSWD" \ >> /etc/postfix/sasl_passwd
- Replace markers:
perl -pi -e "s/MY_FQHN/$MY_FQHN/g; \ s/RELAY_HOSTNAME/$RELAY_HOSTNAME/g; \ s/RELAY_AUTHENTICATE/$RELAY_AUTHENTICATE/g; \ s/RELAY_LOGIN/$RELAY_LOGIN/g; \ s/RELAY_PASSWD/$RELAY_PASSWD/g; \ s/MY_OTHERNAMES/${MY_OTHERNAMES// /,}/g; \ s/MY_ROOTRCPT/${MY_ROOTRCPT/@/\\@}/g" \ /etc/postfix/main.cf /etc/aliases \ /etc/postfix/virtual /etc/postfix/sasl_passwd
- Update some databases that use the files that had markers:
newaliases postmap hash:/etc/postfix/virtual postmap hash:/etc/postfix/sasl_passwd service postfix stop service postfix start
- If you need to change your DNS database to point other systems on the network to this mail server, then do so now.
- If you have rules on your firewall for incoming mail to update, then update them now.
- When sending personal mail from work, it may be that work’s mail servers block access to any remote host on port 25. Therefore:
- Edit /etc/postfix/master.cf and uncomment the line:
smtps inet n - y - - smtpd
- Rerun:
service postfix restart
- Open port 465 on the firewall.
- Android K-9 needs to be told to connect to the SMTP server using STARTTLS on port 465.
- Edit /etc/postfix/master.cf and uncomment the line:
- Do lots of tests!
- If appropriate, add an entry for webmaster to /etc/aliases and run:
newaliases
Mailman
- Install a basic https webserver as follows:
- Run:
apt-get install apache2 a2enmod cgid remoteip ssl a2ensite default-ssl a2dissite 000-default
- Edit /etc/apache2/sites-available/default-ssl.conf to contain only:
<IfModule mod_ssl.c> <VirtualHost _default_:443> ServerAdmin webmaster@localhost DocumentRoot /var/www/html ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined SSLEngine on SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key <FilesMatch "\.(cgi|shtml|phtml|php)$"> SSLOptions +StdEnvVars </FilesMatch> <Directory /usr/lib/cgi-bin> SSLOptions +StdEnvVars </Directory> # ScriptAlias /cgi-bin/mailman/ /usr/lib/cgi-bin/mailman/ # Alias /pipermail/ /var/lib/mailman/archives/public/ # Alias /images/mailman/ /usr/share/images/mailman/ # <Directory /usr/lib/cgi-bin/mailman/> # AllowOverride None # Options ExecCGI # AddHandler cgi-script .cgi # Require all granted # </Directory> # <Directory /var/lib/mailman/archives/public/> # Options FollowSymlinks # AllowOverride None # Require all granted # </Directory> # <Directory /usr/share/images/mailman/> # AllowOverride None # Require all granted # </Directory> </VirtualHost> </IfModule>
- Edit /etc/apache2/ports.conf and comment out:
#Listen 80
- Configure logging of client IPs on backend vhosts.
- Run:
systemctl restart apache2
- Run:
- Run:
apt-get install mailman newlist mailman
and follow the prompts regarding created the required ‘mailman’ mailing list. (Stupidly, mailman won’t work if this list does not exist.)
- Edit /etc/mailman/mm_cfg.py and set the following variable (values shown are thise that my site requires):
DEFAULT_URL_PATTERN = 'https://%s/cgi-bin/mailman/' DEFAULT_EMAIL_HOST = 'pasta.freemyip.com' DEFAULT_URL_HOST = 'mail.pasta.freemyip.com'
- Uncomment the commented-out section in /etc/apache2/sites-available/default-ssl.conf and run:
systemctl reload apache2
- Edit /var/www/html/index.html to contain only:
<html> <body> <ul> <li><a href="/cgi-bin/mailman/listinfo/mailman">Mailman subscribe</a></li> <li><a href="/cgi-bin/mailman/admin/mailman">Mailman admin</a></li> <li><a href="/cgi-bin/mailman/listinfo/filmnight">FilmNight subscribe</a></li> <li><a href="/cgi-bin/mailman/admin/filmnight">FilmNight admin</a></li> </ul> </body> </html>
- If there is a front-end reverse proxy vhost, then add a stanza like this to its configuration:
ProxyPass / https://<backend>/ ProxyPassReverse / https://<backend>/
- Check that the web interface is accessible by visiting http://<default-url-host>/cgi-bin/mailman/listinfo (the links there won’t work yet).
- Important note: if <mailserver-host> differs from <default-url-host> then http://<mailserver-host>/cgi-bin/mailman/listinfo shows no lists, whereas the first URL shows the lists! In my own case, this means I cannot access http://fusilli/cgi-bin/mailman/listinfo, but must set up the proxy (see below) and then access: https://mail.pasta.freemyip.com/cgi-bin/mailman/listinfo.
- If you have mailing lists to migrate then migrate each of them as follows:
- Create the list by running:
newlist <list-name>
and follow the prompts.
- Add suitable entries to the file /var/www/html/index.html.
- On the old mailserver determine the directories to copy across by running:
find /var/lib/mailman -name <list-name>* -type d -prune
- Copy those directories across.
- Create the list by running:
- Make a test posting.
See also
- Computing
- https://www.digitalocean.com/community/tutorials/how-to-set-up-a-postfix-e-mail-server-with-dovecot
- Postfix: configuring Gmail as relay
- http://apetec.com/support/GenerateSAN-CSR.htm
- http://www.postfix.org/SASL_README.html
- http://www.postfix.org/ADDRESS_REWRITING_README.html#masquerade
- https://wiki2.dovecot.org/HowTo/PostfixAndDovecotSASL
- https://listen.jpberlin.de/pipermail/dovecot/2016-January/001011.html