deustux

Servidor de chat XMPP con Prosody

xmpp_logo.png

Mientras todo parece digitalizarse, uno se va dando cuenta de que muchas de las plataformas de mensajería que usamos a diario no respetan nuestra privacidad. Esto se ha ido evidenciando con la propia evolución de Internet: tus mensajes, contactos y grupos suelen pasar por servidores centralizados que pueden recopilar, analizar y correlacionar datos.

El problema no es solo el contenido de los mensajes, sino los metadatos. Quién habla con quién, a qué hora, desde qué dispositivo, con qué frecuencia y desde qué ubicación aproximada. Aunque un servicio prometa cifrado, estos metadatos siguen existiendo y son extremadamente valiosos para elaborar perfiles de usuarios, ya sea con fines comerciales —cuestionables en su propio planteamiento, ya que la extracción masiva de datos personales para su venta resulta, cuanto menos, pretenciosa— o con fines de vigilancia.

Además, los servicios propietarios, como Telegram, funcionan como cajas negras: el código no es auditable y el usuario debe confiar en que se cumpla lo prometido. Como pasó con Telegram pueden haber cambios en las políticas de privacidad, análisis automatizados o integraciones forzadas pueden introducirse sin que el usuario tenga un control real sobre ello. A largo plazo, esto convierte la mensajería en una fuente constante de recolección de datos.

XMPP propone un enfoque distinto. Al ser un protocolo abierto y federado, permite distribuir la confianza: cada usuario puede elegir su servidor o incluso administrar el suyo propio, reduciendo la dependencia de plataformas centralizadas. Combinado con cifrado de extremo a extremo mediante OMEMO, se consigue que el contenido de los mensajes esté protegido y que el control de los datos vuelva al usuario, que es como deberia de ser.

Otro punto fuerte de XMPP es la gran variedad de clientes disponibles para prácticamente cualquier sistema: desde móviles hasta PC y hasta web. Esto significa que no importa si usas Linux, Windows, macOS, Android o iOS, siempre encontrarás un cliente que se adapte a tu flujo de trabajo y preferencias.

conversationsandroid.jpeg

En el escritorio puedes optar por aplicaciones ligeras como Gajim o Dino, que ofrecen todas las funciones de mensajería con cifrado OMEMO y sincronización de historial. Para móviles, hay opciones como Conversations en Android o Monal en iOS, diseñadas específicamente para aprovechar al máximo la federación y mantener tus mensajes privados sin comprometer la experiencia de usuario. Incluso existen clientes web que permiten acceder a tu cuenta desde cualquier navegador sin instalar nada adicional, manteniendo la compatibilidad y seguridad.

gajim.webp

Esta diversidad de clientes es una ventaja enorme frente a plataformas propietarias, que suelen limitarse a apps oficiales con poca flexibilidad y dependientes de la compañía que controla el servicio. Con XMPP, puedes elegir cómo interactúas con tu red, adaptando la experiencia a tus necesidades y asegurándote de que tu comunicación permanezca bajo tu control.


Requisitos para montar el servidor XMPP

En este tutorial vamos a montar un servidor XMPP en una jail de FreeBSD, usando Prosody como motor de mensajería. Prosody es un servidor ligero y flexible escrito en Lua, lo que le da una sintaxis clara y fácil de entender, ideal tanto para administradores novatos como para usuarios avanzados que quieran personalizar su instalación.

Nota sobre llamadas de audio/video (STUN/TURN): XMPP también soporta llamadas y videollamadas mediante protocolos como Jingle, usando servidores STUN/TURN para atravesar NATs y firewalls. Esto permite que los clientes se conecten directamente entre sí para sesiones de audio/video.
En este tutorial no configuraremos servidores TURN/STUN ni llamadas, nos centraremos únicamente en mensajería y transferencia de archivos mediante HTTP, dejando las llamadas como posible ampliación futura.

