Installer son serveur XMPP avec Prosody

/assets/images/articles/installer-son-serveur-xmpp-avec-prosody.png

Publié le 21/02/2021, dans informatique, xmpp

Article mis à jour le 18/06/2023 pour Prosody 0.12.3

Aujourd'hui, un article pour mettre en place son serveur de discussions instantanées pour parler avec ses ami·e·s de manière sécurisée, libre et décentralisée.

Il existe de nombreuses solutions pour faire de la discussion instantanée, mais les avoir sur ses propres serveurs permet de regagner un peu le contrôle de nos conversations. Pour cela XMPP est un ensemble de protocoles standardisés par l'IETF utilisé depuis de nombreuses années au sein de plusieurs technologies. On le retrouvait par exemple derrière Google Talk, le tchat de Facebook ou encore de nos jours derrière le tchat de League of Legend et Nintendo Switch. XMPP a l'avantage d'être extensible et permet de faire de la communication de manière décentralisée, contrairement à d'autres logiciels comme Signal (qui pour une raison qui j'ignore est adoré par plein de libristes alors qu'il souffre de nombreux problèmes que ces derniers rejetent habituellement).

Avec XMPP comme avec de nombreux autres systèmes décentralisés l'identifiant d'un compte est sous la forme nom@domaine et tous les comptes peuvent communiquer entre eux qu'ils soient sur la même instance XMPP ou non.

Pour commencer

XMPP étant extensible, il permet de nombreuses choses. Je vais donc préciser un peu l'étendue de cet article. Ici, le but sera de mettre en place un serveur permettant uniquement les fonctionnalités que je considère comme étant « de base » de la messagerie instantanée en 2021, à savoir : pouvoir avoir une liste de contacts, envoyer/recevoir des messages, faire des discussions de groupe, envoyer/recevoir des fichiers, et éventuellement passer/recevoir des appels audio/vidéo.

Je vais pour cela utiliser le logiciel Prosody. Il en existe bien d'autres, comme ejabberd qui est bien quand on a beaucoup d'utilisateurices, mais le but ici sera de mettre en place un petit serveur pour les membres d'une famille ou un groupe d'ami·e·s par exemple. Prosody est parfait pour ça et consomme peu de ressources.

Je vais également utiliser Coturn qui permettra de gérer le NAT pour faire de l'audio et de la vidéo.

Dans cet article je vais mettre en place un serveur Prosody ~~0.11.2 sur une Debian 10.8~~ 0.12.3 sur une Debian 11.6. Je pars du principe que l'on a un nom de domaine example.com.

On aura besoin de 4 noms de domaine au total :

Dans cet article, tous ces noms pointent vers le même serveur Prosody.

Nous aurons aussi besoin d'une base de données : par défaut Prosody utilise une base sqlite3 mais ici je vais utiliser une base MySQL.

Installation, enregistrements DNS et pare-feu

On commence par ajouter le Dépôt Prosody pour Debian en suivant leur documentation.

Puis on installe Prosody, ses modules de base et le driver pour notre base de données (MySQL pour moi, mais vous pouvez utiliser sqlite3 ou postgresql) :

# apt install prosody prosody-modules lua-dbi-mysql

On crée une base de données nommée prosody et un utilisateur du même nom ayant les droits sur la base.

On va cloner le dépôt qui contient des modules supplémentaires, car on va en utiliser par la suite, ça se fait via Mercurial, donc on installe déjà :

# apt install mercurial

On clone alors le dépôt dans /usr/local/lib/prosody/modules :

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

On devra renseigner ce chemin de modules en plus de celui déjà présent dans la configuration de Prosody.

Enregistrements DNS

On crée ensuite dans notre zone DNS les deux enregistrements SRV suivants :

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

Le premier indique aux clients XMPP quels sont la priorité (0), le poids (5), le port (5222) et le nom (example.com) des serveurs XMPP pour ce domaine (ici nous en n'avons qu'un seul).

Le second indique exactement la même chose mais pour les serveurs XMPP avec qui notre serveur échangera.

Pare-feu

On va devoir ouvrir 7 ports TCP sur notre serveur (documentation) :

Configuration générale

On peut modifier la configuration du serveur dans /etc/prosody/prosody.cfg.lua pour changer les valeurs par défaut pour notre serveur si on le souhaite.

On commence par indiquer qui sont les administrateurices et qui contacter en cas de soucis :

admins = { "moi@example.com" }

