EDIT 2019: Retrouvez cette série de tuto dans une grosse mise à jour ici : Serveur de messagerie complet avec Postfix, Dovecot, Openldap, Rspamd….
Dans cette première partie de mon tuto : Un serveur mail complet; nous allons mettre en place un serveur mail avec gestion multidomaine, le tout sur une base sql.
Les logiciels utilisés sont : Postfix et Dovecot.
Je démarre avec une maquette contenant trois machines, mail, web et sql.
I – Prérequis
1 – SQL
Sur votre serveur sql, rien de particulier à y ajouter. Nous allons juste créer la base nécessaire à Postfix :
mysql> create database postfix; Query OK, 1 row affected (0.00 sec) mysql> GRANT ALL PRIVILEGES ON postfix.* TO 'postfix'@'IP_MAIL' IDENTIFIED BY 'motdepasse'; Query OK, 0 rows affected (0.00 sec) mysql> FLUSH PRIVILEGES; Query OK, 0 rows affected (0.00 sec) mysql> exit
Remplacez bien sur IP_MAIL par l’adresse IP du serveur mail et motdepasse par un vrai mot de passe.
Les acharnés de la sécurisation peuvent faire un compte postfixadmin avec tous les privilèges et un compte postfix qu’avec le select.
Ici, on fait simple pour le tuto.
2 – WEB – Postfixadmin
Coté serveur web, je suppute que vous avez déjà un Apache (ou Nginx peu importe) avec Php, et son extension Mysql. Il faudra ajouter l’extension Php Imap :
# apt-get install php5-imap
Nous allons télécharger et préparer Postfixadmin qui est l’interface nous permettant d’administrer tout cela le plus simplement du monde :
# wget http://tenet.dl.sourceforge.net/project/postfixadmin/postfixadmin/postfixadmin-2.92/postfixadmin-2.92.tar.gz # tar xzvf postfixadmin-2.92.tar.gz -C /var/www/ # cd /var/www # mv postfixadmin-2.92/ postfixadmin/ # chown -R www-data:www-data postfixadmin/ # sed -i 's/change-this-to-your.domain.tld/votredomaine.tld/g' /var/www/postfixadmin/config.inc.php
Remplacez votredomaine.tld par votre domaine.
Dans le fichier confic.inc.php :
$CONF[‘configured’] = true;
…
$CONF[‘default_language’] = ‘fr’;
…
$CONF[‘database_type’] = ‘mysqli’;
$CONF[‘database_host’] = ‘IP_SQL’;
$CONF[‘database_user’] = ‘postfix’;
$CONF[‘database_password’] = ‘motdepasse’;
$CONF[‘database_name’] = ‘postfix’;
…
$CONF[‘smtp_server’] = ‘IP_MAIL’;
…
$CONF[‘encrypt’] = ‘md5crypt’;
Rendez vous ensuite sur http://mondomaine.tld/postfixadmin/setup.php
L’installation ne devrait pas vous poser de soucis si vous lisez tout correctement.
Pour le compte admin , créez le compte admin@mondomaine.tld.
Une fois l’installation terminée, identifiez vous, puis créer le premier domaine virtuel, puis un premier utilisateur (qui sera votre compte principal.
Idem, je ne détaille pas cette partie, vous devriez comprendre par vous mêmes.
Ensuite, vous pouvez rajouter des alias si vous le désirez (je conseille les classiques postmaster, abuse, etc… Créez aussi un alias de admin@domaine.tld vers votrebal@domaine.tld, je rappele que l’idée ici est de tout avoir dans une boite unique)
Évidement, vous ne laisserez pas l’interface de postfixadmin accessible en http seul. L’ajout du SSL n’est pas dans le scope de ce tuto (pour ma part, j’ai un frontal SSL, j’expliquerais le fonctionnement dans un futur article).
II – Postfix
1 – Installation
Pour le serveur mail, nous commençons avec un serveur Debian Wheezy vierge correctement configurée (résolution DNS entre autres).
On installe postfix et les paquets pour les certificats au passage :
# apt-get install postfix-mysql postfix-pcre libsasl2-2 libsasl2-modules sasl2-bin openssl
Lors de la configuration de postfix, sélectionnez la configuration Site internet et renseignez correctement domaine.tld.
Et pour finir, deux fichiers à remplacer, main.cf et master.cf.
On remplace /etc/postfix/main.cf par le contenu suivant :
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU) biff = no append_dot_mydomain = no myhostname = mail.domaine.fr alias_maps = hash:/etc/aliases alias_database = hash:/etc/aliases myorigin = $mydomain mydestination = $myhostname, localhost.$mydomain, localhost mynetworks = 127.0.0.0/8, 192.168.1.0/24 recipient_delimiter = + home_mailbox = Maildir/ notify_classes = 2bounce, bounce, delay, policy, protocol, resource, software smtpd_helo_required = yes strict_rfc821_envelopes = yes relay_domains = proxy:mysql:/etc/postfix/sql/mysql_relay_domains_maps.cf virtual_alias_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_maps.cf,proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_maps.cf,proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_catchall_maps.cf virtual_gid_maps = static:20001 virtual_mailbox_base = /home/virtual virtual_mailbox_domains = proxy:mysql:/etc/postfix/sql/mysql_virtual_domains_maps.cf virtual_mailbox_maps = proxy:mysql:/etc/postfix/sql/mysql_virtual_mailbox_maps.cf,proxy:mysql:/etc/postfix/sql/mysql_virtual_alias_domain_mailbox_maps.cf virtual_minimum_uid = 20001 virtual_uid_maps = static:20001 proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $smtpd_recipient_restrictions $smtpd_sender_login_maps $has_our_domain_as_sender message_size_limit = 50240000 smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, permit smtpd_data_restrictions = reject_unauth_pipelining, permit
Remplacez myhostname par le hostname de votre serveur et votre réseau interne (il faut que nos autres machines puissent utiliser ce postfix).
On va remplacer le contenu de /etc/postfix/master.cf par :
# # Postfix master process configuration file. For details on the format # of the file, see the master(5) manual page (command: "man 5 master"). # # ========================================================================== # service type private unpriv chroot wakeup maxproc command + args # (yes) (yes) (yes) (never) (100) # ========================================================================== smtp inet n - n - - smtpd #smtp inet n - n - 1 postscreen #smtpd pass - - n - - smtpd #dnsblog unix - - n - 0 dnsblog #tlsproxy unix - - n - 0 tlsproxy #submission inet n - n - - smtpd 587 inet n - n - - smtpd -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes -o smtpd_etrn_restrictions=reject -o smtpd_client_restrictions=permit_sasl_authenticated,reject #smtps inet n - - - - smtpd # -o smtpd_tls_wrappermode=yes # -o smtpd_sasl_auth_enable=yes # -o smtpd_client_restrictions=permit_sasl_authenticated,reject #628 inet n - - - - qmqpd pickup fifo n - n 60 1 pickup -o receive_override_options=no_header_body_checks -o content_filter= cleanup unix n - n - 0 cleanup qmgr fifo n - n 300 1 qmgr #qmgr fifo n - - 300 1 oqmgr tlsmgr unix - - n 1000? 1 tlsmgr rewrite unix - - n - - trivial-rewrite bounce unix - - n - 0 bounce defer unix - - n - 0 bounce trace unix - - n - 0 bounce verify unix - - n - 1 verify flush unix n - n 1000? 0 flush proxymap unix - - n - - proxymap proxywrite unix - - n - 1 proxymap smtp unix - - n - - smtp # When relaying mail as backup MX, disable fallback_relay to avoid MX loops relay unix - - n - - smtp # -o fallback_relay= # -o smtp_helo_timeout=5 -o smtp_connect_timeout=5 showq unix n - n - - showq error unix - - n - - error retry unix - - n - - error discard unix - - n - - discard local unix - n n - - local virtual unix - n n - - virtual lmtp unix - - n - - lmtp anvil unix - - n - 1 anvil scache unix - - n - 1 scache # # # See the Postfix UUCP_README file for configuration details. # uucp unix - n n - - pipe flags=Fqhu user=uucp argv=uux -r -n -z -a$sender - $nexthop!rmail ($recipient)
2 – Fichiers appels SQL
Nous allons ensuite créer un répertoire pour stocker les fichiers d’appels sql :
# mkdir /etc/postfix/sql # cd /etc/postfix/sql
Pour chaque fichier, pensez à remplacer ip et mot de passe bien évidement.
- Fichier mysql_relay_domains_maps.cf :
user = postfix password = motdepasse hosts = IP_SQL dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '1' and active = '1'
- Fichier mysql_virtual_alias_domain_catchall_maps.cf :
user = postfix password = motdepasse hosts = IP_SQL dbname = postfix query = SELECT goto FROM alias,alias_domain WHERE alias_domain.alias_domain = '%d' and alias.address = CONCAT('@', alias_domain.target_domain) AND alias.active = 1 AND alias_domain.active='1'
- Fichier mysql_virtual_alias_domain_mailbox_maps.cf :
user = postfix password = motdepasse hosts = IP_SQL dbname = postfix 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'
- Fichier mysql_virtual_alias_domain_maps.cf :
user = postfix password = motdepasse hosts = IP_SQL dbname = postfix 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'
- Fichier mysql_virtual_alias_maps.cf :
user = postfix password = motdepasse hosts = IP_SQL dbname = postfix query = SELECT goto FROM alias WHERE address='%s' and active = '1'
- Fichier mysql_virtual_domains_maps.cf :
user = postfix password = motdepasse hosts = IP_SQL dbname = postfix query = SELECT domain FROM domain WHERE domain='%s' and backupmx = '0' and active = '1'
- Fichier mysql_virtual_mailbox_maps.cf :
user = postfix password = motdepasse hosts = IP_SQL dbname = postfix query = SELECT maildir FROM mailbox WHERE username='%s' and active = '1'
On sécurise :
# chmod 640 /etc/postfix/sql/mysql_* # chgrp postfix /etc/postfix/sql/mysql_*
3 – Utilisateur Vmail
Nous allons ensuite créer l’utilisateur virtuel vmail ainsi que le repertoire qui stockera les mails :
# groupadd -g 20001 vmail # useradd -g vmail -u 20001 vmail -d /home/virtual -m # chown vmail: /home/virtual -R # chmod 770 /home/virtual
III – Mise en place du TLS
Pour le moment, je pratique avec un certificat autosigné. Tres prochainement, nous verrons comme utiliser un certificat signé par une autorité de confiance.
1 – Certificat Racine
Tout d’abord, dans le fichier /etc/ssl/openssl.cnf, modifiez la ligne default_days en :
default_days = 3650
Ensuite, création du certificat Racine :
# cd # /usr/lib/ssl/misc/CA.pl -newca
On entre ce qu’il faut ou il faut. On choisit une pass phrase, on laisse challenge password vide. Pour le Common Name, renseignez domaine.tld.
Si tout est ok, vous devriez avoir :
Write out database with 1 new entries Data Base Updated
Ce certificat va servir à signer nos certificats. Il est localisé dans le repertoire /demoCA.
2 – CSR et clé privée
Nous allons créer une clée privée et une demande de signature de certificat (CSR ou Certificate Signing Request) :
# mkdir ~/CERT # cd ~/CERT # openssl req -new -nodes -keyout domaine-key.pem -out domaine-req.pem -days 3650
Changez bien sur domaine-key et domaine-req par votre domaine.
Entrez les memes infos que pour le Certificat Racine à l’exception du Common Name qui doit être celui de votre serveur mail : mail.domaine.tld par ex.
On signe maintenant le CSR (en gros, un certificat public non signé) avec le Certificat Racine généré au préalable :
# cd # openssl ca -out CERT/domaine-cert.pem -infiles CERT/domaine-req.pem
La aussi, remplacez domaine …
Validez à la fin la signature avec y et la mise à jour de la base encore avec y.
On va maintenant copier les fichiers dans le répertoire de postfix (en pensant à remplacer domaine…) :
# mkdir /etc/postfix/tls # cp demoCA/cacert.pem CERT/domaine-key.pem CERT/domaine-cert.pem /etc/postfix/tls/ # cd /etc/postfix/tls # chmod 644 domaine-cert.pem cacert.pem # chmod 400 domaine-key.pem # chmod 400 ~/CERT/*
Pour finir, on ajoute ceci au fichier /etc/postfix/main.cf :
smtp_tls_CAfile = /etc/postfix/tls/cacert.pem smtp_tls_security_level = may smtp_tls_session_cache_database = btree:${data_directory}/smtp_tls_session_cache smtpd_tls_security_level = may smtpd_tls_auth_only = yes smtpd_tls_key_file = /etc/postfix/tls/domaine-key.pem smtpd_tls_cert_file = /etc/postfix/tls/domaine-cert.pem smtpd_tls_CAfile = /etc/postfix/tls/cacert.pem smtpd_tls_loglevel = 1 smtpd_tls_received_header = yes smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_tls_session_cache tls_random_source = dev:/dev/urandom smtpd_tls_protocols = !SSLv2,!SSLv3
Et on termine en rechargeant Postfix :
# postfix reload
Normalement, pas d’erreurs…
IV – Dovecot
1 – Installation et configuration
Installation simple avec apt-get :
# apt-get install dovecot-core dovecot-common dovecot-imapd dovecot-lmtpd dovecot-managesieved dovecot-mysql dovecot-sieve dovecot-solr
La configuration de base de Dovecot dans Debian est eclatée dans une multitude de fichier située dans /etc/dovecot/conf.d/.
Perso, je trouve cela penible au possible.
# cd /etc/dovecot/ # mv conf.d/ conf.d.ext/
Remplacez ensuite le fichier /etc/dovecot/dovecot.conf par ce qui suit :
auth_mechanisms = plain login disable_plaintext_auth=yes base_dir = /var/run/dovecot dict { quota = mysql:/etc/dovecot/dovecot-dict-quota-sql.conf } mail_uid = vmail mail_gid = vmail mail_plugins = quota fts fts_solr acl zlib mail_log notify log_timestamp = "%Y-%m-%d %H:%M:%S" mail_location = sdbox:/home/virtual/%d/%n mail_privileged_group = vmail managesieve_notify_capability = mailto managesieve_sieve_capability = comparator-i;octet comparator-i;ascii-casemap fileinto reject envelope encoded-character vacation subaddress comparator-i;ascii-numeric relational regex imap4flags copy include variables body enotify environment mailbox date spamtest spamtestplus virustest namespace { inbox = yes separator = / prefix = type = private mailbox Trash { auto = subscribe special_use = \Trash } mailbox Drafts { auto = subscribe special_use = \Drafts } mailbox Sent { auto = subscribe special_use = \Sent } mailbox Spam { auto = subscribe special_use = \Junk } mailbox SpamFalse { auto = subscribe } mailbox SpamToLearn { auto = subscribe } } namespace { separator = / prefix = INBOX/ inbox = no hidden = yes list = no type = private alias_for = } plugin { acl = vfile acl_shared_dict = file:/home/virtual/shared-%d-mailboxes.db quota = dict:User quota::proxy::quota quota2 = dict:User quota::file:/home/virtual/%d/%n/dovecot-quota quota_warning = storage=85%% quota-warning 85 %u sieve = ~/dovecot.sieve sieve_after = /home/virtual/sieve/global.sieve sieve_dir = ~/sieve mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename save mailbox_create # Also available: flags vsize from subject mail_log_fields = uid box msgid size #fts = solr #fts_solr = url=http://localhost:8081/solr/ zlib_save_level = 9 zlib_save = bz2 } protocols = imap sieve lmtp service auth { unix_listener auth-userdb { mode = 0660 user = vmail } unix_listener /var/spool/postfix/private/auth { group = mail mode = 0660 user = postfix } unix_listener auth-master { mode = 0660 user = vmail } } service auth-worker { # Auth worker process is run as root by default, so that it can access # /etc/shadow. If this isn't necessary, the user should be changed to # $default_internal_user. #user = $default_internal_user } service imap-login { inet_listener imap { address = * port = 143 } inet_listener imaps { address = * port = 993 } process_limit = 256 } service imap { } service managesieve-login { inet_listener sieve { address = * port = 4190 } process_limit = 256 vsz_limit = 64M } service dict { unix_listener dict { mode = 0600 user = vmail } } service quota-warning { executable = script /usr/bin/quota-warning.sh user = vmail unix_listener quota-warning { mode = 0600 user = vmail } } service lmtp { user = vmail inet_listener lmtp { address = * port = 24 } } ssl_protocols = !SSLv2 !SSLv3 ssl_ca = </etc/postfix/tls/cacert.pem ssl_cert = </etc/postfix/tls/domaine-cert.pem ssl_key = </etc/postfix/tls/domaine-key.pem ssl_verify_client_cert = yes ssl = required userdb { args = /etc/dovecot/dovecot-sql.conf driver = sql } passdb { args = /etc/dovecot/dovecot-sql.conf driver = sql } protocol imap { imap_client_workarounds = delay-newmail imap_max_line_length = 65536 mail_max_userip_connections = 20 mail_plugins = quota imap_quota acl imap_acl mail_log notify zlib #mail_plugins = quota imap_quota acl imap_acl autocreate mail_log notify fts fts_solr zlib } protocol sieve { managesieve_logout_format = bytes ( in=%i : out=%o ) } protocol lda { info_log_path = log_path = mail_plugins = sieve quota zlib mail_log notify postmaster_address = postmaster@domaine.tld quota_full_tempfail = yes syslog_facility = mail } protocol lmtp { info_log_path = log_path = mail_plugins = sieve quota fts zlib mail_log notify postmaster_address = postmaster@domaine.tld quota_full_tempfail = yes }
Remplacez les noms des certificats et les adresses postmaster.
Créez ensuite un fichier /etc/dovecot/dovecot-sql.conf :
driver = mysql #default_pass_scheme = MD5 connect = host=IP_SQL dbname=postfix user=postfix password=motdepasse user_query = SELECT '/home/virtual/%d/%n' AS home, 'sdbox:/home/virtual/%d/%n' AS mail, concat('*:bytes=', quota) AS quota_rule FROM mailbox WHERE username = '%u' AND active = '1' password_query = SELECT username as user, password FROM mailbox WHERE username = '%u' AND active = '1' # For using doveadm -A: iterate_query = SELECT username FROM mailbox WHERE active = '1'
Et on termine par le fichier /etc/dovecot/docevot-dict-quota-sql.conf :
connect = host=IP_SQL port=3306 dbname=postfix user=postfix password=motdepasse map { pattern = priv/quota/storage table = quota2 username_field = username value_field = bytes } map { pattern = priv/quota/messages table = quota2 username_field = username value_field = messages }
2 – Dovecot LDA
Il faut maintenant choisir quel MDA (Mail Delivery Agent) utiliser afin de distribuer le courrier aux utilisateurs. Le service de base de Postfix ne suffit pas pour notre usage, il ne gere pas le filtrage ni les quotas.
Il existe Maildrop qui fonctionne parfaitement, mais Dovecot propose aussi le sien, tout aussi efficace et du coup deja integré dans notre solution.
Pour le configurer, on ajoute ce qui suit au fichier /etc/postfix/main.cf :
dovecot_destination_recipient_limit = 1 virtual_transport = dovecot
Et cela au fichier /etc/postfix/master.cf :
dovecot unix - n n - - pipe flags=DRhu user=vmail: argv=/usr/lib/dovecot/deliver -f ${sender} -d ${user}@${nexthop} -a ${recipient}
3 – Sieve
Dovecot LDA permet donc de filtrer les messages en utilisant le protocole Sieve.
On peut agir au niveau global et au niveau utilisateur.
Pour le global, une seule régle : les messages marqués comme Spam sont dirigés dans le répertoire Spam.
Par la suite, chaque utilisateur pourra ajouter ses règles afin de filtrer comme il l’entend.
# mkdir /home/virtual/sieve # chown vmail: /home/virtual/sieve # chmod 750 /home/virtual/sieve
Créez le fichier /home/virtual/sieve/global.sieve avec le contenu qui suit :
require ["fileinto", "envelope", "subaddress"]; if header :contains "subject" "SPAM" { fileinto "Spam"; }
Puis ,
chown vmail: /home/virtual/sieve/global.sieve chmod 600 /home/virtual/sieve/global.sieve
4 – SASL
Rien de sorcier, ajoutez ceci au fichier /etc/postfix/main.cf :
smtpd_sasl_auth_enable = yes smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_security_options = noanonymous smtpd_sasl_local_domain = broken_sasl_auth_clients = yes smtpd_sasl_authenticated_header = yes
Pour finir, toujours dans ce fichier, dans la section smtpd_recipient_restrictions, ajoutez permit_sasl_authenticated à l’endroit indiqué :
... permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination, ...
On termine en relancant les services :
# service postfix restart # service dovecot restart
Si vous n’êtes pas manchot, ce devrait fonctionner.
V – Quota
Tout est déjà configuré et fonctionnel, il ne reste qu’à créer un script qui automatise l’envoi de mail d’avertissement aux utilisateurs.
Créez un fichier /usr/bin/quotawarning.sh :
#!/bin/sh PERCENT=$1 USER=$2 cat << EOF | /usr/lib/dovecot/dovecot-lda -d $USER -o "plugin/quota=dict:User quota::noenforcing:proxy::quota" From: postmaster@domaine.tld Subject: Alerte de Quota Alerte de Quota Votre boite email a atteint $PERCENT% de sa taille maximale. Au dela de 100% les emails ne vous seront plus delivres. EOF
Puis :
#chmod +x /usr/bin/quotawarning.sh
VI – Ports utilisés
Voila la liste des ports utilisés et s’ils doivent etre autorisé en entrée et sortie.
25 : IN et OUT : SMTP
143 : IN : Imap.
587 : IN : SMTPs
993 : IN : Imaps
4190 : IN : Protocol Sieve
VII – Conclusion
Voila pour cette premiere partie.
Vous devez pouvoir recevoir et envoyer des mails depuis n’importe quel client lourd. Attention cependant, aucune protection contre le spam n’est encore en place à ce niveau. De meme, vos mails envoyés vers certains domaines (gmail, hotmail) risquent fort de se retrouver classé comme spam.
Dans la partie II, nous allons donc voir comment lutter contre le spam à différrents niveaux et la signature DKIM de vos messages.