lid's stuff

Hébergement mail perso.

Tout d'abord, pourquoi héberger soi-même ses mails? Pourquoi ne pas utiliser tout simplement un email chez son FAI ou chez un fournisseur (des plus classiques (think GAFAM) et utilisés à ceux plus confidentiels mais avec des objectifs plus "nobles" quant à la protection de la vie privée de leurs utilisateurs, de feu lavabit à protonmail en passant par Caliopen)?

Tout simplement pour se réapproprier un des fondamentaux d'Internet: le mail.

Prérequis

Plusieurs choses nécessaires pour la suite des évènements:

  • Un serveur/machine
  • Un nom de domaine
  • Un enregistrement MX pointant sur la machine qui va héberger nos mails
  • spécial Alarig: un PTR aussi, c'est mieux.
  • Bonus, un enregistrement SPF (TXT)
  • Bonus 2, un enregistrement DKIM (on ne traitera pas cette partie ici)
  • Votre utilisateur (celui ou ceux) qui vont recevoir du courrier sont bien membres du groupe mail (vim /etc/group, ajouter les noms d'utilisateurs à la suite de mail:x:8: ou usermod -aG mail username) sinon Dovecot va nous vomir pleins d'insultes dans les logs.
  • Une petite après-midi (le setup devrait prendre ~2 heures pour la première fois).
  • Du café.

Conventions

On partira du principe que votre nom de domaine est domaine.tld et que votre utilisateur principal s'appelle michel.

De même, on partira du principe que votre machine a pour nom d'hôte hostname. Dès lors son FQDN (Fully Qualified Domain Name) sera hostname.domaine.tld.

De même, on partira du principe que michel a configuré l'accès SSH à sa machine dans ~/.ssh/config, et qu'elle porte le nom machine dans ce fichier, ex: ssh michel@machine. si ce n'est pas le cas, ssh michel@IP-du-serveur suffira.

Logiciels utilisés

  • OpenSMTPd, qui sera notre MTA (Mail Transfer Agent). Il se charge d'envoyer et recevoir nos mails.
  • Dovecot, notre MDA (Mail Distribution Agent), qui s'occupera de la partie IMAP (en local uniquement, j'y reviens) et de la distribution du courrier.
  • RoundCube, MUA (Mail User Agent) qui sera notre client mail. C'est un Webmail, classique PHP/MySQL/serveur web (nginx dans notre cas), qui gère PGP assez facilement. Là aussi nous configurerons son vhost pour n'écouter que sur le lien local (127.0.0.1). Nous y accèderons depuis la machine client via ssh -L PORT_LOCAL:127.0.0.1:PORT_SERVEUR_WEB utilisateur@machine, et en faisant pointer notre navigateur sur https://127.0.0.1:PORT_LOCAL/. Ainsi, notre Webmail ne sera accessible que via un tunnel SSH et n'écoutera pas sur Internet, mais uniquement en localhost.
  • gpg, pour le chiffrement des mails (optionnel mais fortement conseillé - on me souffle dans l'oreillette IRC que ce n'est pas optionnel :D)

Première étape: génération de nos certificats (auto-signés)

Si vous disposez déjà d'un certificat SSL pour votre nom de domaine (let's encrypt anyone?), skippez cette partie.

Sinon, nous allons nous créer une clef et un certificat pour l'authentification smtps/imaps et pour le certificat de notre vhost Roundcube (même si on part sur un tunnel ssh, on ne sait jamais, vous pourriez avoir envie qu'il écoute sur l'interface WAN de votre serveur, ça ne coûte rien à mettre en place et comme ça vous saurez le faire).

On stockera nos certificats dans /etc/mail/certs/.

On génère d'abord notre clef:

openssl genrsa -out /etc/mail/certs/domaine.tld.key 4096

Puis un certificat:

openssl req -new -x509 -key /etc/mail/certs/domaine.tld.key -out /etc/mail/certs/domaine.tld.crt -days 730

Notez qu'on se contrefiche du nom de la clef ou des fichiers, c'est juste que ce sera plus pratique de les retrouver, mais vous pouvez les appeler shmurtz.key ou johnmclane.crt si ça vous fait marrer :)

Seconde étape: OpenSMTPd

Autant se servir du backport plus récent d'OpenSMTPd, on ajoute donc le dépôt backports à notre sources.list:

echo "deb http://httpredir.debian.org/debian jessie-backports main contrib" | sudo tee -a /etc/apt/sources.list

puis ensuite:

sudo apt update && sudo apt install opensmtpd opensmtpd-extras

