Journebian · Serveur virtuel Debian 12

Ce serveur virtuel est destiné à l'hébergement de 1 à N domaines avec leur site Web, leur email (SMTP et IMAP) et leur DNS.

Web

Apache

Debian architecture la configuration Apache pour l'utilisation d'hôtes virtuels où la configuration personnelle se trouve finalement dans des fichiers de /etc/apache2/sites-available dédiés chacun à un site.

Le module SSL doit être activé après installation (avec a2enmod ssl).

Pour PHP, j'étais parti avec libapache2-mod-php mais en fait PHP-FPM semble plus approprié. Je supprime donc libapache2-mod-php et installe php8.2-fpm à la place. Ensuite l'installeur indique qu'il faut lancer a2enmod proxy_fcgi setenvif et a2enconf php8.2-fpm.

Certbot

Les certificats Let's Encrypt sont gérés par certbot (et le paquet python3-certbot-apache). Pour l'instant je me suis contenté de certificats pour les domaines servis par Apache. Mais la documentation de Certbot liste de nombreux plugins dont certains utilisant le DNS, y compris hébergé chez Gandi ou Infomaniak.

Quelques commandes utiles.

Le renouvellement est en principe automatisé. De fait la création du certificat a créé /etc/cron.d/certbot, mais c'est surchargé par SystemD, comme le montre systemctl show certbot.timer et plus généralement systemctl list-timers.

Email

Ce n'est pas facile à faire sur un petit serveur personnel, mais ça se fait, comme l'écrit Stéphane Bortzmeyer.

Postfix

La documentation Postfix de Debian n'est pas à jour du passage à SystemD. J'opte plutôt pour la documentation officielle, notamment pour les boîtes aux lettres virtuelles qui peuvent être créées pour des utilisateurs et des domaines arbitraires avec les réglages virtual_mailbox_domains, virtual_mailbox_maps, etc. Les courriers peuvent être stockés façon Maildir.

Sur Debian 12, les logs ne sont plus dans /var/log/mail.log mais obtenus avec journalctl -u postfix@-.service.

Le serveur n'ayant pas d'adresse IPv6 routable, je configure postconf -e "inet_protocols = ipv4" pour éviter des tentatives de connexion d'envoi inutiles, ou pire, le rejet de courriers envoyés si jamais le serveur reçoit un jour une adresse IPv6 routable qui ne serait pas (encore) dans ma configuration SPF.

TLS

Postfix offre le chiffrement avec TLS, configuré avec les réglages smtpd_tls_chain_files, smtpd_tls_security_level, smtpd_tls_auth_only quand il fait serveur, et smtpd_tls_security_level quand il fait client.

Pour la soumission des emails, les standards sont changeants. La documentation de Postfix parle du port 465 au passé. Le port 465 était anciennement appelé smtps. Il est désormais appelé submissions. Sur ce port, SMTP utilise implicitement TLS (sans STARTTLS). Le port 465 du temps où il était appelé smtps n'était pas censé être utilisé pour la soumission d'emails, mais en même temps il ne faisait pas sens car le port 25 était utilisé dans tous les cas par l'infrastructure de transport MX. Il y a donc eu une période de flottement avant que le RFC 8364 désigne le port 465 comme port de soumissions implicitement en TLS et le promeuve.

Spam

Pour éviter de relayer des emails et limiter le spam, Postfix SMTP relay and access control donne les réglages de base (smtpd_client_restrictions, smtpd_helo_restrictions, smtpd_sender_restrictions, smtpd_recipient_restrictions, smtpd_relay_restrictions, smtpd_data_restrictions, smtpd_end_of_data_restrictions).

Évidemment, des serveurs idiots comme spring-chicken-bc.twitter.com se font jeter avec leur HELO spring-chicken-bc.x.com.

Postscreen

Postscreen aide à lutter contre le spam en avant-poste. Postfix Postscreen Howto donne les réglages utiles (postscreen_denylist_action, postscreen_greet_action, postscreen_dnsbl_action et postscreen_dnsbl_sites).

SPF

Pour l'envoi, il n'y a rien à faire dans Postfix. Il suffit selon le RC 7208 d'un enregistrement TXT (on trouve des exemples avec SPF, mais c'est abandonné) dans le DNS pour indiquer que seul le MX du domaine mongenet.ch est autorisé à envoyer des emails de ce même domaine :

mongenet.ch.            3600    IN      TXT     "v=spf1 mx -all"

Pour la réception, il faut utiliser Postfix SMTP Access Policy Delegation, et en particulier déléguer à python-postfix-policyd-spf qui a son paquet Debian. La commande man 1 policyd-spf donne la configuration Postfix à faire.

DKIM

Mon ancienne installation contient les clés dans un répertoire /etc/opendkim/ créé à la main. Mais dans Debian (12) le répertoire /etc/dkimkeys est prévu. Debian fournit une documentation d'installation d'OpenDKIM, car c'est un peu plus manuel que d'habitude.

À la fin, j'ai publié l'enregistrement DNS suivant :

201810._domainkey       IN      TXT     ( "v=DKIM1; h=sha256; k=rsa; s=email; "
          "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxhNr+Crx3f76vgsTw3uPVKl02Eb/4q70YQTU4kt0e8w2uBLOULuZoxzh5VwB0T+AezWTH8uYK5dBApN2ogbTBQUQ5spwAGqNGElFYNNKZ1ITRLryM8tNdDK858FMkMOU21CqSixld0WP5iJovCtxvlC10dLZi1IN/j2XDJzxhbcNqPRYTawGnyWanOxmS7v9vXKEpv9THPY/HL"
          "MhxDr9d+DaJo0a6bpT8iR7RZUkJ1V/vCZ8g/5gV5rhD/AHS37P8mCdFWYlynjTjGr6zudkADYiCfkacc4DTLWXHYOhH3RliRKcANGX5nRmxsVRn3sxWX9XgNQBJQ13jlWpDGGNRQIDAQAB" )  ; ----- DKIM key 201810 for mongenet.ch

