WhatsApp в России депутаты обещают заблокировать уже в очень скором времени. Доверие к Telegram у многих довольно сильно было подорвано после публикации расследования одного издания об особенностях их протокола вкупе с подробностями о том, кто владеет их сетевой инфраструктурой и с кем он связан (администрация Хабра попросила меня не прикладывать ссылку, т.к. издание признано "нежелательной организацией" в РФ), да и недавнее появление Telegram в реестре РКН тоже оптимизма в их отношении не добавляет. Max - оставим для сумасшедших и безвыходных, учитывая, кто и зачем его создал. Signal - отличный мессенджер и всем хорош, но в России его тоже периодически пытаются заблокировать.
На фоне всего этого многие начали задумываться о поднятии своего сервера для обмена сообщениями. С самодельными серверами и "не-попсовыми" протоколами всегда встает проблема "а с кем там общаться?", потому что перетащить прям вот вообще всех собеседников и контрагентов на что-то им непривычное практически нереально. Но если речь идет только, например, об инструменте общения внутри семьи, небольшой группы единомышленников или внутри одной компании, то это может быть вполне неплохим вариантом.
В наше время как self-hosted альтернативу популярным мессенджерам часто упоминают Matrix, например, с клиентом Element. На Хабре есть подробные инструкции, например вот эта: https://habr.com/ru/articles/837904/. Я попробовал, и мне не понравилось. Клиенты тормозные, через нестабильный интернет-канал все работает просто отвратительно, а сам сервер просто неповоротливый и укладывает не слишком богатый на процессор и память VPS даже всего с парой клиентов.
И тут мне вспомнилось про XMPP, он же Jabber. Он родом еще из тех времен, когда люди пользовались процессорами на 200-300 мегагерц и подключались к интернету через dial-up модемы - то есть он изначально очень нетребовательный к ресурсам. Между тем, развитие его не замерло на месте, а на сегодняшний день он умеет почти все то что требуется от современного мессенджера: хранение истории, передача файлов, аудио-видео звонки, end-to-end шифрование, и другое.
Я буду настраивать XMPP-сервер Prosody. Система у меня на сервере Ubuntu 22.04
Подключаем официальные deb-репозитории от проекта Prosody. Сам prosody есть в обычных репах Debian и Ubuntu, но там старые версии, а я советую использовать версию сервера не ниже 0.12, а в идеале версию 13.x, потому что в более старых версиях не хватает некоторых полезных фич, и некоторые модули не включены в поставку и их нужно устанавливать отдельно. Поэтому подключаем репы от разработчиков, чтобы иметь самые свежие версии:
wget https://prosody.im/downloads/repos/$(lsb_release -sc)/prosody.sources -O/etc/apt/sources.list.d/prosody.sources
apt update
apt install prosody
У меня установилась версия 13.0.2. Она требует довольно свежего интерпретатора Lua (Prosody написан на Lua), и если при запуске сервиса оно ругается на интерпретатор, нужно доустановить и выбрать правильный:
update-alternatives --config lua-interpreter
# в появившемся списке выбираем версию 5.4
Далее нам нужен домен для работы сервера, XMPP работает через TLS со всеми вытекающими. В принципе, можно использовать и бесплатный домен с какого-нибудь dynu.com, freedns.afraid.org, или даже sslip.io, но тут все упирается в доверие к сервису - кто владеет доменом, тот имеет доступ ко всему (если только вы не сделаете certificate pinning). Параноики могут и без доменов использовать самосгенеренные сертификаты, вручную добавляя их в список доверенных - в prosody генерация самоподписанных сертификатов делается очень легко командой prosodyctl cert generate habr.com
(либо используйте прям IP-адрес сервера вместо домена).
Окей, допустим мы используем домен habr.com. Нам нужно будет направить на IP-адрес вашего сервера сам habr.com, и еще сделать поддомен типа upload.habr.com (чуть позже расскажу зачем), который тоже будет указывать на IP сервера.
Далее делаем получение сертификатов через LetsEncrypt для вашего домена (если оно у вас уже есть, можете пропустить):
apt install certbot
certbot certonly --standalone -d habr.com -d upload.habr.com
Оно получит от LetsEncrypt сертификаты и настроит их автоматическое обновление.
Теперь настало время отредактировать конфиг сервера, он располагается обычно в /etc/prosody/prosody.cfg.lua
.
В самом начале там идет список модулей, активированных на сервере. Я приведу то что в итоге получилось у меня, а комментарием -- ! отмечу те, что были отключены в конфиге по умолчанию и которые я включил специально:
modules_enabled = {
"disco";
"roster";
"saslauth";
"tls";
"blocklist";
"bookmarks";
"carbons";
"dialback";
"limits";
"pep";
"private";
"smacks";
"vcard4";
"vcard_legacy";
"account_activity";
"cloud_notify";
"csi_simple";
"invites";
"invites_adhoc";
"invites_register";
"ping";
"register";
"time";
"uptime";
"version";
"cloud_notify_extensions"; -- ! добавил
"turn_external"; -- ! добавил
"mam"; -- ! добавил
"csi_simple"; -- добавил
-- "http_file_share"; -- ! вот этот используется, но закомментирован, чуть позже расскажу почему
"admin_adhoc";
"admin_shell";
}
Модуль mod_cloud_notify_extensions
не входит в стандартную поставку, поэтому его надо будет доустановить отдельно:
apt install liblua5.4-dev
prosodyctl install --server=https://modules.prosody.im/rocks/ mod_cloud_notify_extensions
Также Prosody позволяет выбрать, как будут храниться данные пользователей (аккаунты, сообщения, и т.д.). По умолчанию используется хранилище на простых файлах. Можно выбрать чтобы использовалась база SQLite, это будет более эффективно. Для серверов с большим количеством пользователей и сообщений можно использовать MySQL и PostgreSQL.
Дальше скроллим ниже до раздела с VirtualHost
. По умолчанию там прописан localhost, заменяем его на наш основной домен:
VirtualHost "habr.com"
Сохраняем конфиг, запускаем
prosodyctl --root cert import /etc/letsencrypt/live
Prosody автоматически найдет сертификаты для доменов и скопирует их к себе для использования. Чтобы они обновлялись автоматически, можно добавить хук, создав файл типа
/etc/letsencrypt/renewal-hooks/deploy/prosody.sh
с содержимым
#!/bin/sh
/usr/bin/prosodyctl --root cert import /etc/letsencrypt/live
и сделать его исполняемым: chmod +x /etc/letsencrypt/renewal-hooks/deploy/prosody.sh
В принципе, все почти готово. Мы настроили сервер со всеми необходимыми модулями, сертификатами, и прочим. И даже E2E-шифрование (OMEMO) будет работать из коробки, если оно поддерживается клиентами.
Но есть еще пара нюансов.
Первое - это передача файлов. Сам по себе XMPP предусматривает передачу файлов только peer to peer без участия сервера. Это требует чтобы оба клиента в момент передачи находились онлайн, да и в наши времена повсеместного NAT'а практически не работает.
Есть решение - использовать http_file_share модуль. Тогда при отправке файла через чат, клиент зальет его на сервер по HTTP, а собеседники получат ссылку на загруженный файл. URL представялет из себя огромный UUID, так что перебором собрать файлы на сервере не получится.
Добавим в конфиг следующий текст прямо под описанием вашего VirtualHost:
VirtualHost "habr.com"
disco_items = {
{ "upload.habr.com", "file sharing service" },
}
Component "upload.habr.com" "http_file_share"
http_file_share_expires_after = 31 * 24 * 60 * 60 -- сколько должны храниться файлы на сервере, в моем примере 31 день
http_file_share_global_quota = 1024*1024*1024*10 -- ограничение объема хранилища на сервере, в моем случае 10 гигабайт
Поскольку вы тут явно объявили "component", не надо перечислять "http_file_share" в списке модулей в начале конфига (у меня он там закомментирован), иначе сервер ругается.
Если по каким-то причинам вам не нравится идея с HTTP-ссылками, есть еще модуль proxy_65
(https://prosody.im/doc/modules/mod_proxy65), который позволяет передавать файлы через сервер (используя его как прокси чтобы обойти проблему прямых подключений через NAT), но не сохраняя их на сервере.
Второе - это аудио/видео звонки. В принципе, того, что мы имеем в конфиге, уже достаточно для них. Для установления соединений между клиентами для аудио-видеозвноков в условиях невозможности прямых подключений из-за NAT'а клиенты будут использовать публичные STUN/TURN сервера.
Однако если вы параноик, или хочется ни от кого не зависеть, можно поднять свой TURN-сервер:
apt install coturn
Далее редактируем /etc/turnserver.conf
:
realm=habr.com
use-auth-secret
static-auth-secret=verysecretsecret
Перезапускаем coturn: systemctl restart coturn
и добавлем в конфиг Prosody выше описания вашего VirtualHost следущие строки:
turn_external_host = "habr.com"
turn_external_port = 3478
turn_external_secret = "verysecretsecret"
Естественно, coturn вы можете разместить на отдельном сервере, например сделав для него домен turn.habr.com
Вот теперь все готово.
Можно запустить проверку конфига командой prosodyctl check
- утилита проверит, что все настроено правильно и даст советы, если что-то можно улучшить.
Не забываем после правки конфига перезапустить сервер: systemctl restart prosody
и можно подключаться.
Как создавать новые аккаунты на сервер? В конфиге можно разрешить регистрацию для всех желающих через клиенты (с этим аккуратнее), а можно добавлять кого надо вручную:
prosodyctl adduser user@habr.com
А теперь про клиенты.
С мобильными клиентами все довольно неплохо.
Для Android лучшим из них считается Conversations. В Google Play он стоит пару долларов, но можно бесплатно установить его из F-Droid.
Из альтернатив мне еще понравился Blabber.im
Видеозвонки работают и там и там.
На iOS традиционно хорошими клиентами считаются Siskin IM и его форк Snikket (я честно говоря, разницы не заметил). Видеозвонки работают.
Еще иногда упоминают клиент ChatSecure, с ним осторожнее - он кажется в полумертвом состоянии, по крайней мере домен, который там используется для push-уведомлений уже не существует.
Под дестктоп же... Ну, там такое. Есть много старых "классических" клиентов типа Gajim, Pidjin, Psi, но они имеют интерфейс из 90-х и часто не поддерживают современные фичи.
Если у вас нет аллергии на Electron, советую ConverseJS - стильный и удобный интерфейс, умеет все что надо (кроме аудиозвонков), может запускаться как Electron-приложение, а можно поставить его на свой сервер и подключаться из браузера.
Из клиентов, в которых заявлена поддержка аудиовидеозвонков - Movim (тоже веб), и кто-то хвалил Dino (Linux, но есть неофициальная сборка под Windows), и BeagleIM под MacOS. Kaidan под Linux выглядит очень похоже на Телегу, но видеозвонки, кажется, не умеет.
И еще есть проприетарный AstraChat, который, как заявлено, умеет все, но скачать просто так с сайта разработчика его нельзя (требуется регистрация на корп. емайл), на гитхабе кто-то выкладывает бинарники, но это уже на ваш страх и риск.
И в заключение вопрос - а насколько все это дело устойчиво к блокировкам, если РКН решит как-то вычислить и заблокировать именно ваш сервер по какой-то причине?
XMPP по умолчанию работает по стандартному порту 5222. Можно поставить на 443 порт что-то типа sslh
, за которым еще будет стоять безобидный веб-сервер, и коннектиться клиентами на порт 443 как будто это обычный HTTPS.
Веб-сервер для файлов у Prosody висит тоже на нестандартном порту и отдает страничку prosody при запросе с урлом /. Можно спрятать его за веб-сервером типа Nginx или Caddy, чтобы по / они отдавали свою страницу, и при 404 ошибке - тоже (ну и само собой слушали на 443 порту, в http_file_share модуле есть параметр, который сообщает пользователям куда надо стучаться).
Как еще более эффективное решение, существуют расширения XMPP для работы через чистый HTTP (модуль bosh
) и вебсокеты (модуль websocket
), что в теории позволяет полностью замаскироваться под обычный веб-сервер и даже работать через CDN. Но клиентов, умеющих подобное, мне пока не встретилось, если кто-то знает - напишите в комментариях.
Комментарии (41)
dreams_killer
26.07.2025 10:21Jabber живее всех живых , а вот с клиентами так себе - большинство не умеет otr ( кроме как раз той классики )
Uporoty Автор
26.07.2025 10:21А чем OTR лучше OMEMO?
OMEMO умели все современные клиенты из тех что я пробовал.
dreams_killer
26.07.2025 10:21Насколько я помню/знаю они очень похожи ( otr и omemo) не возьмусь сказать лучше или хуже. Имею в контакт листе людей общающихся исключительно с otr , по этому проблема поиска клиента с его поддержкой знакома.
mrDoctorWho
26.07.2025 10:21OMEMO является эталоном на текущий момент, он лучше OTR большей стабильностью, возможностью отправки сообщений в оффлайн и поддержкой множества устройств одновременно
dreams_killer
26.07.2025 10:21Что вы имеете ввиду под большей стабильностью?
mrDoctorWho
26.07.2025 10:21Нет проблем с совместимостью, обновлением ключей и внезапной потерей сессии. Дело конечно в реализации, но насколько я помню, она всегда хромала.
0x00FA7A55
26.07.2025 10:21Зачем prosody-то? Буквально сейчас поднял себе сервак на ejabberd. Кластеризация из коробки, он на elixir, понятный yml в настройках, интеграция с let's encrypt, сразу умеет в stun/turn да и вообще всё что надо. Есть apt и rpm репы. Развивается активно компанией, которая им реально зарабатывает.
mrDoctorWho
26.07.2025 10:21Такой же вопрос — а зачем ejabberd, если на сервере будет полтора анонимуса? Ejabberd это про высокие нагрузки (Whatsapp, eve online), а prosody — про сервер для друзей и родных.
ash_lm
26.07.2025 10:21Ну как минимум он сложнее в настройке и нужно осваивать erlang. А если у вас на сервере десяток человек то зачем городить сложности?
andreymal
26.07.2025 10:21нужно осваивать erlang
Зачем? У меня личный сервер на ejabberd уже лет пятнадцать, из настроек всего один yaml-файлик, erlang до сих пор не знаю
mrDoctorWho
26.07.2025 10:21Не понимаю где вы в Gajim увидели устаревший интерфейс. Давно уже выглядит как один из самых современных мессенджеров
Uporoty Автор
26.07.2025 10:21Я тестил версию 2.2, она прям вообще олдскульная. Сейчас проверил 2.3, там обновили интерфейс, стало поприличнее, но уж точно не "как один из самых современных" :) Думаю, это уже вопрос вкуса и личных предпочтений
mrDoctorWho
26.07.2025 10:21Это вы похоже не видели олдскульные клиенты — Gajim 0.6, Tkabber, QIP. Так когда-то выглядели все XMPP клиенты.
Uporoty Автор
26.07.2025 10:21Почему же, видел и хорошо их помню. Речь даже не про компоновку окна (олдскульные часто делали отдельное окно под ростер, и отдельное под чаты, а то и под каждый чат), а в целом про то как выглядит приложение - шрифты (и антиалиасинг), иконки, и т.д. Времена-то не стоят на месте.
ash_lm
26.07.2025 10:21А почему был выбор именно в пользу Prosody, а не тот же Snikket, который сразу в докере? Или Openfire, который вообще буквально в пару кликов устанавливается, насколько я помню, к тому же он с самым вменяемым web интерфейсом из всех?
dartraiden
26.07.2025 10:21Openfire
Придётся втаскивать Java, да и сам по себе Openfire местами весьма творчески интерпретрует спецификациии. По крайней мере, когда к нам в багтрекер приходят с очередным "что-то не работает", чаще всего оказывается, что с ejabberd оно работает, с Prosody работает, а вот Openfire имеет своё особое мнение.
Johan_Palych
26.07.2025 10:21Using Prosody with Docker
https://prosody.im/doc/dockerTestman2023
26.07.2025 10:21Есть(An Overview of XMPP) и что выбрать по клиентам и серверам
Понравилась лаба(офис или организация):
https://github.com/spanishairman/ejabberd-postgresql-debian
ash_lm
26.07.2025 10:21Просто Snikket это уже настроенный, готовый к использованию дочерний проект этих ребят. Сейчас уже не помню, но если мне не изменяет память там даже конфиг править не надо (есть примитивная админка на web).
P.S. Да и гайд какой-то поверхностный. На вскидку: ничего не сказано, что оф. репозиторий использует устаревший алгоритм (dsa1024), а сейчас многие Linux-дистрибутивы больше не доверяют DSA-ключам. Не раскрыта админка (а штука важная), не раскрыто создание комнат (не менее важно). Модуль bosch почему-то не освещён. Да и про то, что такое "prosodyctl" не мешало бы рассказать.
aax
26.07.2025 10:21Signal - отличный мессенджер и всем хорош.
Особенно он хорош деаноном при создании аккаунта и централизованной архитектурой.
Да и не нужно про встроенное сквозное шифрование. Без одноразового шифроблокнота передаваемого независимым от шифруемого канала способом это всего лишь маркетинг. Как и в Телеграмм к примеру.
tsilia
26.07.2025 10:21Как раз на неделе интересовался вопросом. Спасибо за статью, утащил в закладки!
По поводу сертификатов: не безопаснее ли сгенерить ключ своего собственного certificate authority (CA), которым затем подписывать сертификат сервера, выданный хоть на внутренний домен, хоть на dyndns-домен, хоть на IP
, хоть на домен habr.com, как в вашей статье? Если не пользоваться LE или другими публичными CA, то всё равно нужно будет либо какой-то сертификат добавлять в хранилище, либо пинить в самом клиенте или в системе. Имхо, лучше пусть это будет не самоподписанный серт (вдруг забудете запинить его — и привет MITM), а заверенный вашим CA, приватный ключ от которого есть только у вас — никто другой не сможет подписать серт вашего сервера вашим CA. А если запинить сам CA, а другие запретить нафиг, то это ещё секьюрнее, но тут нужна поддержка со стороны клиентского приложения.Uporoty Автор
26.07.2025 10:21Я выше писал что это тоже вариант, да. Но тогда это потребует ручного добавления вашего корневого серта на все устройства всех ваших пользователей.
Девайсы на Android в таком случае (когда какой-то левый CA добавлен в доверенные), например, начинают всякие страшные сообщения юзеру показывать.
olku
26.07.2025 10:21Можно ли связать несколько серверов вместе как relay? Например, чтобы поднять mesh на OpenWRT и не выходить в Интернет вовсе?
lv333
Делать альтернативу и упирается вот в это:
Немного неосмотрительно мягко говоря, а если доступ к домену будет по какой то причине утерян? Если нарушится связность с некоторыми сегментами интернет? Не будет доступа к ДНС и/или к серверу сертификации? Если уж желаете неубиваемую болталку, то она должна быть способна работать хоть в локальной сети на два устройства + сервер, а в идеале вообще без сервера в режиме точка-точка + меш из многих точек, но это уже разумеется уровень железа и каналов затрагивает уже. А пока это песочная "крепость" на пляже. Но это разумеется мое имхо...
Uporoty Автор
Параноики могут и без доменов использовать самосгенеренные сертификаты, вручную добавляя их в список доверенных.
lv333
Наверное это стоило написать, а ещё лучше описать настройку прямо в статье?
Uporoty Автор
добавил
lv333
И кстати зачем этим всем заниматься если вы не
параноикреалист? Всегда же есть "прекрасная альтернатива" этим вашим враждебным сервисам! ;)Uporoty Автор
Не понял вопроса, перефразируйте пожалуйста
haga777
МаКсимально пафосный троллинг просто
dartraiden
А ориентировочно в конце этого года можно будет у LE получать валидные сертификаты для IP-адресов.
lv333
Это не решает вопроса с доступностью самого LE в определенный момент с определенного сегмента сети.
kenomimi
Не параноики.
Во-первых, выставлять что-то без крайней необходимости в интернет на публичные адреса в наше время весьма попрочная практика. Уязвимостей в таком комплексном софте настолько много, что взлом - дело времени. И хорошо, если что-то лайтовое зальют - там ведь могут начать цопе распространять, или пропаганду запрещ енки вести - а отбрехиваться от товарища майора вам потом.
Во-вторых, сервисы "для себя и компании" часто сидят на приватном TLD типа ".lan" внутри локалки, куда доступ через ipsec (или другой впн). Это наиболее безопасное и взломостойкое решение... Там как ни крути, но серты самому делать, поскольку на приватный TLD получить нормальный серт нереально...
Uporoty Автор
Когда поднял сервер для пары друзей, требовать подключаться к нему исключительно через постоянно поднятый VPN - затея довольно сомнительная и всетаки ближе к паранойе.
А если сервер только внутри локалки, это никак не мешает использовать LE. В LE есть челенджи, с которыми для подтверждения владения доменом не нужно иметь связность снаружи, а например достаточно добавить определенную TXT NS-запись, и после этого можно генерить сертификаты даже для доменов которые указывают на чисто локальные адреса.
lv333
VPN может быть достаточно лёгким и простым как по настройке, так и для конечного пользователя, например ssh туннель. В одном скрипте запустить туннель и клиент следом. Просто и без затей так говорится и достаточно надёжно в плане перехвата траффика. Все крутится внутри сервера, наружу только один порт и один сервис - красота же!
lv333
Правда тогда ssl для сервера вроде как и не нужен уже, шифровать внутри зашифрованного туннеля несколько излишне...
Uporoty Автор
На мобильнике, ага
lv333
И? Что именно вас смущает? На Андроиде к примеру с этим проблем точно нет, на яблоках возможно... Даже скорее всего! Но тут как бы я не помощник:)
Uporoty Автор
На андроиде это не получится одной командой. Нужно ставить отдельную аппку, настраивать роутинг (чтобы на впн шло только то что надо), а бонусом оно будет еще дополнительно батарею поджирать
lv333
Ну почему же? На самом деле можно, но пользоваться этим будет не особо удобно... В 16-м Андроиде обещали завезти нативно запуск Линукс приложений, ну а для более ранних версий - termux.