contact_info = {
    abuse = { "mailto:abuse@example.com" };
    admin = { "mailto:abuse@example.com" };
    feedback = { "mailto:abuse@example.com" };
    sales = { "mailto:abuse@example.com" };
    security = { "mailto:abuse@example.com" };
    support = { "mailto:abuse@example.com" };
};

On y modifie la variable plugin_path pour ajouter notre chemin de modules clonés plus tôt :

plugin_paths = { "/usr/local/lib/prosody/modules" }

On décommente la ligne pour utiliser libevent :

network_backend = "event"

On active les modules utiles :

modules_enabled = {
        "admin_adhoc";
        "announce";
        "blocklist";
        "bookmarks";
        "bosh";
        "carbons";
        "cloud_notify";
        "csi";
        "dialback";
        "disco";
        "filter_chatstates";
        "mam";
        "offline";
        "pep";
        "ping";
        "posix";
        "private";
        "proxy65";
        "register";
        "roster";
        "saslauth";
        "server_contact_info";
        "smacks";
        "throttle_presence";
        "time";
        "tls";
        "turncredentials";
        "uptime";
        "vcard4";
        "vcard_legacy";
        "version";
        "watchregistrations";
        "welcome";
}

On indique ensuite les ports de connections TLS direct :

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

Ici on voit que j'ai désactivé l'inscription depuis l'extérieur, car je ne veux pas que n'importe qui puisse s'inscrire sur mon instance.

Comme on veut aussi faire de l'audio/vidéo, on ajoute les informations Turn, on verra par la suite comment installer Coturn :

turncredentials_host = "example.com"
turncredentials_secret = "un-super-secret"
turncredentials_port = 3478

On indique qu'on utilise du SQL et on ajoute les infos pour se connecter à la base :

storage = "sql"

sql = { driver = "MySQL", database = "prosody", username = "prosody", password = "prosody-password", host = "localhost" }

pep permet de publier des infos (la musique qu'on écoute, etc), on indique ici un maximum d'élements :

pep_max_items = 10000

On indique le certificat pour le proxy HTTP :

https_certificate = "/etc/prosody/certs/example.com.crt"

Concernant les certificats TLS, Prosody va automatiquement les chercher dans /etc/prosody/certs/, il y a une documentation pour ça que je vous recommande de lire selon votre cas d'usage (j'utilise "Automatic certificate import" pour récupérer mes certificats), il y en a même une spécifique à Let's Encrypt.

On peut également mettre les logs via syslog avec cette configuration :

log = {
    -- Log files (change 'info' to 'debug' for debug logs):
    info = "/var/log/prosody/prosody.log";
    error = "/var/log/prosody/prosody.err";
    -- Syslog:
    { levels = { "error" }; to = "syslog";  };
}

Configuration du virtualhost

On va à présent créer le fichier de configuration de notre domaine example.com : /etc/prosody/conf.avail/example.com.cfg.lua.

On fait un lien symbolique pour faire pointer /etc/prosody/conf.d/example.com.cfg.lua vers notre configuration dans conf.avail :

# ln -s /etc/prosody/conf.avail/example.com.cfg.lua /etc/prosody/conf.d/example.com.cfg.lua

Et on l'édite :

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 = "/etc/prosody/certs/example.com.crt";
                ciphers = "EECDH+AES:+AES128:+AES256:+SHA256:+SHA512";
                dhparam = "/etc/prosody/certs/dh-2048.pem";
                options = {
                        "cipher_server_preference",
                        "no_sslv2",
                        "no_sslv3",
                        "no_ticket",
                        "single_dh_use",
                        "single_ecdh_use"
                };
        }

        ------ Components ------

        ---Set up a MUC (multi-user chat) room server on conference.example.com:
        Component "conf.example.com" "muc"
            modules_enabled = { "muc_mam", "vcard_muc" }

        -- Set up a SOCKS5 bytestream 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_upload"

On génère notre DH (documentation) :

# openssl dhparam -out /etc/prosody/certs/dh-2048.pem 2048

On vérifie notre configuration avec la commande :

# prosodyctl check config

On donne les droits à l'utilisateur prosody sur le dossier qui contiendra les fichiers envoyés par les utilisateurs :

# chown -R prosody:prosody /var/lib/prosody/http_upload

Si tout est ok on relance prosody :

# systemctl restart prosody

Et on vérifie dans les logs que tout se passe bien :

# tail -f /var/log/prosody/prosody.log

