Installation de XMPP


Petit guide d’installation de XMPP sur une jail FreeBSD.

Niveau : intermédiaire.

Ce billet de blog n’exiterait pas sans celui de ma camarade Codimp

Translate Me

Pré-requis

Outre une jail en état de fonctionner avec les outils de base (vim, sudo, zsh),

Il nous faut :

  • un serveur DNS en état de marche et accessible ;
  • un nom de domaine example.com ;
  • plusieurs sous-domaine :
    • conference.example.com : pour les discussions de groupe ;
    • proxy.xmpp.example.com : le proxy sock5 ;
    • xmpp.example.com : le proxy HTTP pour le transferts de fichiers ;
  • les certificats pour votre instance (par exemple prosody.example.com).

nous aurons besoin d’ouvrir certains ports sur le firewall (pf).

Ces ports ont au nombre de 7 (comme les nains). En voici la liste :

  • 5222 : Port de dialogue en les clients et les serveurs (aka c2s) ;
  • 5223 : Port de dialogue en les clients et les serveurs sur TLS (aka c2s ausi) ;
  • 5269 : Port de dialogue entre les serveurs (aka s2s) ;
  • 5270 : Port de dialogue entre les serveurs sur TLS (aka s2s) ;
  • 5280 : Proxy HTTP BOSH ;
  • 5281 : Proxy HTTP BOSH sur TLS ;
  • 5000 : Proxy socks5 pour les transferts.

Il faudra faire des changements sur le DNS.

En cas de doute, référez-vous à la documentation.

Rappel : le signe % en début de ligne indique une commande lancée par un utilisatur lambda, le signe # indique une commande lancée par l’utilisatur root

Installation de prosody

Nous faire cette installation tout doucement en commençant par le logiciel principal, sources ouvertes naturellement, prosody.

# sudo pkg install prosody

Lisez attentivement le message de l’installation. Vous pourrez le retrouver avec la commande % pkg info -D prosody.

Configuration de prosody

La configuration se trouve dans /usr/local/etc/prosody.

On trouve dans ce répertoire les fichiers *.lua et *.lua.sample.

Ne supprimez pas les fichiers *.lua.sample, ils peuvent à tout moment servir de référence (en plus des pages de manuel et de la documentation).

Lisez les commentaires du fichier de configuration, ils sont très utiles pour comprendre la syntax.

Éditez le fichier prosody.cfg.lua.

Je commence par indiquer l’adresse email du ou des administrateurs de l’instance :

admins = { "admin@example.com" }

Il faut indiquer dans plugins_path, le chemin vers les modules : /usr/local/lib/prosody/modules et /usr/local/lib//prosody/modules-mercurial.

Viennent ensuite les modules qui vont être utilisés. J’ai retiré invites, invites_adhoc, invites_register, register et ajouté le module mam. turn_external

Dans les Admin interfaces rien a modifier.

Dans les HTTP modules j’ai activé bosh et websocket.

Passons aux Other specific functionality ;

annouce, server_contact_info

Attention aux modules_disabled, lisez les commentaires.

De nombreuses lignes n’ont pas à être modifiées (selon ma configration).

Par contre, des options décritess dans la documentation ne sont pas présentes dans le fichier.

c2s_direct_tls_ports = { 5223 };
s2s_direct_tls_ports = { 5270 };

et, pour ne pas ouvrir l’enregistrement depuis l’extérieur,

allow_registration=false

Dans la rubrique (à brac) Storage, j’ai choisi sql et la base de données SQLite3, qu’il faudra penser à installer.

Je n’ai pas réussi à faire fonctionner Prosody avec Sqlite3, je suis repassé au stock interne.

Rubrique Audio/video XMPP à l’aide d’un serveur TURN, qu’il faudra installer ultérieurment. Mais j’ai besoin de renseigner certains items :

turn_external_host = xmpp.example.com
turn_external_secret=UnSuperSecret
turn_external_port = 3478