Prosody soporta varias opciones de almacenamiento para los datos del servidor: PostgreSQL, SQLite, MySQL/MariaDB aunque no es una opción recomendada según el equipo de Prosody y su propio formato interno. Esto nos permite adaptar la instalación a nuestras necesidades, desde un entorno de pruebas hasta un entorno de producción más robusto.

Para que todo funcione correctamente necesitaremos:

  1. Un dominio propio, que será usado para identificar nuestro servidor en la red XMPP.

  2. Registros DNS, que permitirán a otros clientes y servidores localizar nuestro servicio de mensajería de manera estándar y eficiente. Esto incluye SRV y A records para los distintos servicios del servidor. Por ejemplo, en nuestro caso usamos:

1
2
3
4
5
6
7
A @ 127.0.0.1
A muc.deustux.xyz 127.0.0.1
A up.deustux.xyz 127.0.0.1

SRV _xmpp-server._tcp 0 5 5269 muc.deustux.xyz.
SRV _xmpp-client._tcp.deustux.xyz. 3600 IN SRV 0 5 5222 deustux.xyz.
SRV _xmpp-server._tcp.deustux.xyz. 3600 IN SRV 0 5 5269 deustux.xyz.
  1. Certificado SSL/TLS: Necesitarás un certificado válido para tu dominio (por ejemplo, de Let’s Encrypt) para asegurar las conexiones de los clientes y servidores mediante TLS, garantizando privacidad y autenticidad de las comunicaciones.

  2. Subida de archivos: Para la transferencia de archivos en XMPP utilizaremos HTTP, por medio del modulo http_upload_external de prosody, por lo que es recomendable tener un subdominio específico para ello. En nuestro caso creamos el subdominio up.deustux.xyz, que se usará exclusivamente para manejar las cargas y descargas de archivos de manera eficiente y separada del servicio de mensajería principal.

  3. Permitir tráfico en el firewall: Asegúrate de que los puertos 5222 (cliente XMPP) y 5269 (servidor XMPP) estén abiertos en el firewall para que los clientes y otros servidores puedan conectarse correctamente.

Con estos requisitos y registros configurados, podremos instalar y configurar Prosody dentro de la jail, definir nuestro dominio, usar el almacenamiento interno por defecto y empezar a crear cuentas de usuario para conectarnos desde cualquier cliente XMPP compatible.

Instalación de Prosody en FreeBSD 15.0-RELEASE

Cabe aclarar que en este tutorial no usaremos ninguna base de datos externa. Nos quedaremos con el almacenamiento interno por defecto de Prosody, que es suficiente para un entorno de pruebas y permite configurar usuarios y gestionar mensajes sin complicaciones adicionales. Esto nos simplifica la instalación y nos permite centrarnos en la configuración del servidor y la conexión de los clientes.

Lo primero que necesitamos es instalar el servidor Prosody y sus módulos adicionales. En FreeBSD, esto se hace fácilmente con pkg, el gestor de paquetes del sistema.

Dado que estamos trabajando en FreeBSD 15.0-RELEASE, abrimos una terminal dentro de nuestra jail y ejecutamos:

1
2
pkg update
pkg install prosody prosody-modules

Esto instalará Prosody junto con los módulos opcionales para ampliar sus funcionalidades.

Tras instalar Prosody con pkg, es posible que veas un mensaje como este:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
Message from prosody-13.0.2:

--

If you're running Prosody in a jail and experience problems, please add

the following to the global section of your prosody.cfg.lua:

interfaces = { 'x.x.x.x' }

where 'x.x.x.x' is the public IP you wish Prosody to bind to.

Este aviso es importante: al ejecutar Prosody dentro de una jail de FreeBSD, el servidor podría no enlazar automáticamente a la IP pública correcta. Para evitar problemas de conexión, debemos añadir la línea indicada en la sección global de nuestro archivo /usr/local/etc/prosody/prosody.cfg.lua, reemplazando 'x.x.x.x' por la dirección IP pública de nuestro servidor.