DMARC

DMARC est ce qui rend SPF et DKIM utiles à l'envoi, en disant aux serveurs destinataires que faire des emails sans signatures valables. C'est documenté dans le RFC 7489 mais une documentation plus pratique comme celle de LinuxBabe aide. Et un site comme MxToolbox aide à vérifier la configuration faite. À la fin, j'ai publié l'enregistrement DNS suivant :

_dmarc          IN      TXT     "v=DMARC1; p=reject; fo=1; rua=mailto:dmarc@mongenet.ch;"

Dovecot

Dovecot tient mordicus à utiliser l'UID 1002 pour accéder à Maildir. Suivant la documentation Simple Virtual User Installation¶ de Dovecot je crée l'utilisateur et le groupe vmail à la main avec ID 1002.

DNS

Bind

J'installe les paquets bind9 et dnsutils.

Comme le serveur n'a pas d'adresse IPv6 routable, je supprime le support IPv6 en utilisant l'option de ligne de commande -4 de named (systemctl edit named.service). Je pourrais aussi ajouter l'option filter-aaaa-on-v4 yes; dans la configuration de named, mais je vais attendre de voir si c'est utile.

Par défaut, à partir de Bind 9.4.1-P1, allow-recursion a pour liste d'accès par défaut : localnets; localhost;. J'ai mis du temps à trouver l'information, mais je l'ai eu dans What has changed in the behavior of "allow-recursion" and "allow-query-cache" du site officiel. C'est cohérent avec la sortie de named -C qui donne les options compilées. J'ai donc bien un DNS récursif pour mon serveur, mais pas pour l'extérieur.

DNSSEC

Sur le serveur précédent je n'avais pas DNSSEC. La commande delv permet de vérifier DNSSEC. La page DNSSEC de Debian donne une marche à suivre détaillée pour utiliser DNSSEC, sauf pour ce qui est de trouver la longueur des clés utilisées dans le domnaine racine (.ch). D'après Switch c'est de l'ECDSA, du SHA-256, avec KSK et ZSK de 256 bits (256 bits pour les clés privées, 512 pour les publiques). Une fois les clés générées, une commande donne l'enregistrement DS mongenet.ch. IN DS 52882 13 2 9DB8A6FC25D3A87E281582915C0D1BB04BCECF903F3ECDA2EEAE83839A861F52. Il m'a fallu un peu d'aide artificielle pour savoir que mettre dans les champs clé et hash de mon registrar. Enfin, c'est à présent tout vert sur https://dnssec-debugger.verisignlabs.com/mongenet.ch.

Le site DNSVIZ donne un bon aperçu de la chaîne de clés DNSSEC :

schéma DNSVIZ

La documentation de Debian ne dit pas qu'il est possible d'indiquer à Bind9 que le DS est publié dans le DNS parent. Or j'ai vu avec la commande rndc dnssec -status mongenet.ch que ma clé CSK n'a pas un statut clair :

# rndc dnssec -status mongenet.ch
dnssec-policy: default
current time:  Mon Oct 28 00:02:40 2024

key: 52882 (ECDSAP256SHA256), CSK
  published:      yes - since Tue Oct  8 01:46:11 2024
  key signing:    yes - since Tue Oct  8 01:46:11 2024
  zone signing:   yes - since Tue Oct  8 01:46:11 2024

  No rollover scheduled
  - goal:           omnipresent
  - dnskey:         omnipresent
  - ds:             rumoured
  - zone rrsig:     omnipresent
  - key rrsig:      omnipresent
...

D'après la documentation DNSSEC de Bind9 la commande rndc dnssec -checkds -key 52882 published mongenet.ch. fait l'affaire. La commande répond KSK 52882: Marked DS as published since 28-Oct-2024 01:45:34.000 mais il n'y a aucun changement dans la sortie de rndc dnssec -status mongenet.ch... Cela dit, ça viendra peut-être avec le temps, si j'en crois la réponse à after DS RECORD publish/verify, DSStatus stuck @ "rumoured" after manual `rndc dnssec -checkds` update ?.

Encore plus troublant est la mise à jour d'une zone protégée par DNSSEC. J'ai changé l'enregistrement _dmarc à p=reject et le numéro de série, mais après un rndc reload, le nouveau numéro de série est servi (dans un transfert de zone par exemple) mais pas la mise à jour du _dmarc ! Je pensais avoir une piste avec la commande rndc zonestatus mongenet.ch m'indique :

# rndc zonestatus mongenet.ch
name: mongenet.ch
type: primary
files: /etc/bind/primary/mongenet.ch
serial: 2024102800
signed serial: 2024102800
nodes: 7
last loaded: Sun, 27 Oct 2024 21:34:38 GMT
secure: yes
inline signing: yes
key maintenance: automatic
next key event: Mon, 28 Oct 2024 03:40:18 GMT
next resign node: _dmarc.mongenet.ch/NSEC
next resign time: Fri, 01 Nov 2024 15:59:37 GMT
dynamic: no
reconfigurable via modzone: no

Mais le next resign node: _dmarc.mongenet.ch/NSEC semble sans rapport avec ma mise à jour de la valeur TXT.

Finalement, la seule solution que j'ai trouvée est de stopper Bind, effacer les fichiers mongenet.ch.jnl, mongenet.ch.signed mongenet.ch.signed.jnl, puis lancer à nouveau Bind.


© 2024 Marc Mongenet
Ce document est disponible sous licence CC BY-SA 4.0.
Dernière mise à jour et validation le 31 octobre 2024.