Installer son serveur XMPP avec Prosody

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

Publié le 21/02/2021

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. Je pars du principe que l'on a un nom de domaine example.com.

On aura besoin de 4 noms de domaine au total :

  • example.com : le nom de notre domaine de base
  • conf.example.com : le nom pour les discussions de groupe
  • proxy.xmpp.example.com : le nom pour le proxy sock5 (qui permet de simplifier les choses pour les gens derrière un NAT)
  • xmpp.example.com : le nom pour le proxy HTTP pour l'envois de fichiers

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 installer 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.
_xmpp-server._tcp               IN  SRV     0 5 5269 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 n'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 5 ports TCP sur notre serveur (documentation) :

  • 5222 : Port sur lequel les clients parlent aux serveurs (aussi nommé c2s)
  • 5269 : Port sur lequel les serveurs parlent aux autres serveurs (aussi nommé s2s)
  • 5280 : Port du proxy HTTP BOSH
  • 5281 : Port du proxy HTTP BOSH sur TLS
  • 5000 : Port du proxy socks5 pour les transferts

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", "/usr/local/lib/prosody/modules" }

On décommente la ligne pour utiliser libevent :

use_libevent = true

On active les modules utiles :

modules_enabled = {

    -- Generally required
        "roster";       -- Allow users to have a roster. Recommended ;)
        "saslauth";     -- Authentication for clients and servers.
        "tls";          -- Add support for secure TLS on c2s/s2s connections
        "dialback";     -- s2s dialback support
        "disco";        -- Service discovery

    -- Not essential, but recommended
        "private";      -- Private XML storage (for room bookmarks, etc.)
        "vcard";        -- Allow users to set vCards

    -- Nice to have
        "version";      -- Replies to server version requests
        "uptime";       -- Report how long server has been running
        "time";         -- Let others know the time here on this server
        "ping";         -- Replies to XMPP pings with pongs
        "pep";          -- Enables users to publish their mood, activity, playing music and more
        "welcome";      -- Welcom message for new users
        -- "register";      -- Allow users to register on this server using a client and change passwords

    -- Admin interfaces
        "admin_adhoc";      -- Allows administration via an XMPP client that supports ad-hoc commands

    -- HTTP modules
        "bosh";         -- Enable BOSH clients, aka "Jabber over HTTP"

    -- Other specific functionality
        "posix";        -- POSIX functionality, sends server to background, enables syslog, etc.
        "announce";     -- Send announcement to all online users
        "watchregistrations";   -- Alert admins of registrations
        "offline";      -- Store offline messages

    -- Contrib modules installed in /usr/local/lib/prosody/modules
        "mam";          -- message archive management
        "smacks";       -- stream managment
        "csi";          -- client state indication
        "throttle_presence";    -- presence throttling in CSI
        "vcard_legacy";     -- vcards
        "carbons";      -- carbons
        "blocklist";        -- blocking command
        "server_contact_info";  -- advertise various contact addresses
        "bookmarks";        -- private bookmarks
        "cloud_notify";     -- push notifications
        "turncredentials";  -- time-limited TURN credentials
}

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 configure Disco qui permet de découvrir les services XMPP, ici on lui indique juste où se trouve le proxy socks5 :

disco_items = {
    { "xmpp.example.com", "SOCKS5 service" };
}

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/xmpp.example.com.crt"
https_key = "/etc/prosody/certs/xmpp.example.com.key"

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.

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.11.2
startup info    Prosody is using the libevent epoll backend for connection handling
portmanager     info    Activated service 's2s' on [::]:5269, [*]:5269
portmanager     info    Activated service 'http' on [::]:5280, [*]:5280
portmanager     info    Activated service 'https' on [::]:5281, [*]:5281
portmanager     info    Activated service 'c2s' on [::]:5222, [*]:5222
portmanager     info    Activated service 'legacy_ssl' on no ports
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: '/var/lib/prosody/http_upload'
portmanager     info    Activated service 'proxy65' on [::]:5000, [*]:5000

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.

Publié dans informatique xmpp


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