Si no configuramos esto, los clientes o servidores externos podrían no poder conectarse a nuestro XMPP, incluso si los registros DNS y el firewall están correctamente definidos. Por eso conviene tenerlo en consideración desde el principio.

El archivo principal de configuración por donde deberíamos comenzar se encuentra en:

1
/usr/local/etc/prosody/prosody.cfg.lua

Este archivo es el punto de partida para definir el dominio de tu servidor, activar módulos, configurar la base de datos (en nuestro caso el almacenamiento interno), y establecer otros parámetros esenciales del servidor XMPP. Desde aquí podremos personalizar Prosody para que funcione exactamente como necesitamos.

Para simplificar y asegurar que tu servidor funcione correctamente, este tutorial incluye el contenido completo de prosody.cfg.lua como bloque de código. Contiene todo lo necesario para continuar con el tutorial e ir añadiendo las funcionas extras como el servidor de subida HTTP.

prosody.cfg.lua

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
VirtualHost "deustux.xyz"

admins = { "admin@deustux.xyz" }
plugin_paths = { "/usr/local/lib/prosody-modules/" }

s2s_secure_auth = true
certificates = "certs"

authentication = "internal_hashed" 
storage = "internal" -- Usamos almacenamiento default de prosody y no una base de datos externa
archive_expires_after = "1w" -- Borrar mensajes automaticamente tras 1 semana

-- MODULOS --
modules_enabled = {
		-- "conversejs";
	-- Generally required
		"disco"; -- Service discovery
		"roster"; -- Allow users to have a roster. Recommended ;)
		"saslauth"; -- Authentication for clients and servers. Recommended if you want to log in.
		"tls"; -- Add support for secure TLS on c2s/s2s connections

	-- Not essential, but recommended
		"blocklist"; -- Allow users to block communications with other users
		"bookmarks"; -- Synchronise the list of open rooms between clients
		"carbons"; -- Keep multiple online clients in sync
		"dialback"; -- Support for verifying remote servers using DNS
		"limits"; -- Enable bandwidth limiting for XMPP connections
		"pep"; -- Allow users to store public and private data in their account
		"private"; -- Legacy account storage mechanism (XEP-0049)
		"smacks"; -- Stream management and resumption (XEP-0198)
		"vcard4"; -- User profiles (stored in PEP)
		"vcard_legacy"; -- Conversion between legacy vCard and PEP Avatar, vcard

	-- Nice to have
		"account_activity"; -- Record time when an account was last used
		"cloud_notify"; -- Push notifications for mobile devices
		"csi_simple"; -- Simple but effective traffic optimizations for mobile devices
		"invites"; -- Create and manage invites
		"invites_adhoc"; -- Allow admins/users to create invitations via their client
		"invites_register"; -- Allows invited users to create accounts
		"ping"; -- Replies to XMPP pings with pongs
		--"register"; -- Allow users to register on this server using a client and change passwords
		"time"; -- Let others know the time here on this server
		"uptime"; -- Report how long server has been running
		"version"; -- Replies to server version requests
		"mam"; -- Store recent messages to allow multi-device synchronization
		--"turn_external"; -- Provide external STUN/TURN service for e.g. audio/video calls

	-- Admin interfaces
		"admin_adhoc"; -- Allows administration via an XMPP client that supports ad-hoc commands
		"admin_shell"; -- Allow secure administration via 'prosodyctl shell'

	-- HTTP modules
		--"bosh"; -- Enable BOSH clients, aka "Jabber over HTTP"
		--"http_openmetrics"; -- for exposing metrics to stats collectors
		--"websocket"; -- XMPP over WebSockets

	-- Other specific functionality
		--"announce"; -- Send announcement to all online users
		"groups"; -- Shared roster support
		"mimicking"; -- Prevent address spoofing
		--"motd"; -- Send a message to users when they log in
		--"proxy65"; -- Enables a file transfer proxy service which clients behind NAT can use
		--"s2s_bidi"; -- Bi-directional server-to-server (XEP-0288)
		--"server_contact_info"; -- Publish contact information for this service
		--"tombstones"; -- Prevent registration of deleted accounts
		--"welcome"; -- Welcome users who register accounts
		"reload_modules";
		"s2s_reload_newcomponent";
		
}