Pour la gestion des logs il est possibie de tout confier à syslog, en gardant en tête qu’il era nécesaire d’installer et de configurer logrotate.

Les certificats doivent être accesible à prosody, c’est pourquoi ils sont dans le répertoire certs.

Si vous utiliez letencrypt pour obtenir vos certificats, il est important de lire la page de documentation.

Configuration de Virtual hosts

Prosody a beoin d’au moins un virtual hosts. Il faut désativer localhost pour mieux définir xmpp.example.com. Ici s’éteingent les commentaires et seule la documentation peut nous venir en aide. Voici une possibilité :

VirtualHost "example.com"
        -- Assign this host a certificate for TLS, otherwise it would use the one
        -- set in the global section (if any).
        ssl = {
                key = "/etc/prosody/certs/example.com.key";
                certificate = "/ur/local//etc/prosody/certs/example.com.crt";
                ciphers = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256";
                protocol = "tlsv1_2+";
                dhparam = "/ur/local//etc/prosody/certs/dh-2048.pem";
                options = {
                        "cipher_server_preference",
                        "no_compression",
                        "no_ticket",
                        "single_dh_use",
                        "single_ecdh_use"
                };
        }

        disco_items = {
            { "proxy.xmpp.exemple.com", "SOCKS5 proxy" };
            { "conf.exemple.com", "Chatrooms" };
            { "xmpp.exemple.com", "File sharing service" };
        }

Pour terminer, il faut configurer les Components.

Les commentaires sont, là encore très utiles et la documentation est toujours là.

---Set up a MUC (multi-user chat) room server on conf.example.com:
        Component "conference.example.com" "muc"
            modules_enabled = { "muc_mam", "muc_moderation", "vcard_muc" }
            name = "Chatrooms"
            restrict_room_creation = "local"
            muc_max_rooms = 100
            muc_room_default_public = false

-- Set up a SOCKS5 bybasejailream proxy for server-proxied file transfers:
        Component "proxy.xmpp.example.com" "proxy65"
            proxy65_address = "example.com"
            proxy65_acl = { "example.com" }

        Component "xmpp.example.com" "http_file_share"
            http_file_share_size_limit = 1024 × 1024 × 10
            http_file_share_expire_after = 60 × 60 × 24 × 21600

Nous en avons fini avec la Configuration de prosody.

L’installation de l’instance n’est pas termnée pour autant. Il faut :

  • installer les modules mercurial ;
  • mettre en place les certificats ;
  • ~~installer SQLIte3 ~~;
  • mettre à jour le DNS ;
  • modifier le firewall ;
  • tester..

Installation des modules mercurial

Pour installer ces modules, nous allons avoir besoin d’installerle logiciel mercurial un « équivalent » de git.

# pkg install -y mercurial

Puis on clone le dépôt qui propose des modules supplémentaires qui sont déjà utilisés dans le fichier de configuration principal.

# hg clone https://hg.prosody.im/prosody-modules/ /usr/local/lib/prosody/modules

Il y a très peu de chance que nous ayions à utiliser à nouveau mercurial. Pour le désintaller la commande est # pkg remove mercurial

Mise à jour du DNS

Sur la machine/jail qui gère ma zone DNS il faut que j’ajoute des enregistrements.

; xmpp
_xmpp-client._tcp       3600    IN      SRV     0       5       5222       xmpp.example.com.
_xmpps-client._tcp      3600    IN      SRV     0       5       5223       xmpp.example.com.
_xmpp-server._tcp       3600    IN      SRV     0       5       5269       xmpp.example.com.
_xmpps-server._tcp      3600    IN      SRV     0       5       5270       xmpp.example.com.
_xmpp-server._tcp.conf  3600    IN      SRV     0       5       5270       xmpp.example.com.
_xmpps-server._tcp.conf 3600    IN      SRV     0       5       5270       xmpp.example.com.

Et plus loin (chez moi c’est en fin de fichier de zone, celui-ci étant classé alphabétiquement).

