Version en travail, non testée, reprenant les points clés vu dans les divers tutos et adaptés à ma propre façon de fonctionner.
Ça peut se faire par la suite mais comme ça met toujours un peu de temps à se propager… et autant avoir rapidement le nom de domaine dispo.
Quelque chose dans ce genre :
mail.example.org. IN A a.b.c.d mail.example.org. IN AAAA 2001:a::b example.org. IN MX 10 mail.example.org.
Le faire sur ipv6 si possible… Aujourd'hui tous les serveurs devraient le permettre.
Il faut aussi configurer son Reversedns et ça, c'est permis ou non par l'hébergeur (dans l'interface web de gestion de la machine). La machine prend le “nom” du serveur mail.
Sur Oneprovider, pas de souci. Depuis OVH telecom, ça se fait aussi, dans la partie telecom justement.
Ensuite, pour tester :
dig +short -x "a.b.c.d" @9.9.9.9 dig +short -x "2001:a::b" @9.9.9.9
L'un et l'autre doivent donner le nom de domaine configuré pour les ip en question. Le “@9.9.9.9” à la fin permet de passer par l'extérieur, si on teste en local sur un ordi local, dig ne retourne rien…
CF Serveur neuf : les trucs à faire. Détails propre au serveur mail :
Pour le pare-feu : dans la majorité des cas, le serveur est déjà derrière un pare-feu (proxy, box), les ports autorisés le sont explicitement. Chez moi, derrière la box. Un coup de nmap ip
permet de vérifier les ports ouverts. Sur Numenaute, de la même façon, le proxy protège les containers et vm derrière ; mais là c'est sur lui qu'il faut vérifier que tout est propre.
Il faut tout de même s'assurer que certains ports seront accessibles.
Certains sont non-chiffrés :
Et d'autres pour les échanges chiffrés :
Et suivant les besoins :
J'ai un doute : 25 doit être ouvert puisqu'il sert à initier les communications, mais ensuite seul les chiffrés sont utiles ?
Pour le reste, c'est le paramétrage d'iptable et consort, et c'est détaillé avec la config idoine.
Vérifier que /etc/hosts a un nom de domaine cohérent (si renseigné) avec notre reversedns. Dans mon cas il avait doublé “poste” ce qui faisait un domaine en “poste.poste.mondomain.org”.
Cela donne un fichier de ce genre comme ceci :
127.0.0.1 localhost 127.0.1.1 poste.mondomaine.fr poste # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters
Parait que la commande suivante permet d'avoir les logs “mails” de postfix (plus tard dans le tuto) :
journalctl -ru postfix@-.service
Le -r c'est pour inverser l'ordre, avoir les lignes les plus récentes au début.
En gros postfix.service ça doit être les logs du démon postfix, et postfix@-.service ceux de son pool de mails.
Il y a plein de possibilité de panachages. J'ai fait un choix, ça m'aura pris des jours à me décider, plus des jours à adapter… Je vais essayer d'expliquer mais ce qui est fait pour un logiciel, peut s'adapter à un autre.
Bases de données :
juillet 2024 : je vais tenter de gérer les utilisateurs avec Postfixadmin, donc une base conforme à son usage.
Je fais le choix de Postfix (avec postfix-mysql pour parler à Mariadb) ; aujourd'hui pas mal de gens apprécieront plus Opensmtpd et c'est legit. Pourquoi j'ai finalement pris Postfix ?
Dovecot, tout le monde le plébiscite, et ce n'est pas celui qui m'aura posé de souci.
La chasse aux spams se fera avec rspamd, un logiciel tiers qui traite les spams. Il gère aussi la signature automatique des clés de domaine (DKIM) MAIS je n'ai jamais réussi à le faire marcher de mon côté sur ça, et il m'a bien enquiquiné sur le reste. Donc, le DKIM est géré par Opendkim chez moi.
Quelques outils pratiques à avoir :
Le certificat SSL sera géré avec certbot, classique et fonctionnel.
On va avoir un peu d'apache pour quelques outils visuels de gestion (adminer, rspamd).
Finalement :
sudo apt install mariadb-server redis-server apache2 php postfix postfix-mysql dovecot-mysql dovecot-pop3d dovecot-imapd dovecot-lmtpd dovecot-managesieved rspamd adminer swaks mutt certbot python3-certbot-apache python3-icu opendkim opendkim-tools
Quand Postfix demande sa configuration, répondre “Site Internet”. Vérifier le nom de domaine, par exemple “poste.mondomaine.fr”.
Faire de nouveau un petit sudo grep -nri "poste" /etc/ --exclude-dir=lvm
pour vérifier qu'il n'y a pas de doublon ou de nom bizarre qui traîne.
Refaire un snapshot parce que c'est long d'installer ces logiciels.
sudo lvcreate -L 20g -s -n snap_root_$(date --iso)_logicielsok /dev/VgPoste/root
Maj juillet 2024 : je vais tester :
sudo apt install mariadb-server redis-server apache2 php postfix postfix-mysql dovecot-mysql dovecot-imapd dovecot-lmtpd dovecot-managesieved rspamd swaks mutt certbot
puis (une fois mariadb configuré)
sudo apt install phpmyadmin postfixadmin
Mon apt est configuré pour ne pas installer par défaut les recommandés et suggérés, ce qui demande de voir la liste et de compléter au besoin. Ici, à installer en complément pour se simplifier la vie :
sudo apt install shared-mime-info xdg-user-dirs php-curl php-gd
et enfin (parce qu'il est un chouïa pénible sinon)
sudo apt install rkhunter
Après, snapshot et on continue.
Ouais, Apache, parce que je le connais, mais vu ce qu'il y a à faire, Nginx suffira aussi.
On se crée une entrée DNS pour un sous-domaine qui permettra de gérer la partie “web” du serveur (A et AAAA). Je l'ai appelé “lapin”. Ensuite, on crée un dossier et un index (avec un simple hello dedans à ce stade) et on paramètre apache en mode hyper basique (on y reviendra). On fait aussi une page pour la partie “mail”, cela permettra à let's encrypt d'avoir une réponse et à qui cherche le domaine de savoir “c'est quoi”. Le détail de tout ça ci-dessous.
sudo mkdir /var/www/lapin sudo mkdir /var/www/poste
Une page web “propre” quand même…
sudo nano /var/www/poste/index.html
<!DOCTYPE html> <head> <html class="js desktop" lang="fr" dir="ltr"> <meta http-equiv="Content-Type" content="text/html; charset=utf8" /> <!-- meta --> <meta name="description" content="Mail server."> <meta name="author" content="Lievre"> </head> <body> Ceci est un serveur mail. En cas de problème, merci de contacter l'adresse en abuse@. <br>This is a mail server. If you have any problems, please contact the abuse@ address. </body>
sudo nano /var/www/lapin/index.html
<!DOCTYPE html> <head> <html class="js desktop" lang="fr" dir="ltr"> <meta http-equiv="Content-Type" content="text/html; charset=utf8" /> <!-- meta --> <meta name="description" content="Ceci n'est pas un terrier de lapin."> <meta name="author" content="Lievre"> </head> <body> Lapin ! </body>
Puis les droits
sudo chown -R www-data: /var/www/lapin sudo chown -R www-data: /var/www/poste
sudo a2dissite 000-default.conf sudo nano /etc/apache2/sites-available/lapin.conf
Mettre ça :
<VirtualHost *:80> ServerName lapin.example.org DocumentRoot /var/www/lapin </VirtualHost>
Idem sur la poste.
sudo nano /etc/apache2/sites-available/lapin.conf
<VirtualHost *:80> ServerName poste.example.org DocumentRoot /var/www/lapin </VirtualHost>
Puis les commandes suivantes.
sudo a2ensite lapin.conf sudo a2ensite poste.conf sudo systemctl reload apache2
Se rendre sur le web et voir que la page “lapin” et “poste” sont bien là.
Et maintenant on crée un certificat mais juste pour le domaine (hé, on limite les trucs autogénérés dans Apache !) :
sudo certbot certonly --webroot --webroot-path /var/www/lapin -d lapin.example.org sudo certbot certonly --webroot --webroot-path /var/www/poste -d poste.example.org
Puis on crée le fichier apache pour https : sudo nano /etc/apache2/sites-available/lapin-https.conf
(et refaire pareil sur la poste).
<VirtualHost *:443> ServerName lapin.example.org DocumentRoot /var/www/lapin SSLEngine on SSLCertificateFile /etc/letsencrypt/live/lapin.example.org/fullchain.pem SSLCertificateKeyFile /etc/letsencrypt/live/lapin.example.org/privkey.pem </VirtualHost>
On va aussi modifier (re) /etc/apache2/sites-available/lapin.conf
(et poste…) et ajouter ça à la fin mais avant la fermeture de la balise </VirtualHost>
:
RewriteEngine On RewriteCond %{REQUEST_URI} !.well-known/acme-challenge RewriteRule ^(.*)$ https://%{SERVER_NAME}$1 [R=301,L]
Enfin on active ssl, le module rewrite, le site https puis on relance apache.
sudo a2enmod ssl sudo a2enmod rewrite sudo a2ensite lapin-https.conf sudo a2ensite poste-https.conf sudo apachectl -t sudo apachectl graceful
Enfin, vu qu'on a un certbot sur-mesure, il faut lui préciser de redémarrer les logiciels quand le certificat est renouvelé (en théorie rien à faire de ce côté, il gère seul quand demander le renouvellement à ce stade). On édite /etc/letsencrypt/cli.ini
et on ajoute cette ligne :
post-hook = systemctl restart postfix dovecot apache2
On commence en ligne de commande. Ça va bien se passer.
Passons root afin de pouvoir bidouiller mysql sans mot de passe (sinon on ne peux rien faire), lançons mysql puis créons la première database.
sudo -i mysql CREATE DATABASE mailserver;
On va créer 2 users, mailadmin et mailserver (ce dernier ayant seulement le droit de lire la bdd du même nom). Comme mailadmin sera admin, trouvez-lui un nom personnalisé. Générez aussi une phrase de passe pour chaque utilisateur et stockez ça dans votre gestionnaire de clé.
Adaptez les commandes suivantes à ces personnalisations :
grant all on mailserver.* to 'mailadmin'@'localhost' identified by 'PHRASE DE PASSE'; grant select on mailserver.* to 'mailserver'@'127.0.0.1' identified by 'PHRASE DE PASSE';
Pour la suite, je suis presque bêtement ISPmail. Toutes les commandes sont dans mysql.
USE mailserver; CREATE TABLE IF NOT EXISTS `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; USE mailserver; CREATE TABLE IF NOT EXISTS `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `email` varchar(100) NOT NULL, `password` varchar(150) NOT NULL, `quota` bigint(11) NOT NULL DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `email` (`email`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; USE mailserver; CREATE TABLE IF NOT EXISTS `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `source` varchar(100) NOT NULL, `destination` varchar(100) NOT NULL, PRIMARY KEY (`id`), FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Et on va à présent peupler notre base de donnée, et c'est là qu'on adapte un peu le tuto… Bien remplacer “example.org” par notre propre nom de domaine ! Et celui sans le sous-domaine, si j'ai bien suivi…
On quitte un instant mysql et on va générer un mot de passe salé avec dovecot :
sudo doveadm pw -s BLF-CRYPT
Bien le noter et le mettre à la place de celui de l'exemple…
Le code à adapter à présent ! On revient dans mysql
et :
REPLACE INTO mailserver.virtual_domains (id,name) VALUES ('1','example.org'); REPLACE INTO mailserver.virtual_users (id,domain_id,password,email) VALUES ('1', '1', '{BLF-CRYPT}$2y$05$.WedBCNZiwxY1CG3aleIleu6lYjup2CIg0BP4M4YCZsO204Czz07W', 'john@example.org'); REPLACE INTO mailserver.virtual_aliases (id,domain_id,source,destination) VALUES ('1', '1', 'jack@example.org', 'john@example.org');
Si on veut ajouter un autre utilisateur :
REPLACE INTO mailserver.virtual_users (id,domain_id,password,email) VALUES ('X', 'Y', '{BLF-CRYPT}$2y$05$.WedBCNZiwxY1CG3aleIleu6lYjup2CIg0BP4M4YCZsO204Czz07W', 'user@example.org');
Étape facultative.
On va utiliser adminer pour nous aider un peu. On rebidouille /etc/apache2/sites-available/lapin-https.conf
pour ça. Comme toujours avant </VirtualHost>
, on ajoute une ligne de ce genre :
Alias /adminer /usr/share/adminer/adminer
Ça n'a hélas pas l'air de bien marcher si on met une autre adresse que “adminer” (souci de chemin de css codé en dur quelque part)… Comme mettre ce genre de logiciel ouvre une faille (suffirait de brute-forcer la page d'authentification) on va la désactiver une fois nos modifs faites. C'est le plus efficace. On pourrait aussi ajouter un mot de passe en plus, s'appuyer sur fail2ban, etc, mais condamner la porte est plus efficace que de rajouter des verrous, et puis là c'est aussi plus facile à tout point de vue.
Pour prendre ça en compte :
sudo systemctl reload apache2
La page devrait être accessible à l'adresse demandée. Rentrer l'identifiant de “mailadmin” et sa phrase de passe. Laissez “localhost” et “database” vide, on s'en fout.
On peut contrôler visuellement que les tables et leurs données sont cohérentes.
Ici on suit très bêtement https://workaround.org/ispmail/bullseye/making-postfix-get-its-information-from-the-mariadb-database/ sans oublier de changer “example.org” par notre nom de domaine. La partie dite “facultative” n'est pas facultative (on ne crée pas d'alias catch-all mais on crée quand même de quoi gérer les alias et les redirections entre eux…).
Idem sur la suite avec Dovecot et LMTP, rien de nouveau face au tuto.
En fait à ce stade, j'ai suivi sans diverger les pages suivantes :
J'ai sauté le chapitre sur le webmail, il n'est pas question de l'avoir sur cette machine et c'est juste un client.
Je pense tout de même que ça serait bien de reprendre ça à ma sauce, à un moment. La façon dont les modifs sont faites dans /etc/postfix/main.cf
donne un fichier assez illisible.
Je personnalise en français le message aux utilisateurs :
#!/bin/sh PERCENT=$1 USER=$2 cat << EOF | /usr/lib/dovecot/dovecot-lda -d $USER -o "plugin/quota=maildir:User quota:noenforcing" From: postmaster@webmail.example.org Subject: Quota warning - $PERCENT% reached FR : Votre boîte aux lettres ne peut stocker qu'un nombre limité d'e-mails. Actuellement, elle est pleine à $PERCENT%. Si vous atteignez 100 %, les nouveaux courriels ne pourront plus être stockés. Merci de votre compréhension. EN : Your mailbox can only store a limited amount of emails. Currently it is $PERCENT% full. If you reach 100% then new emails cannot be stored. Thanks for your understanding. EOF
Et pour qu'imap affiche le quota restant :
sudo nano /etc/dovecot/conf.d/20-imap.conf
Avoir la ligne suivante :
mail_plugins = $mail_plugins imap_quota imap_sieve
J'ai aussi affiné via Dovecot les valeurs par défaut. Modifier /etc/dovecot/conf.d/90-quota.conf
pour avoir ce contenu :
plugin { quota = maildir:User quota # Mettre 5G de quota par défaut quota_rule = *:storage=5G # Ajouter 100M pour ce qui est dans la corbeille, ça permet de faire du tri sans "ranger" dans la corbeille. quota_rule2 = Trash:storage=+100M quota_status_success = DUNNO quota_status_nouser = DUNNO quota_status_overquota = "452 4.2.2 Mailbox is full and cannot receive any more emails" } service quota-status { executable = /usr/lib/dovecot/quota-status -p postfix unix_listener /var/spool/postfix/private/quota-status { user = postfix } }
C'est bien beau tout ça, mais quand un mail interne au système (par exemple à root) est envoyé, il arrive où ? Nul part, et cette fois pas question de jouer avec Msmtp : le relai, ça sera “nous”. Mais, la logique n'est pas très différente.
On commence par éditer /etc/aliases
:
mailer-daemon: postmaster postmaster: root nobody: root hostmaster: root usenet: root news: root webmaster: root www: root ftp: root abuse: root noc: root security: root default: admin@nomdomaine.org root: admin@nomdomaine.org
Oui, sans le @ à la fin des alias, cette fois. Et vers admin@mondomaine ou autre, hein, tant que c'est un utilisateur présent sur le système.
Puis on régénère le fichier de postfix à propos des alias :
postalias /etc/aliases
Et on peut tester l'envoi d'un mail. J'ai craqué, installé bsd-mailx
(dont la syntaxe pour l'envoi d'un mail test ne me pose pas de souci) et hop :
echo "Test" | mail -s "Test " root
Cela arrive bien dans la boite mail configurée !
Les logiciels de courriel correctement fichus peuvent chercher leur info à https://example.org/.well-known/autoconfig/mail/config-v1.1.xml
. Notez la subtilité : pas le relais mais bien le domaine de base.
Donc, on ajoute ce fichier, soit directement “là”, soit dans un autre dossier et on fait un joli alias dans apache
Alias /.well-known/autoconfig/mail /var/www/monsite.org/autoconfig-mail
Redémarrer Apache.
Dans ce dossier, on va donc mettre config-v1.1.xml
qui va contenir ceci (copié directement de https://workaround.org/ispmail/bullseye/mail-client-auto-configuration-2/ ) :
<?xml version="1.0" encoding="UTF-8"?> <clientConfig version="1.1"> <emailProvider id="workaround.org"> <domain>workaround.org</domain> <displayName>Christoph's Mail Service</displayName> <displayShortName>ISPmail</displayShortName> <incomingServer type="imap"> <hostname>webmail.workaround.org</hostname> <port>143</port> <socketType>STARTTLS</socketType> <authentication>password-cleartext</authentication> <username>%EMAILADDRESS%</username> </incomingServer> <outgoingServer type="smtp"> <hostname>webmail.workaround.org</hostname> <port>587</port> <socketType>STARTTLS</socketType> <authentication>password-cleartext</authentication> <username>%EMAILADDRESS%</username> </outgoingServer> </emailProvider> </clientConfig>
workaround.org
par votre domaine principalwebmail.workaround.org
par votre relaisdisplayName
et displayShortName
À noter, il y a potentiellement d'autres procédures, avec entre autre des ajouts à faire dans la zone DNS. Voir ceci :
Mais, je m'embêterais avec ça si j'ai des soucis… pour le moment, ça suffit.
Oui ben, des soucis, y'en a… Faudra revoir la chose. En tout cas sur l'ajout d'un autre sous-domaine ça a bien cafouillé…
Voir la page dédiée : DNS, SPF, DKIM, DMARC et autres choses à configurer sur le mail
On en arrive au point vital. Et on va voir que ce n'est pas si simple.
Mais de quoi je cause ?
Il faut savoir que Gandi a une fonctionnalité épatante : l'alias avec joker.
Extrait de leur doc :
Entrez le nom de d'alias, sans inclure le @. Vous pouvez également utiliser le caractère joker “*” pour, par exemple, avec “pierre*”, rediriger tout ce qui commence par pierre dans votre boite (ex.: pierre@ → pierremartin@, pierreafeu@, etc.). Cette option ne fonctionne toutefois qu'avec un minimum de 2 caractères avant ou après le joker.
Un peu plus d'exemples. J'ai la boite mail vilain@mondomaine.org
, qui me sert à recevoir les inscriptions des sites, newsletters, commandes internet… autant dire que c'est bien rempli. vilain@
n'est jamais exposé sur le net1), au lieu de ça, je donne des alias, dont voici une liste :
Les deux premiers (nom.prenom@
et autrealias@
) n'ont pas de joker, il faut avoir l'adresse exacte pour leur écrire. Les suivants par contre, je les adapte à la volée ; je donne marchand.site1@mondomaine.org
à un premier site marchand et marchand.site2@mondomaine.org
à un second site marchand, sans avoir besoin de créer les alias explicitement. Ensuite je m'en sert pour filtrer ce que je reçois dans ma boite mail et voir qui a revendu mon adresse (elles le sont rarement, en fait).
Je peux non seulement recevoir des mails à ces adresses avec joker, mais aussi répondre avec au besoin, bien que dans ce cas je sois dans l'obligation de déclarer l'alias dans Thunderbird (mais pas chez le fournisseur mail !).
Voilà la killer feature de Gandi, si difficile à trouver ailleurs.
Coup de bol pour moi, tous mes alias fonctionnels sont de la forme chaine.joker
; sans le point, j'allais avoir des soucis.
On va bidouiller quelque chose d'équivalent en deux temps :
Dans ces manipulations, n'importe quelle adresse gagne son “joker” en fin… donc john@domain.org va recevoir aussi tout les possibles john.*@domain.org sans rien avoir à déclarer de plus. Ce qui est un peu gênant, ouvrant la porte à du potentiel flood de spam…
Cela se réglera, chez nous, par l'usage d'Anonaddy. Mais, en attendant, il faut s'assurer de pouvoir tout recevoir.
C'est Dovecot qui débloque la solution.
sudo nano /etc/dovecot/conf.d/15-lda.conf
Il y a là la ligne recipient_delimiter = .
(à décommenter et à mettre avec un point, donc).
Lors de mes premiers tests, ça ne permettait pas de répondre.
Mais… Au fil des bidouilles “là ça marche” et je ne suis pas sûre de ce que j'ai changé. J'ai tout de même </WRAP>recipient_delimiter = .
dans /etc/postfix/main.cf
en plus. Pas sûr que ça serve à grand chose car postfix ne reconnait pas le point comme caractère valide, dans mes précédents tests, mais c'est là…
J'ai aussi mes alias déclarés. Par exemple “spam@mondomaine.org” est un alias du vrai mail ; si je tente d'envoyer avec “spam.moi@mondomaine.org” (sans avoir déclarer cet alias par ailleurs), ça envoie.
Par contre tous les alias déclarés sont sans point ; c'est peut-être ça qui bloquait dans mes précédents tests… je n'ai pas déclaré un spam.moi@mondomaine.org“ officiellement et il n'est renseigné nul part. Mais il peut envoyer.
Tout cela demandera plus d'investigation quand je referais un autre serveur mail.
Recharger dovecot et postfix.
En plus de la manipulation précédente, si on veut utiliser le +
en plus du .
.
Dans /etc/postfix/main.cf
, modifier virtual_alias_maps
pour ajouter regexp:/etc/postfix/point_addressing
. Ça devrait ressembler à ça :
virtual_alias_maps = regexp:/etc/postfix/point_addressing, mysql:/etc/postfix/mysql-virtual-alias-maps.cf,mysql:/etc/postfix/mysql-email2email.cf
Modifier /etc/postfix/point_addressing
en mettant les regexp suivantes (à adapter aux noms de domaines servis) :
/^(.*)\.(.*)@(mondomaine\.org|autredomaine\.fr)$/ $1+$2@$3 /^(.*)\+(.*)@(mondomaine\.org|autredomaine\.fr)$/ $1@$3
Le fait de déclarer des noms de domaine évitera qu'on permette n'importe quel alias à tous les domaines, cela offre un peu plus de contrôle.
Recharger postfix.
À la fin de https://workaround.org/ispmail/bullseye/relay-outoing-email-through-postfix/, il y a une note assez sibylline sur le sujet :
Allow aliases?
If you want to allow users to send as one of their aliases you could create a new *.cf file with a mapping query like this: SELECT email FROM virtual_users WHERE email='%s' UNION SELECT destination FROM virtual_aliases WHERE source='%s'
Dans un premier temps, j'ai laissé ça de côté.
Mais, il faut que nos alias puissent répondre. Si John reçoit un mail via son alias Jack, il faut qu'il puisse répondre avec Jack ; et je confirme qu'à ce stade, le serveur refuse que Jack envoie un mail.
Voici la méthode plus détaillée.
J'ai créé /etc/postfix/mysql-allow-alias-send.cf
:
user = mailserver password = hosts = 127.0.0.1 dbname = mailserver query = SELECT email FROM virtual_users WHERE email='%s' UNION SELECT destination FROM virtual_aliases WHERE source='%s'
Pour le faire prendre en compte, modifions smtpd_sender_login_maps
dans /etc/postfix/main.cf
pour que ça ressemble à ça :
smtpd_sender_login_maps=mysql:/etc/postfix/mysql-email2email.cf,mysql:/etc/postfix/mysql-allow-alias-send.cf
Et ça marche. Mieux, si je déclare un alias forgé dans Thunderbird, par exemple si je lui dis que “joe” est un alias de John et que je tente d'envoyer un mail avec joe, le serveur éjecte Joe avec le message suivant dans les logs :
<joe@nordcantal.fr>: Sender address rejected: not owned by user john@mondomain.org; from=<joe@mondomain.org> to=<admin@mondomain.org> proto=ESMTP helo=<[192.168.1.89]>
Ouf ! Ça, ça marche !
Ce sera avec Anonaddy, mais c'est pour une autre fois. Voir la page dédiée.
Anonaddy va permettre d'anonymiser complètement l'adresse mail réelle, d'avoir uniquement les adresses jokers sur certains alias, et même de bloquer l'envoi vers certains alias avec joker. C'est encore mieux que Gandi.
L'outil https://nstools.fr/ liste divers points qui peuvent être améliorés.
(à vérifier, là je teste)
Cela sert à avoir la liste des mails valides sur un serveur. Utilisé par les spammeurs pour contacter les gens… Donc, le désactiver n'est pas vu comme une mauvaise pratique.
Dans /etc/postfix/main.cf
, ajoutez la ligne
disable_vrfy_command = yes
Il faut camoufler les infos sur les versions des logiciels, pas besoin qu'on sache sur quelles failles compter. Rien de compliqué, il suffit de revoir le paramètre smtpd_banner
dans /etc/postfix/main.cf
.
On passe de ceci :
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
à cela :
smtpd_banner = $myhostname ESMTP
Ça devrait suffire.
Ce morceau n'est pas fait ni testé.
Créer le fichier /etc/postfix/check/header_checks_out et mettre ces regexp dedans (source) :
/^\s*Received: from \S+ \(\S+ \[\S+\]\)(.*)/ REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])$1 /^X-Originating-IP:/ IGNORE /^X-Mailer:/ IGNORE /^Mime-Version:/ IGNORE /^User-Agent:/ IGNORE
Là il faut regarder plus en détail… attends, on n'active pas de suite !
Dans l'absolu, ipv6, c'est mieux.
J'ai cependant rencontré un souci de taille : mon routeur n'est pas tout jeune, et ne me permet pas de déclarer l'ipv6 de ma machine. Pour le dire autrement, le réseau local n'est qu'en ipv4 (si j'ai bien compris), et je ne peux rien y faire. En attendant d'acheter un routeur plus optimum et de me former un peu plus à la partie réseau… il va falloir désactiver ipv6 sur mon service, au risque de rencontrer de vrais gros soucis.
La première chose à faire est d'éviter d'avoir une entrée AAAA vers le serveur dans son DNS ; ça, c'est facile.
Mais par défaut, postfix va quand même tenter d'envoyer certains mails en ipv6 (puisque notre serveur, lui, ne sais pas qu'on est fâché avec la technologie moderne). Cela va créer des erreurs de distributions… Car le reverse dns ne peux pas fonctionner sur l'adresse ipv6 à cause de ce fichu routeur !
Je note ça plusieurs jours après l'avoir fait donc, j'ai pu oublier des détails…
Il faut donc ajouter ces lignes dans /etc/postfix/main.cf
:
# Forcer ipv4 tant que je n'ai pas un routeur me permettant d'indiquer mon ipv6 smtp_address_preference = ipv4 inet_protocols = ipv4
Et déclarer uniquement le réseau en ipv4 (mais commentez la partie en ipv6, on espère un jour l'activer…) :
#mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 mynetworks = 127.0.0.0/8
Cette partie risque d'être augmentée au fil du temps.
Je garde trace ici de la manip, mais ce n'est pas pertinent à ce stade, puisque le souci d'ipv6 avec Google venait du routeur et non d'en face…
On peut indiquer des règles spécifiques suivant la destionation. Par exemple pour forcer les communications avec Google à passer par ipv4, créer le fichier /etc/postfix/transport
avec la ligne suivante :
gmail.com smtp4:
Ajouter la ligne suivante dans /etc/postfix/main.cf
:
transport_maps = hash:/etc/postfix/transport
Il faut aussi générer un fichier /etc/postfix/transport.db
, avec cette commande :
postmap /etc/postfix/transport
Redémarrer Postfix.
Là on est dans un truc entre sécurité et mesures antispam. Il est toujours possible qu'un compte mail se fasse pirater, et que le compte serve alors à flooder du spam à fond. Et ça, ce sera très, trèèès mauvais pour nous, parce qu'on va se faire bannir de partout et inscrire en block-list.
Bref, il est temps de paramétrer la chose.
La limite du nombre de mail envoyé à la minute est vraiment facile. Dans /etc/postfix/main.cf
, ajouter quelque chose comme :
smtpd_client_message_rate_limit = 10 anvil_rate_time_unit = 60s smtpd_recipient_limit = 40
Ce qui ici, veut dire qu'on a le droit d'envoyer 10 mails à la minute, chacun à 40 destinataires au maximum. Faut arriver à les écrire, quand même.
anvil_rate_time_unit
: par défaut c'est de toute façon 60 secondes donc on pourrait aussi bien ne pas le déclarer. Cela sert à diverses choses, pas juste à la limite d'envoi de mail. smtpd_client_message_rate_limit
: le nombre de messages autorisé dans cette limite. 2 est évidement mauvais pour la prod, mais cela permet de tester que tout marche : envoyez 3 mails différents depuis la même adresse, en moins d'une minute, et admirez le résultat. Postfix ne met pas vraiment de limite par défaut…smtpd_recipient_limit
: Nombre maximum de destinataires qu'un serveur SMTP de Postfix accepte par requête de livraison de message (défaut : 1000). Il me semble que 40 est déjà énorme, mais ça arrive qu'on envoie un mail collectif à une grosse partie de notre carnet d'adresse.Il y a d'autres options similaires (cf http://www.postfix.org/TUNING_README.html#conn_limit ) mais cela me semble inutile.
En regardant les logs on peut voir que tout le net tente de se connecter à notre pauvre serveur.
Fail2ban éjecte les plus nuisibles (et stupides) mais on peut ajouter aussi ceci dans /etc/postfix/main.cf
:
smtpd_error_sleep_time = 5s smtpd_soft_error_limit = 3 smtpd_hard_error_limit = 10
smtpd_error_sleep_time
: la réponse du serveur SMTP n'est envoyée qu'après un délai lorsque le client a fait plus de $smtpd_soft_error_limit et moins de $smtpd_hard_error_limit erreurs, sans livrer de courrier (1s par défaut).smtpd_soft_error_limit
: Nombre d'erreurs qu'un client SMTP distant est autorisé à faire sans livrer de messages avant d'être ralenti par le serveur SMTP de Postfix (10 par défaut).smtpd_hard_error_limit
: Nombre maximum d'erreurs qu'un client SMTP distant est autorisé à commettre sans livrer de message. Le serveur SMTP de Postfix coupe la connexion au delà de cette limite (20 par défaut).Là je me fais plaisir à bien baisser la limite… parce que les serveurs sérieux ne font pas d'erreurs. On verra si cela complexifie ma réception de mails.
Attention cependant car cela peut aussi ralentir tout postfix et donc appliquer des délais à des clients légitimes.
Dans /etc/postfix/main.cf
:
error_notice_recipient = postmaster@mondomain.org notify_classes = resource, software,policy,bounce,delay
error_notice_recipient
: par défaut les notifications sont délivrées à “postmaster” (en local), donc ça devrait arriver, mais on peut aussi indiquer une autre adresse mail, vu que de toute façon… ben on a un serveur d'envoi de mail…notify_classes
: qu'est-ce qui va être notifié. Par défaut, resource
(problème de ressources) et software
(problème de logiciel). On peut ajouter ce qui suit : bounce
: détails des en-têtes pour les messages rejetés à la livraison. Inclut le paramètre 2bounce
donc pas besoin de le mettre aussi. 2bounce
: avis de rejets non-livrablesdelay
: à propos des messages retardéspolicy
: à propos des messages rejetés pour cause de restriction. Genre trop d'envoi à la minute.protocol
: erreur de protocole du client ou du serveur. Et là je crains que ça floode à mort sur les gens qui tentent de se connecter de façon non autorisée, alors je ne l'ai pas mis dans ma configuration.Cela peut faire pas mal de flood sur postmaster, mais permet aussi de voir rapidement si le serveur a un souci.
Cf https://postfix.traduc.org/index.php/postconf.5.html#notify_classes pour la doc officielle traduite.
Doc de référence : https://www.postfix.org/postconf.5.html.
Attention, c'est pas au point parce que je n'ai pas encore mis en place “subcleanin” comme proposé dans https://blog.debugo.fr/serveur-messagerie-optimisation-postfix/ et donc ben… c'est le bordel !
Postscreen va appliquer des vérifications sur les domaines (entre autre) et faciliter le tri. On pourra ainsi déclarer certains domaines comme bloqués, et d'autres comme de confiance, et en mettre certains en liste grise. Pour chaque contrôle, on peut au choix :
ignore
: on ne fait rienenforcer
: on bloque et on enverra un retour RCPT TO: 550 5.3.2 Service currently unavailable
drop
: on répondra 521 5.3.2 Service currently unavailable
Dans le fichier /etc/postfix/master.cf
, commentez la ligne :
smtp inet n - y - - smtpd
et décommenter
smtp inet n - y - 1 postscreen smtpd pass - - y - - smtpd -o cleanup_service_name=subcleanin dnsblog unix - - y - 0 dnsblog tlsproxy unix - - y - 0 tlsproxy
Qu'est-ce qu'on est en train de faire ?
Les colonnes se réfèrent aux informations suivantes :
inet
passe par TCP/IP et est accessible depuis le réseauunix
et pass
sont des processus locaux. pass
ne reçoit qu'une connexion par requête.inet
est forcément public. Par défaut sur “y” et par déduction je dirais que “y” veut dire “privé”.?
ça indique qu'il ne faut pas le réveiller tant qu'il n'a pas été appelé par ailleurs. 0 indique qu'on ne fait pas de réveil automatique.-o name=value
(forme raccourcie, sinon il y a une façon longue de le raconter) : surcharge le paramètre en question de main.cf
. La doc conseille de ne pas en abuser.Source : le manpage et configuration de postcreen par Debugo.
Ici, donc, on va activer l'usage de postscreen (utile pour bloquer pas mal de spam), dnsblog pour filtrer les dns bloqués, et tls proxy pour le support de STARTTLS dans postscreen.
On ajoute les lignes suivantes dans /etc/postfix/main.cf
:
postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/mycfg/postscreen_access.cidr postscreen_blacklist_action = drop
/etc/postfix/mycfg/postscreen_access.cidr
permet de bloquer des ip, selon cette forme :
xxx.xxx.xxx.xxx reject
Mais bon, ce travail est surtout réalisé par fail2ban en principe. Ne pas oublier de créer le fichier quand même !
On ajoute ensuite une grande subtilité de postscreen : un petit temps de délai avant de répondre. Un serveur mail bien configuré attend poliment qu'on lui donne la parole… cela éjecte donc un certain nombre de “zombies”. La “greet_banner” est le message envoyé lors de l'attente. Le temps d'attente (ici 3 secondes) permet aussi d'interroger si l'ip est blacklistée.
postscreen_greet_wait = 3s postscreen_greet_banner = Cool, we have time... postscreen_greet_action = drop
Ensuite, on va ajouter des listes à interroger pour savoir si l'ip ne serait pas bloquée. Si oui, alors… on vire
postscreen_dnsbl_sites = zen.spamhaus.org*2, bl.spamcop.net, b.barracudacentral.org*2 postscreen_dnsbl_threshold = 3 postscreen_dnsbl_action = drop
Ici, quelques subtilités (si j'ai compris, ce qui n'est pas certain !) :
postscreen_dnsbl_threshold
indique la limite inférieure inclusive du score du domaine testé qu'on peut accepter. Et là ça demande un peu de détails.Si une ip est trouvée dans une des listes, ça va compter pour “1”. Sauf si on ajoute un chiffre après le nom du domaine et l'astérisque ; dans ce cas ça sera pondéré d'autant. Dans l'exemple ici, si une ip est trouvée sur zen.spamhaus.org, ça va compter pour “2”. Là, avec nos trois listes dont 2 pondérées à “2”, si l'ip est listée partout, elle obtiendra un score de 5. C'est plus haut que 3 ⇒ c'est probablement une adresse louche.
Interroger plusieurs listes augmente donc les chances que l'ip bloquée le soit pour des raisons légitimes.
Et c'est une partie que je dois améliorer dans ma config
Mais, attention. Ces listes ne sont pas toutes gratuites, elles ont des conditions d'utilisation, bref pour ne pas se faire ban soi-même… il faut aller voir tout ça.
Enfin, quelques manip qui passent les ip en “greylisting” en attente d'en savoir plus. Attention, cela peut éjecter des serveurs légitimes mais configurés de façon un peu légère (d'ailleurs, moi-même, je donnerais quoi ?). Enfin, bon, comme cela risque surtout de concerner des copains et qu'ils savent comment me contacter autrement… perso ça ne me stresse pas.
Ajout : ça risque aussi de foutre le boxon dans d'autres cas, car le serveur en face reçoit un message comme quoi “on peut pas recevoir” en premier. Et il doit retenter un envoi, ensuite, qui lui passera… si l'ip du serveur est ok. Or avec les gros, c'est bien possible que les ips tournent histoire d'arriver à envoyer. Bref, à tester mais c'est pas forcément une idée parfaite.
postscreen_pipelining_enable = yes postscreen_pipelining_action = enforce postscreen_non_smtp_command_enable = yes postscreen_non_smtp_command_action = enforce postscreen_bare_newline_enable = yes postscreen_bare_newline_action = enforce
Toutes ces actions demandent que le client en face agisse proprement : il passe le test, se déconnecte, et cause ensuite au vrai postfix. Cela ralentit les échanges et peut être coûteux en ressources (et en temps). Cependant une fois le test passé, l'ip est enregistrée comme “bonne” pendant un certain temps (paramètre postscreen_*_ttl
, 30 jours par défaut donc je ne change rien).
Un petit postfix reload
et… On espère que tout va bien !
C'est quand même plus pratique que de bidouiller la base de donnée, bien que la solution mérite d'être un peu améliorée. Mais, c'est du php : je peux y faire des choses. Et en attendant “ça marche”.
En profiter (si ce n'est déjà fait) pour sécuriser Apache d'après https://khaganat.net/wikhan/fr:apache.
En principe on a déjà un admin pour la base de donnée Mailuser si on a suivi le tuto plus haut.
Télécharger ISPMail Admin. Le dézipper et le mettre “où il faut” sur la partie web.
Dans cfg/config.inc.php
:
db_user
et db_pass
pour mettre l'admin de la database “mailserver”. define('IMA_CFG_LOGIN', IMA_LOGINTYPE_ACCOUNT);
(ou pas, cf la doc)admin_user
et admin_Pass
en créant un truc rien que pour ça.
Dans la config apache de /etc/apache2/sites-enabled/monsite-https.conf
, modifier/ajouter les détails suivants (à adapter au chemin) :
<Directory /var/www/monsite/ > Options FollowSymLinks MultiViews AllowOverride All Order allow,deny allow from all </Directory> <Directory /var/www/monsite/isp/cfg/ > Require all denied </Directory>
Se rendre sur index.php (chemin vers isp) et admirer une interface plus commode pour ajouter users, domaines, etc.
Une fois ISPMail installé, adminer ne sert à rien et présente une faille potentielle, donc on l'enlève :
sudo apt remove adminer
À présent, la gestion des spams.
Vu que j'étais un peu fâchée avec rspamd, s'assurer qu'il a tout ce qu'il lui faut :
apt --install-recommends install rspamd
Et… je vais avoir un souci parce que opendkim a besoin de ceci dans postfix :
smtpd_milters = inet:localhost:8891 non_smtpd_milters = $smtpd_milters
Et rspamd de cela…
smtpd_milters=inet:127.0.0.1:11332 non_smtpd_milters=inet:127.0.0.1:11332
la grande question… peut-on déclarer plusieurs milters ? ça sent les ennuis ça.
Tant qu'on a opendkim, y'a ça à faire
nano /etc/rspamd/local.d/dkim_signing.conf
enabled = false;
Je pense que rspamd donne les infos : https://www.rspamd.com/doc/modules/dkim_signing.html
Et donc on envoie à rspamd qui délègue à opendkim… bon… pas certain que ça soit au top tout ça. Pause, hélas.
https://workaround.org/bullseye/filtering-out-spam-with-rspamd/
Cela va permettre de créer des règles de filtre sur le serveur et donc de trier automatiquement les emails sans lien avec le client courriel. Pratique quand on switche entre webmail et divers thunderbird.
En principe ce qu'on a déjà fait suffit en bonne partie, mais il vient le moment de le tester, et surtout de permettre de gérer ces filtres via un client mail (et ce sera plutôt via notre webmail snappymail que via thunderbird dont l'extension ne marche plus).
Il faut modifier /etc/dovecot/conf.d/20-managesieve.conf
et décommenter les lignes suivantes :
protocols = $protocols sieve service managesieve-login { inet_listener sieve { port = 4190 } service_count = 1 }
Décommenter aussi cette ligne dans /etc/dovecot/conf.d/10-auth.conf
:
disable_plaintext_auth = yes
Relancer Dovecot, puis vérifier que les ports sont bien ouverts :
service dovecot restart lsof -i :4190 -P
Cela devrait donner ce genre de retour
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME dovecot 371602 root 15u IPv4 487495 0t0 TCP *:4190 (LISTEN) dovecot 371602 root 16u IPv6 487496 0t0 TCP *:4190 (LISTEN)
Il faut qu'iptable laisse passer ça aussi :
iptables -A INPUT -p tcp --dport 4190 -j ACCEPT netfilter-persistent save
Il faut aussi permettre à ce port d'être accessible à travers le firewall/proxy/box (mais là, ça dépend de la box etc, donc pas de tuto ici…).
Et voilà, plus qu'à configurer le port et la possibilité d'utiliser SIEVE sur notre client mail favori, ça marche !
Documenter :