limits = {
	c2s = {
		rate = "10kb/s";
	};
	s2sin = {
		rate = "30kb/s";
	};
}


log = {
	info = "prosody.log"; -- Change 'info' to 'debug' for verbose logging
	error = "prosody.err";
--	"*syslog"; -- Uncomment this for logging to syslog
     "*console"; -- Log to the console, useful for debugging when running in the foreground
}


-- CONFIGURANDO SALA DE CHAT PÚBLICAS --
Component "muc.deustux.xyz" "muc" 
    modules_enabled = {
        "muc_auto_member";
	"muc_mam";
    }
    muc_log_by_default = false
    muc_log_precenses = false

    muc_log_cleanup_interval = 60 * 60
    restrict_room_creation = true
    component_admins_as_room_owners = true
    max_history_messages = 5
    muc_vcard = true
    muc_room_default_public = true
    muc_room_default_persistent = true
    muc_room_default_members_only = false
    muc_room_default_moderated = false
    muc_room_default_public_jids = false
    muc_room_default_change_subject = false
    muc_room_default_history_length = 5
    muc_room_default_language = "es"

Tras dejar el archivo de configuración como el que mostramos, necesitamos asegurar las conexiones TLS/SSL con un certificado válido. Prosody espera que los certificados estén dentro de la carpeta que definimos en certificates = "certs".

Si ya tienes un certificado emitido por Let’s Encrypt (o cualquier otra autoridad), normalmente los archivos estarán en algo como:


/usr/local/etc/letsencrypt/live/deustux.xyz/

y contienen los archivos .key (clave privada) y .crt (certificado público).

En lugar de copiar y renombrar manualmente estos archivos en la carpeta certs, Prosody ofrece una herramienta propia para importar los certificados de manera automática y eficiente:

1
2

prosodyctl --root cert import /usr/local/etc/letsencrypt/live/ deustux.xyz

Esto hace que Prosody lea los certificados y los coloque correctamente en su formato interno, listo para usarlos en las conexiones TLS de clientes y servidores XMPP. Así te aseguras de que todo el tráfico esté cifrado y que el servidor sea reconocido como seguro por los clientes.


Si queremos comprobar que la configuración es correcta antes de arrancar el servicio (o después de cualquier cambio en prosody.cfg.lua), Prosody incluye un comando muy útil:

1
prosodyctl check

Esto revisa la sintaxis y la coherencia de la configuración. Si hay errores, nos los indica para poder corregirlos antes de que el servicio falle al iniciar. Si no hay errores, se quedará callado y listo para funcionar.


Una vez configurado Prosody y los certificados, necesitamos asegurarnos de que el servicio se inicie automáticamente al arrancar la jail de FreeBSD, y también poder iniciarlo de inmediato. Para ello usamos service:

1
2
service prosody enable 
service prosody start 

serviceprosodystart.png

Con esto ya tenemos el servicio listo, seguro y bajo control. El siguiente paso es crear el primer usuario, que será el administrador definido en la configuración de Prosody (admin@deustux.xyz). Esto lo hacemos con:

1
prosodyctl adduser admin@deustux.xyz

Se te pedirá una contraseña dos veces, y si todo va bien, verás algo así:

1
OK: Created admin@deustux.xyz with role 'prosody:member'

Este usuario podrá gestionar todo el servidor: crear más cuentas, configurar salas de chat públicas, ajustar módulos, ver logs, etc.


Primer Login

Antes de ponernos a montar el HTTP External Upload para la subida de archivos, es buena idea verificar que nuestro servidor XMPP funciona correctamente. Para eso, haremos el primer login usando cualquier cliente XMPP de nuestra elección: puede ser Conversations en Android, Monal en iOS, Gajim o Dino en escritorio.