Quelques questions vous seront posées, lisez-les bien, normalement rien de bien méchant.

Alors on a quelques blagounettes avec systemd - histoire de changer - mais rien de bien méchant: tout comme pour Varnish (cf article précédent sur ce blog), l'unité systemd d'opensmtpd va d'abord lire /usr/local/etc/smtpd.conf, et si on systemctl restart opensmtpd, ce petit enfoiré le lira depuis /etc/smtpd.conf.

Qu'à cela ne tienne, on résout le problème sans modifier l'unité systemd:

ln -s /usr/local/etc/smtpd.conf /etc/smtpd.conf

et basta!

On édite le fichier /etc/mailname, il devrait contenir ça:

hostname.domaine.tld

Donc, soit vous voulez envoyer vos mail avec l'adresse michel@hostname.domaine.tld et là tout va bien. Mais ça peut être embêtant, et en général on préfèrera envoyer et recevoir des mails via une adresse du type: michel@domaine.tld. On modifie donc le fichier /etc/mailname qui ne devrait au final contenir que ça:

domaine.tld

Une fois que c'est fait, éditons notre fichier /usr/local/etc/smtpd.conf (ou plus simplement /etc/smtpd.conf, vu que c'est un lien symbolique désormais), vous allez voir, ça tient en moins de douze lignes:

pki domaine.tld key "/etc/mail/certs/domaine.tld.key"
pki domaine.tld certificate "/etc/mail/certs/domaine.tld.crt"

listen on eth0 port 25 tls pki domaine.tld hostname "domaine.tld"
listen on eth0 port 587 tls-require pki domaine.tld hostname "domaine.tld"

table aliases file:/etc/aliases

accept from any for domain "domaine.tld" alias <aliases> deliver to mbox
accept from any for domain "hostname.domaine.tld" alias <aliases> deliver to mbox
accept for local alias <aliases> deliver to mbox
accept for any relay

Alors, qu'est ce qu'on fait là?

Premièrement, on déclare les fichiers nécessaires à notre certificat.

Ensuite on demande à opensmtpd de bien vouloir écouter gentiment sur notre interface eth0, sur les ports 25 et 587, en tls, pour notre domaine "domaine.tld"

On déclare ensuite accepter le mail de tout le monde (from any) pour notre domaine "domaine.tld" et pour nos adresses mails renseignées dans /etc/aliases (opensmtpd préconfigure déjà lors de son installation certains grands classiques, genre postmaster, webmaster, etc, etc.), et on les délivrera au format mbox (utilisez la directive maildir si vous préférez utiliser Maildir). Si vous modifiez le fichier /etc/aliases, pensez bien à exécuter la commande:

newaliases

afin qu'opensmtpd puisse les prendre en compte.

On doit normalement, après un:

systemctl restart opensmtpd

Pouvoir envoyer et recevoir du mail dans nos mbox!

Pour vérifier qu'on peut envoyer du mail depuis l'utilisateur michel:

michel@hostname $ echo "yippee"|mail -s "sujet du mail" michel@vilainfai.tld

Normalement vous devriez avoir un mail dans votre boîte "classique" michel@vilainfai.tld. Si on le teste dans l'autre sens, c'est à dire en envoyant un mail depuis la boîte de michel@vilainfai.tld et à destination de michel@domaine.tld, on devrait le recevoir dans la mbox de l'utilisateur michel de notre serveur de mail, et on devrait le voir avec la commande mail.

Si on veut par exemple voir l'état de la file d'attente d'OpenSMTPd:

smtpctl show queue

Qui devrait être vide (normalement). je vous invite bien évidemment chaudement à lire les manpages de smtpd, smtpctl, etc :)

Si tout est OK à ce niveau,on va procéder à l'installation de Dovecot, qui permettra à notre webmail de récupérer les mails de nos utilisateurs. Et qui, si on le fait écouter à l'extérieur (son paramétrage par défaut), nous permettra de récupérer les mails en question en IMAPS avec n'importe quel client mail correctement configuré - mais ce n'est pas le but de cet article (ici, on met juste en place dovecot et roundcube en local).

Dovecot

On va tout d'abord installer dovecot:

apt install dovecot-core dovecot-imapd

Puis on le configure, tout d'abord dans /etc/dovecot/dovecot.conf. Ici, la seule directive que je modifie est la directive listen, je veux juste que dovecot écoute en local:

listen 127.0.0.1

puis dans /etc/dovecot/conf.d/10-ssl.conf:

