Hace unos días me recomendaron Snikket como una opción sencilla para montar un servidor XMPP1, y me lancé por el terraplén de cabeza. A mitad del descenso, me encontré un montón de problemas interesantísimos que resolver, que iré desgranando paso a paso en los próximos artículos.
En éste os voy a contar cuáles son esos problemas, por qué surgen, por qué los quiero resolver y cómo los he resuelto, pero desde un punto de vista de diseño por el momento. No vas a encontrar instrucciones de terminal para resolver todo esto, sino el contexto necesario para saber qué estoy intentando resolver; las instrucciones detalladas vendrán en los siguientes artículos.
Hasta ahora, todos mis servicios alojados bajo mi impresora eran servicios Web, es decir, basados en comunicaciones a través de los puertos 80 y 443 (HTTP y HTTPs). Estos puertos eran suficientes para comunicar todos mis servicios con mis dispositivos o con mi navegador, o con otros servidores en el caso de mi instancia de Mastodon. Para poder atender a tantos servicios tras los mismos puertos, uso NGINX como proxy inverso:
“Barcas” es el nombre de mi servidor.
A diferencia de mis otros servicios, XMPP usa más puertos TCP y UDP que el 80 y el 443: 5000, 5222, 5269,… En el caso de Snikket como, supongo, toda otra serie de alternativas, los puertos 80 y 443 también se usan para proporcionar un panel de control Web y poder administrar usuarios y salas de chat.
Sobre el papel, la configuración para instalar Snikket sería la siguiente:
- Configurar los puertos 80 y 443 en NGINX para poder usar el panel de control de usuarios y conversaciones de Snikket.
- Configurar acceso directo a todo el resto de los puertos de Snikket: 5222, 5269,… ésta es la lista completa (en inglés). Como no son puertos compartidos entre varios servicios, no hace falta configurarlos en un proxy inverso.
- Configurar las DNS de mi servicio de XMPP en mi proveedor de dominios, que es Cloudflare.
Esta configuración, que a priori tendría buena pinta, se resume en esta figura:
Esta configuración, aunque parece que tiene sentido, no funciona. Cloudflare sólo ofrece funciones de proxy para los puertos 80 y 443 en su cuenta gratuita, por lo que el tráfico del resto de puertos de Snikket es descartado.
Sin embargo, esto tiene un problema que no es evidente, y la configuración de arriba no funciona sin más. Las características de seguridad de Cloudflare que están disponibles para las cuentas gratuitas en forma de “el proxy de Cloudflare” sólo soportan los puertos 80 y 443. Con el proxy de Cloudflare activado, todo el tráfico que no es web (80 y 443) se descartaba, por lo que ninguno de los puertos que entran en juego en las conversaciones de XMPP llegaba a mi servidor.
Desactivando el proxy de Cloudflare para la configuración de los subdominios de Snikket todo funciona, pero queda así:
Esta configuración, aunque funciona, supone un riesgo. Al desactivar la función de proxy, la dirección IP de mi casa (por donde se entra a “barcas”) queda expuesta a todo internet. Un ataque de denegación de servicio distribuido que afecte a mi proveedor de servicios de acceso a internet puede dejar sin internet a toda la casa, cosa que no nos gusta.
Desactivar el proxy de Cloudflare no es ideal, porque expone la IP del servidor al resto de internet. Mi servidor está en casa, por lo que un ataque de denegación de servicio que, por puro azar, incluyese la dirección IP que mi operador de acceso a internet me asigna, tiraría por tierra toda mi red doméstica. Eso nos impediría trabajar o estudiar desde casa y, probablemente, me traería problemas con mi proveedor de servicio.
Una alternativa a esto es contratar un servidor barato en cualquier proveedor de alojamiento en la nube (un VPS) y mover toda mi configuración de NGINX a él, conectando este servidor en la nube con el servidor de mi casa mediante una VPN (la cuenta gratuita de Tailscale funciona muy bien y es más que suficiente).
- El proveedor de alojamiento en la nube protegería mi servidor porque la IP expuesta sería la suya, no la de mi casa, y este tipo de empresas protegen su infraestructura ante ataques, por lo menos a un nivel de red. Tras los puertos XMPP no hay contenido, sino un servicio de mensajería que además cifra el tráfico, así que no hay problema por perder la capa de seguridad y anti-bots que proporciona Cloudflare para estos puertos.
- Conectar el VPS a mi servidor a través de una VPN es perfecto para este caso, porque oculta la dirección IP de mi red doméstica ahorrándome configurarla en el panel de control de DNS, y también el tener que abrir puertos en mi router. Además, para todo el tráfico que iría entre la VPS y mi servidor, se aplicaría una capa de cifrado que lo protegería en caso de que, de por sí, no estuviese ya cifrado.
Esta configuración funciona y resuelve el problema de la configuración anterior, pero requiere encontrar una solución para redirigir el tráfico de todos los puertos diferentes a 80 y 443 a “barcas”.
¿Por qué mover sólo la configuración de NGINX y no todos los servicios? Por una cuestión de recursos y precio: para ejecutar NGINX y una serie de reglas de cortafuegos, los requisitos que necesitamos son mínimos. Con un servidor que tenga 1 GB de RAM y con una CPU es más que suficiente, y eso cuesta entre 3 y 6€ al mes. Si muevo todo2 necesitaría entre 8 y 16 GB de RAM, mucho más almacenamiento potencia de CPU, una solución de copias de seguridad,… Con todo ello me estaría moviendo en un rango de unos 40€, o más, al mes. Teniendo un servidor en casa donde ejecutar los servicios, moverlo todo a la VPS acarrea un coste innecesario en mi caso.
Así pues, parece que contratar una VPS sencilla para tener NGINX configurado allí, y conectarla al servidor de casa mediante Tailscale, resolvería mis problemas a un coste muy bajo (3 a 6€ al mes).
La única complicación adicional de este método es que tenemos que tener algún mecanismo para redirigir el tráfico de los puertos de XMPP (varios puertos como el 5222, 5269,… en TCP y UDP) desde el VPS hacia nuestro servidor (en casa o donde fuere). Al final lo he resuelto configurando el VPS para que haga IP forwarding y luego he configurado una serie de reglas DNAT3 en su cortafuegos.
En próximos artículos veremos más en detalle la configuración de todos los elementos.
-
Extensible Messaging and Presence Protocol – Protocolo Extensible de Mensajería y Presencia. XMPP es un protocolo que comunica comunidades de usuarios a través de sus servidores, creando conversaciones entre pares de usuarios, o salas para conversaciones en grupo. Google Talks fue el ejemplo más popular de aplicación de XMPP. Una ventaja de XMPP es que es un protocolo federado, es decir: aunque yo me conecte a un servidor donde sólo esté yo, puedo establecer contacto con cualquier otro usuario de cualquier otro servicio que utilice XMPP en el planeta. Los nombres de usuario en XMPP tienen el mismo formato que un correo electrónico, y los servidores se comunican entre ellos cuando sus usuarios lo necesitan. ↩︎
-
Aunque en este artículo hablo casi exclusivamente de Snikket, en mi servidor de casa tengo muchos otros servicios: Mastodon, Castopod, algún que otro blog, Linkwarden, FreshRSS, Actual Budget, Forgejo y Nextcloud. ↩︎
-
Destination NAT. Traducción de direcciones de destino de red. ↩︎