gajimlogin.gif

Hacer esta verificación antes de montar el HTTP External Upload nos asegura que cualquier problema posterior no sea por el servidor base, sino solo por la configuración del módulo de subida de archivos.

Una vez confirmada la conexión y que podemos enviar y recibir mensajes, podemos pasar al siguiente paso: configurar up.deustux.xyz para la subida y descarga de archivos vía HTTP.


HTTP External Upload en Prosody

El módulo http_upload_external de Prosody funciona de manera bastante simple: básicamente expone un endpoint HTTP donde los clientes pueden subir (POST) o descargar (GET) archivos, protegido con una secret key. Solo quien tenga la clave puede subir archivos, evitando que cualquiera llene tu servidor de basura o haga spam. Es decir, solo un GET y un POST con una clave, nada complicado ni mágico, muy fácil de auditar.

Para nuestro ejemplo, vamos a usar prosody-filer, escrito en Go. Usamos Go porque es ligero, rápido, trae su propio servidor HTTP y no depende de librerías externas ni de infiernos de dependencias como sucede con Python. Pero si deseas usar otro HTTP upload de la comunidad, los desarrolladores han hecho soluciones similares en Python+Flask, Perl, Rust o PHP, así que puedes usar lo que prefieras.

El servidor se encarga de validar la secret key, guardar los archivos y servirlos de vuelta, integrándose perfectamente con http_upload_external usando nuestro subdominio up.deustux.xyz.

No entraré en detalles sobre cómo instalarlo, ya que está bastante bien explicado en el repositorio de prosody-filer.

A continuación, dejo el archivo de configuración para el demonio en FreeBSD:

/usr/local/etc/rc.d/prosody_filer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/bin/sh
#
# PROVIDE: prosody_filer
# REQUIRE: LOGIN
# KEYWORD: shutdown

. /etc/rc.subr

name="prosody_filer"
rcvar=prosody_filer_enable
command="/home/prosody-filer/prosody-filer"
pidfile="/var/run/${name}.pid"
user="prosody-filer"

load_rc_config $name
: ${prosody_filer_enable:=no}

start_precmd="prosody_filer_precmd"
start_cmd="prosody_filer_start"
stop_cmd="prosody_filer_stop"

prosody_filer_precmd() {
    cd /home/prosody-filer || return 1
}

prosody_filer_start() {
    echo "Arrancando prosody-filer..."
    /usr/sbin/daemon -u $user -p $pidfile $command
}

prosody_filer_stop() {
    echo "Parando prosody-filer..."
    if [ -f $pidfile ]; then
        kill $(cat $pidfile)
        rm -f $pidfile
    fi
}

run_rc_command "$1"

Finalmente, tendrás que desplegar públicamente el servicio usando nginx, HAProxy o el proxy que prefieras, y configurar SSL/TLS para que las subidas y descargas sean seguras.

Solo quedaría añadir la configuración correspondiente en /usr/local/etc/prosody/prosody.cfg.lua para habilitar el HTTP External Upload con nuestro subdominio up.deustux.xyz:

1
2
3
4
Component "up.deustux.xyz" "http_upload_external"
   http_upload_external_base_url = "https://up.deustux.xyz/upload/"
   http_upload_external_secret = "contraseña"
   http_upload_external_file_size_limit = 500000000 -- 500 MB

Con esto, cualquier cliente que tenga la secret key podrá subir y descargar archivos de manera segura mediante HTTP, integrándose directamente con Prosody y manteniendo nuestro servicio limpio y controlado.

Después de añadirlo, recuerda reiniciar Prosody para que los cambios tengan efecto:

1
service prosody restart

Y listo: ahora el servidor está preparado tanto para mensajería como para subir archivos de forma controlada.

#freebsd #linux #xmpp #prosody #server