;--- xmpp
xmpp                            A           192.0.2.124
xmpp                            AAAA
2001:DB8::1234:1234:1234:1234:1234:1234
conf                            CNAME       xmpp.example.com.
upload                          CNAME       xmpp.example.com.
turn                            CNAME       xmpp.example.com.

Ne pas oublier de changer le serial et les points . en fin de ligne.

Dans une heure, et depuis une autre machine, je pourrais vérifier que mes changements sont pris en compte :

% drill @8.8.8.8 xmpp.example.com
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 4768
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; xmpp.example.com.	IN	A

;; ANSWER SECTION:
xmpp.example.com. 21600 IN  A 192.0.2.214

;; AUTHORITY SECTION:

;; ADDITIONAL SECTION:

;; Query time: 30 msec
;; SERVER: 8.8.8.8
;; WHEN: Wed Mar 26 10:28:57 2025
;; MSG SIZE  rcvd: 49

J’utilise le serveur DNS public de Google (8.8.8.8) et j’obtiens la réponse attendue. Si cela n’avait pas été le cas il m’aurait fallu revoir toute cette partie.

Copie des certificats dans cert

Mes certificats sont issus de Let’s Encrypt ils ont un traitement spécifique avec l’outil prosodyctl.

# prosodyctl cert import /usr/local/etc/letsencrypt/live/example.com

ATTENTION : Si vous montez le répertoire letsencrypt depuis l’hôte, en nullfs l’outil ne fonctionnera pas à cause des permissions. Il est hors de question de changer les permissions du répertoire letsencrypt. La solution que j’ai choisie est d’utilier une petit script demon amie Codimp :

#!/bin/sh

set -e -o pipefail

# certificates after Certbot renewal

certificate_certbot_path="/usr/local/etc/letsencrypt/live/foucry.net"
certificate_prosody_path="/usr/local/etc/prosody/certs"
prosody_user="prosody"
prosody_group="prosody"

cp $(readlink -f ${certificate_certbot_path}/cert.pem) ${certificate_prosody_path}/foucry.net.crt
cp $(readlink -f ${certificate_certbot_path}/chain.pem) ${certificate_prosody_path}/foucry.net.chain.pem
cp $(readlink -f ${certificate_certbot_path}/fullchain.pem) ${certificate_prosody_path}/foucry.net.fullchain.pem
cp $(readlink -f ${certificate_certbot_path}/privkey.pem) ${certificate_prosody_path}/foucry.net.privkey.pem