ssl = yes
ssl_cert = </etc/mail/certs/domaine.tld.crt
ssl_key = </etc/mail/certs/domaine.tld.key
ssl_protocols = !SSLv2 !SSLv3

On veut donc utiliser SSL, enfin plutôt TLS, avec les certificats que nous avons généré préalablement. Bien sûr si vos certificats sont différents, ou si vous utilisez des certificats spécifiques pour dovecot, à vous de les renseigner. Et en gros… voilà, c'est tout. Un petit:

systemctl restart dovecot

et on peut normalement passer à la suite.

RoundCube

La première étape est d'installer les dépendances dont nous allons avoir besoin pour roundcube (on ne l'installera pas des paquets):

apt install mariadb-server mariadb-client nginx-extras php-auth-sasl php-mail-mime php-net-sieve php-net-smtp php-net-socket php-patchwork-utf8 php-pear php5 php5-cli php5-common php5-fpm php5-gd php5-intl php5-json php5-mcrypt php5-mysqlnd php5-pspell php5-readline

Atchoum!

Notez bien le mot de passe pour l'utilisateur racine de votre base de données!. Par défaut MariaDB et mySQL écoutent uniquement en local sur 127.0.0.1:3306. On teste qu'on peut se connecter à la base de données:

mysql -uroot -pvotremotdepasse

On part du principe qu'on va stocker, ensuite, les données de site de roundcube dans /var/www/roundcube, on récupère la dernière version de RoundCube:

cd /var/www
wget https://github.com/roundcube/roundcubemail/releases/download/1.2.0/roundcubemail-1.2.0-complete.tar.gz
tar xvzf roundcubemail-1.2.0-complete.tar.gz
rm *tar.gz # on ne laisse pas de traces :p
mv roundcubemail-1.2.0 roundcube #on va pas s'embêter avec un nom de répertoire "relou"
chown -R www-data: roundcube

On va maintenant créer notre vhost nginx, dans /etc/nginx/sites-available/roundcube:

server {
            listen 127.0.0.1:8443 ssl;
            server_name _;
            ssl_certificate /etc/mail/certs/domaine.tld.crt;
            ssl_certificate_key /etc/mail/certs/domaine.tld.key;
            ssl_session_timeout  5m;
            ssl_protocols  TLSv1;
            ssl_ciphers  HIGH:!aNULL:!MD5;
            ssl_prefer_server_ciphers   on;

            access_log /var/log/mail.roundcube.log;

            # Path to the root of your installation
            root /var/www/roundcube;
            index index.php;

           location ~ ^/favicon.ico$ {
            root /var/www/roundcube/skins/classic/images;
            log_not_found off;

            expires max;
           }

           location = /robots.txt {
            allow all;
            log_not_found off;

           }

           location ~ ^/(README|INSTALL|LICENSE|CHANGELOG|UPGRADING)$ {
            deny all;
           }

           location ~ ^/(bin|SQL)/ {
            deny all;
           }

       # Deny all attempts to access hidden files such as .htaccess, .htpasswd, .DS_Store (Mac).
           location ~ /\. {
            deny all;

            log_not_found off;
           }

            location ~ \.php$ {
            try_files $uri =404;
            include fastcgi_params;                
            fastcgi_pass unix:/var/run/php5-fpm.sock;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            fastcgi_index index.php;
            fastcgi_keep_conn on;
            fastcgi_split_path_info       ^(.+\.php)(.*)$;
            fastcgi_param PATH_INFO       $fastcgi_path_info;
            fastcgi_param PATH_TRANSLATED    $document_root$fastcgi_path_info;
           }
 }

Bon, qu'est ce qu'on fait en gros ici? un tuto sur nginx n'étant pas le principe de cet article, quelques petites explications cependant:

  • On écoute sur 127.0.0.1, sur le port 8443, en local. On ne veut pas - dans ce setup précis - que roundcube et le serveur web écoutent sur l'interface WAN (ie, connectée à Internet) mais uniquement en local. On les joindra via du ssh port forwarding.

  • On utilise quand même SSL (votre navigateur va couiner tout à l'heure, confirmez l'exception de sécurité)

  • On filtre certains types de fichiers (SQL, .htaccess, etc)

  • On envoie via une socket UNIX notre code PHP à PHP-FPM, qui doit écouter (normalement par défaut) sur /var/run/php5-fpm.sock. Vérifiez bien votre configuration à ce sujet dans /etc/php5/fpm/pool.d/www.conf la directive listen, qui doit être de la forme:

    listen = /var/run/php5-fpm.sock