Voici typiquement les logs après le démarrage du serveur :

startup info    Hello and welcome to Prosody version 0.12.3
startup info    Prosody is using the libevent epoll backend for connection handling
portmanager info    Activated service 'http' on [127.0.0.1]:5280, [::1]:5280
portmanager info    Activated service 'https' on [*]:5281, [::]:5281
xmpp.example.com:http   info    Serving 'upload' at https://xmpp.example.com:5281/upload
xmpp.example.com:http_upload    info    URL: <https://xmpp.example.com:5281/upload> - Ensure this can be reached by users
xmpp.example.com:http_upload    info    Storage path: '/data/1/xmpp/prosody/http_upload'
portmanager info    Activated service 's2s' on [*]:5269, [::]:5269
portmanager info    Activated service 's2s_direct_tls' on [*]:5270, [::]:5270
xmpp.example.com:tls    info    Certificates loaded
portmanager info    Activated service 'c2s' on [*]:5222, [::]:5222
portmanager info    Activated service 'c2s_direct_tls' on [*]:5223, [::]:5223
portmanager info    Activated service 'legacy_ssl' on no ports
mod_http    info    Serving 'websocket' at https://*:5281/xmpp-websocket
example.com:http    info    Serving 'websocket' at https://example.com:5281/xmpp-websocket
portmanager info    Activated service 'proxy65' on [*]:5000, [::]:5000
example.com:tls info    Certificates loaded
example.com:cloud_notify    info    Module loaded
portmanager info    Activated service 'console' on [127.0.0.1]:5582, [::1]:5582
mod_http    info    Serving 'bosh' at https://*:5281/http-bind
example.com:http    info    Serving 'bosh' at https://example.com:5281/http-bind
conf.example.com:tls    info    Certificates loaded
localhost:http  info    Serving 'websocket' at https://localhost:5281/xmpp-websocket
localhost:tls   info    Certificates loaded
localhost:cloud_notify  info    Module loaded
localhost:http  info    Serving 'bosh' at https://localhost:5281/http-bind
proxy.xmpp.example.com:tls  info    Certificates loaded

Ajout des utilisateurices et tests

Comme ce serveur est uniquement pour un petit nombre je n'ai pas autorisé l'enregistrement depuis l'extérieur, il faut donc créer les comptes à la main (documentation) :

# prosodyctl adduser codimp@example.com

Ensuite on peut se connecter avec le client XMPP de son choix (j'utilise Gajim sur ordinateur et Conversations sur Android) et tester que tout fonctionne bien.

Si vous préferez les interfaces web il y a un module d'administration web.

Gérer l'audio et la vidéo

Si on souhaite aussi faire de l'audio et de la vidéo on va installer Coturn, la documentation explique bien comment faire.

Conclusion

On a maintenant notre petit serveur de messagerie instantanée et on peut donner notre adresse XMPP à nos ami·e·s pour qu'elleux aussi puissent bavarder avec nous.

Il faut aussi bien penser à surveiller, comme pour tout en informatique, notre serveur XMPP via un logiciel de supervision.

Cet article ne porte que sur l'installation d'un serveur, mais j'en ferai peut-être un autre sur le choix de clients XMPP pour ordinateur ou mobile.

Merci à Imriel pour sa relecture.


Vous pouvez commenter en envoyant un mail via ce bouton (votre adresse ne sera pas publié).

Commenter par mail
ofcourse 23/02/2021

Ils sont 2 sur terre à utiliser encore ce protocole mort née.

Gudbes 03/03/2021

Hé ben je suis l'un des deux restants.... Juste pour info Facebook messenger utilise le protocole XMPP.

Merci pour cette article. Si tu as des astuces pour optimiser et sécuriser ce type de serveur je suis preneur.

Bonne continuation

nks 06/03/2021

je suis le deuxieme, la boucle est bouclée

merci pour ton article ca fait plaisir :)

deuxplusunégaltrois 02/04/2021

ehbahavecmoiçafaittroisofcourse

Ericounet 13/02/2022

merci pour cet article ... j'utilise xmpp depuis très longtemps (donc ça fait 4 utilisateurs!)

Je vais de ce pas installer le serveur sur mon serveur perso à la maison

;)

Eric

Ericounet 10/03/2022

ça y est, c'est installé .... je suis en pleine config des modules, mais j'arrive à 75% de "compliance" .. ça progresse doucement.

serveur : im.yojik.net

Eric