chown ${prosody_user}:${prosody_group} ${certificate_prosody_path}/*.pem

service prosody restart

Pour les autres fourniseurs de certificats, référez-vous à la documentation.

Je l’ai indiqué dans la fichier de configuration, j’ai besoin d’un fichier dhparam. Je le génère sur la ligne de commande  :

# openssl dhparam -out [usr local etc prosody certs dh pem](/usr/local/etc/prosody/certs/dh-2048.pem) 2048

Modification du pare-feu

ATTENTION : Je pars du principe que vous utilisez pf, que votre configration est NAT opérationelle et que vous avez les compétences nécesaires pour finir la configuration du pare-feu.

Il suffit, pour cette jail, de définir son adresse IP et les ports à ouvrir :

xmpp_jailv4="192.168.127.3"
xmpp_jailv6="2001:0DB8:1234:5678::3"
xmpp_ports={ "5222 5223 5269 5270 5280 5281 5000 2203 3478 5249" }

Puis j’ajoute la redirection :

rdr on $ext_if inet proto tcp from yyany to $ext_if port $xmpp_ports ->
xmpp_jailv4
rdr on $ext_if inet proto tcp from yyany to $ext_if port $xmpp_ports ->
xmpp_jailv6

J’ajouté tout de suite les ports pour l’audio et la vidéo, à savoir : - 3478 : Port en clair - 5349 : Port en TLS

Je teste le fichier avec la commande pfctl :

pfctl -nf /etc/pf.conf

Et si tout est bon, il suffit de supprimer l’option n de la commande précédente.

Installation du serveur TURN

L’installation est simple, FreeBSD propose un paquet :

# pkg install turnserver

Configuration du serveur TURN

J’ai copié le fichier /usr/local/etc/turnserver.conf.defautl dans /usr/local/etc/turnserver.conf. C’est ce dernier qui contientra la configration de mon serveur.

Une fois de plus, lisez les commentaires.

J’ai modifié external-ip pour mettre l’adresse ip externe de mon serveur. J’ai également indiqué que je voulais que les tilisateurs soient gérés dans une bae SQLite3, userdb=/var/db/turndb. Je dois configurer les chemains vers les certificats et inquiquer que je proscri l’utilisation d’anciennes versions de tls : no-tlsv1 et no-tlsv1\_1. Sont imortantes aussi le ligne listen-ip que j’utilie deux fois, pour l’adresse IPv4 et l’adresse IPv6.

Démarrage du serveur TURN

Le serveur TURN démarre au lancement de la jail. Il faut donc l’activer dans le fichier /etc/rc.conf. Pour simplifier cette étape j’utilise : # service turserver enable

Pour démarrer immédiatement le service, j’utilise # service turnserver start et je regarde les logs dans /var/log/

Démarrage de Prosody

Tout comme pour turnserver quelques étapess sont indispensables avant le démarrage du serveur XMPP :

  • créer le premier utilisateur, moi-même : # prosodyctl adduser jacques@example.com ;
  • vérification de la configuration : # prosodyctl check config ;
  • changer le propriétaire et le groupe du dossier utilisé pour les échanges de fichiers : # chown -R prosody:prosody /ur/local/lib/prosody/http_upload ;
  • ajouter le serveur prosody à la séquence de démarrage de la jail : # service prosody enable

La suite, c’est le démarrage du service :

# service prosody start

Regardez le fichier de log. J’ai choisi la gestion des logs par syslog, c’est donc le fichier /var/log/debug.log que je dois regarder.

Mar 30 08:58:59 xmpp prosody[91227]: certmanager: Automatically locating certs for host conference.example.com
Mar 30 08:58:59 xmpp prosody[91227]: certmanager: Using cert "/usr/local/etc/prosody/certs/example.com.fullchain.pem" from index for host "conference.example.com"
Mar 30 08:58:59 xmpp prosody[91227]: conference.example.com:tls: Creating context for s2sin
Mar 30 08:58:59 xmpp prosody[91227]: certmanager: Automatically locating certs for host conference.example.com
Mar 30 08:58:59 xmpp prosody[91227]: certmanager: Using cert "/usr/local/etc/prosody/certs/example.com.fullchain.pem" from index for host "conference.example.com"
Mar 30 08:58:59 xmpp prosody[91227]: unbound: Setting up net.server event handling for ub_ctx: 0x1f5113643238
Mar 30 08:59:00 xmpp prosody[91927]: mod_cron: Running periodic tasks for host example.com
Mar 30 08:59:00 xmpp prosody[91927]: mod_cron: Considering daily task mam/remove_expired_messages (function<mod_mam.lua:545>())
Mar 30 08:59:00 xmpp prosody[91927]: runnerdZhnLBlu6n0_: creating new coroutine
Mar 30 08:59:00 xmpp prosody[91927]: runnerdZhnLBlu6n0_: changed state from ready to error (ready)

Le log me suggère d’activer le module mod_cron pour nettoyer les messages expirés. Toutefois, mon serveur semble fonctionner, il faut mainteant que je fasse des tests.

Derniers mots

Il y a de nombreuses étapes dans la mise en place de ce service, mais souvenez-vous que XMPP est à la base de nombreux logiciels de conférences en visio, je pense notamment à jiti meet qui n’est finalement qu’une jolie interface web sur XMPP.

Il reste à trouver des correspondant·es…