Libre à vous d'utiliser un autre nom de socket, ou d'utiliser en TCP (127.0.0.1:9000 de mémoire par défaut si c'est en TCP). On va aussi avoir besoin d'une dépendance de PHP-Pear qui n'est pas disponible dans les dépôts, pour ça:

pear install channel://pear.php.net/Net_IDNA2-0.1.1

Une fois que tout ça est fait, on va pouvoir mettre en place notre site. Si on ne se sert pas du site par défaut de nginx:

rm /etc/nginx/sites-enabled/default

Puis:

ln -s /etc/nginx/sites-{available,enabled}/roundcube

Et enfin:

systemctl reload nginx

Et… on ne peut pas accéder à notre webmail depuis le grand ternet, mais c'est trop nul!! On y arrive, mais avant, un dernier truc:

mysql -uroot -pmotdepasse
CREATE DATABASE roundcube;
GRANT ALL PRIVILEGES ON roundcube.* TO 'utilisateur'@'localhost' IDENTIFIED BY 'votremotdepassequitue';
EXIT;

Et enfin:

mysql -uutilisateur -pvotremotdepassequitue roundcube < /var/www/roundcube/SQL/mysql.initial.sql

accès et configuration du webmail

En fait, oui, on ne peut pas accéder à notre webmail depuis l'extérieur, et c'est voulu! Pour celà, on va en fait faire du tunneling ssh. Depuis notre machine de travail:

ssh -L 8443:127.0.0.1:8443 michel@machine

à partir de là, on peut accéder à l'interface de configuration de roundcube via l'URL suivante:

https://127.0.0.1:8443/installer

Suivez bien les instructions, il n'y a rien de difficile normalement et l'installateur vous pointera les problèmes de dépendances, username/password, etc. Pensez à activer le plugin Enigma.

Une fois que tout est fini, et que vous avez pu envoyer et recevoir un mail depuis roundcube en vous connectant à https://127.0.0.1:8443/ et en vous identifiant avec le login et le mot de passe UNIX de michel, supprimez le répertoire /var/www/roundcube/installer, vous n'en aurez plus besoin.

Désormais, pour accéder à votre Webmail, pensez à toujours vous connecter à votre serveur via le SSH port forwarding expliqué ci-dessus. Si vous pensez que vous ne risquez pas grand chose, vous pouvez modifier la directive correspondante dans la configuration du vhost nginx.

De même, si vous voulez utiliser votre client mail favori depuis votre desktop pour accéder à vos mails, modifiez la configuration de dovecot en conséquence. Ne lésinez pas sur les détails de sécurité omis ici puisque tout se passe, mis à part la conf' d'OpenSMTPd, en local de votre serveur et tout est forwardé en SSH (et donc chiffré) jusqu'à chez vous.

Bonus points: GPG

Sur une de vos machines (pas nécessairement le serveur), créez d'abord la clef GPG pour votre utilisateur michel@domaine.tld:

$ gpg --gen-key

Soyez patients (n'hésitez pas à faire "mouliner" disque dur et CPU pour générer de l'entropie au maximum afin d'accélerer les calculs de GnuPG) et renseignez bien les différents champs demandés (notamment: 4096 bits pour RSA, et bien évidemment… celui de l'adresse mail (ORLY?)).

En fin de calcul, GPG vous sortira quelque chose comme ça:

pub   4096R/FFFFFFFF 2016-06-05

Où bien évidemment, FFFFFFFF sont les 32 derniers bits de l'empreinte de votre clef GPG.

Puis ensuite:

$ gpg --keyserver pgp.mit.edu --send-key FFFFFFFF

On va ensuite avoir besoin de renseigner la clef publique ET la clef privée dans la configuration GPG de Roundcube (dans Paramètres/PGP Keys), il faut donc les exporter de notre trousseau:

$ gpg --export --armor FFFFFFFF > ~/ma_clef_publique_GPG
$ gpg --export-secret-key -a "michel" > ~/ma_clef_privee_gpg

Et charger ensuite via notre navigateur ce couple de clef dans l'interface de roundcube prévue à cet effet, et modifier les options de chiffrement dans Paramètres/Préférences/Encryption.

Et voilà, vous pouvez désormais envoyer/recevoir des mails chiffrés. pensez à rajouter les clefs publiques GPG de votre Web of trust dans l'interface de roundcube.

Ça marche pas!

Vous pouvez m'insulter si ça ne marche pas à l'adresse blog arobase lidstah dot info :)


Tagged under: sysadmin, linux, network, UNIX, mail, openstmpd