После “Апдейтов и фиксов на домашнем сервере” решил, с одной стороны, альтернативно подойти к оставшейся со времен переезда на VPS копии ejabberd’а – а там у меня еще ejabberd 2.x и Debian 7, который я использовал для написания и отладки RSS-транспорта и других проектов (фактически, тут от сервера требовалось просто его наличие, чтобы к нему подключался транспорт. Ну и держать какой-то тестовый аккаунт, где со всем этим работать). С другой стороны, раз уж развивать эту тему, то иметь и тестовый сервер на базе Prosody, так как купленная с год назад виртуалка и домен mychat.name для написания руководства на JabberWorld уже закончились, а пощупать Prosody все же иногда полезно. А там может и Snikket под боком иметь…
Так вот. Развернуть очередную пару виртуалок несложно, ресурсов на обновленном сервере хватает под все. Но делать – так делать: захотелось нормально выпустить имеющиеся серверы в мир с доступом к ним снаружи и нормальным общением между собой. Одна незадача. Даже две: внешнего адреса дома у меня нет (а IPv6 все так же не предоставляется), а внешний адрес VPS’ки уже занят “боевым” сервером, обслуживающим JabberWorld и остальные домены.
И вот решил попробовать разрулить целиком все через SRV-записи. В том числе телефонию!
TL;DR: да, все удалось! Софт вполне корректно работает через SRV, в том числе есть связь с jabber.ru, где на данный момент работает ejabberd 3.x (а ему уже больше 10 лет!).
А дальше – поэтапная работа:
- Развернул новую виртуалку, поделал базовые настройки, слил ее копию, чтобы не делать работу несколько раз.
- В виртуалке добавил VPN-клиент, зафиксировал адрес клиента на сервере.
- Установил свежий ejabberd (24.10) и Prosody (0.14.2) на полученных виртуалках. С одной стороны использовал наработки боевого сервера для ejabberd, с другой – старался максимально сохранить дистрибутивный конфиг-файл. Для Prosody активно использовал упомянутое выше руководство.
- Сделал пару субдоменов на jabberworld.info.
- А дальше пошла основная работа вокруг SRV на эти субдомены: пара записей для клиент/сервер, еще пара для TLS-вариантов, по s2s-записи для каждого из 4 “дефолтных” сервисов у сервера (аплоад, прокси, pubsub и конференции) и 6 записей для STUN/TURN и их шифрованных вариантов – в общей сложности 14 записей. Для удобства у каждого сервера сделал сдвиг старшей цифры номера порта на одинаковое значение для всех сервисов: т.е., 5222 и 5223 стали, например, 6222 и 6223 для одного сервера и 7222/7223 для другого. В итоге вот лишь часть того, что получилось в админке:
- Дальше дело было за iptables и форвардами. На тест-сервере ejabberd’а, как и на боевом, сделал максимальное разделение портов между сервисами, поэтому и записей потребовалось больше. А уже при тестировании начали всплывать особенности: например, форма веб-регистрации выдавала ссылку на капчу на том же порту, что и работала сама (что логично) – в итоге при пробросе капча выходила нерабочей. Пришлось в конфиге сервера ставить тот же порт, который планировалось использовать “снаружи”. IPv6 пока не форвардил: в отличие от IPv4, со стороны VPN-сервера не было единого IPv6-адреса, на который удобно было бы делать SNAT. Да и в целом, NAT при наличии IPv6-адресов – как-то чересчур. Немного почитал про раздачу IPv6-адресов для VPN-клиентов, надо будет заняться, но боязно в чем-то ошибиться – пока оставил эту тему и тест-серверы на сейчас без IPv6. Итого – правило в FORWARD’e, правило в PREROUTING’e – DNAT: снаружи смотрим порт, описанный в SRV, внутри мапим его на нужный порт сервера. В POSTROUTING’e – SNAT.
После этого смог подключаться к серверам в мире. Подключение, правда, было своеобразным: внешние серверы обращались на VPS, пакеты форвардились через VPN и попадали на нужный сервер. Дальше сервер устанавливал ответное соединение, но default route у него (сейчас сделан) не через VPN и соединение устанавливается напрямую. В основном это работает. Плюс – меньшая задержка, меньше отвалов соединений при переподключении VPN’а. Минус – не ко всем серверам можно подключиться напрямую, к которым есть связь со стороны VPS’ки.
Отдельным моментом была настройка взаимодействия тест-серверов с “боевым”. Между собой тест-серверы взаимодействовали “естественным” образом: несмотря на то, что находились рядом и в одной сети, обращение шло на SRV-запись, шло через интернет, VPN и возвращалось на нужный хост. Обратное соединение в итоге шло тем же путем. А вот для “боевого” сервера надо было форвардить уже обращение на локальный порт. В итоге делается это так:
sysctl net.ipv4.conf.all.route_localnet=1 # ets / pts
"${ipt}" -A OUTPUT -t nat -p tcp --dport 6269 -m addrtype --dst-type LOCAL -j DNAT --to-destination 192.168.223.205:5269 # local to pts s2s
"${ipt}" -A OUTPUT -t nat -p tcp --dport 6270 -m addrtype --dst-type LOCAL -j DNAT --to-destination 192.168.223.205:5270 # local to pts ss2s
"${ipt}" -A OUTPUT -t nat -p tcp --dport 7269 -m addrtype --dst-type LOCAL -j DNAT --to-destination 192.168.223.206:5269 # local to ets s2s
"${ipt}" -A OUTPUT -t nat -p tcp --dport 7270 -m addrtype --dst-type LOCAL -j DNAT --to-destination 192.168.223.206:5270 # local to ets ss2s
После этого связь заработала во все стороны. Не особо быстро, но заработала.
Одним из интересных и объемных моментов стало корректное проксирование всего, что связано с вебом: получение сертификатов напрямую на тест-серверах с оглядкой на то, что домен смотрит на VPS, а также наладка работы HTTP Upload.
В целом, хотелось сделать систему, которую (хотя бы теоретически) можно скопировать на условный “боевой” сервер и минимально при этом править конфиги, поэтому все делалось с оглядкой на работающий вариант – со стороны тест-сервера, как и в случае с “боевым” вариантом, используется Apache2. На веб-сервере заведены домен и все его субдомены-сервисы, сделаны DocumentRoot’ы и работает certbot, которому были при создании сертификатов указаны нужные домены и каталоги. На VPS у Apache сделано простейшее проксирование для HTTP-запросов для тех же доменов на Apache на нужном тест-сервере. В итоге получили работающую систему обновления сертификатов на сервере. Далее они копируются для jabber-серверов: самописным скриптом для ejabberd и через prosodyctl –root cert import для Prosody. Да, кстати: попутно нашелся способ подхватывать обновленные сертификаты в Просоди: ставится и включается модуль reload_modules, позволяющий перезапускать модуль tls отдельно от сервера.
С HTTP Upload все немного сложнее.
Для ejabberd указываем в конфиге put_url: https://@HOST@:7280/upload
– с этого порта делается форвард в iptables, но listener настроен как и в боевом варианте – на 5280 (хотя может не стоило?). Для get_url
и сохранения “красивых” URL’ов аплоада (напомню, клиенты зачастую гораздо больше любят делать превью на обычных HTTPS-ссылках, чем на нестандартных портах) используется все тот же upload.jabberworld.info с “боевого” сервера. Т.е., клиент отправляет файл на https://@HOST@:7280/upload и попадает на аплоад-сервис jabber-сервера, а получает в ответ ссылку на другой сервер. В свою очередь, для распределения функций (и снова: для сохранения структуры сервисов “как на боевом”) на тест-сервере отдачей файлов занимается Апач, а не встроенный HTTP-сервер ejabberd’а. Для этого в DocumentRoot’е для upload.ets.jabberworld.info сделана ссылка (имя не особо принципиально) на /opt/ejabberd/upload. А дальше занимаемся проксированием на Apache VPS: в конфиге сервисных доменов для jabberworld.info добавляем
RequestHeader set Host "upload.ets.jabberworld.info"
ProxyPass /ets https://192.168.223.206/u
вот это “u” – это и есть название той ссылки, упомянутой выше, которая фигурирует, фактически, только в этом редиректе. А первая строка, фактически, говорит второму серверу, куда именно идет запрос, так как указать домен в запросе напрямую нельзя (он смотрит на внешний адрес VPS).
И тут появился еще один подводный камень: для отдачи файлов оба сервера используют HTTPS (да, можно было после боевого Апача внутри VPN использовать обычный HTTP, но смотри выше: сохраняем общие принципы), а тут разные домены, разные сертификаты и так далее. Решилось все такими методами:
SSLProxyEngine on
ProxyPreserveHost On
SSLProxyVerify none
SSLProxyCheckPeerCN off
А со стороны веб-сервера на тестовой машине upload.jabberworld.info был добавлен в качестве ServerAlias’a для upload.ets.jabberworld.info – не знаю, насколько это красиво и правильно, но работает.
Для Prosody пришлось отказаться от разгрузки сервера через Апач: для модуля http_file_share, фактически, нет каталога, где лежат непосредственно раздаваемые файлы – в каталоге /var/lib/prosody/SERVICE/http_file_share/
лежат файлы с расширением *.bin (хоть и с нужным контентом), которые транслируются в оригинальные по сопоставлению в базе. В итоге остается только или проксировать запросы через внешний Апач напрямую на HTTP Upload порт в Prosody, или (для сохранения общей схемы) проксировать на персональный Апач тест-сервера, а тот уже пусть заворачивает все на Prosody. Сделал по второму пути. На внешнем сервере, фактически, добавилась пара строчек – очередной set host и ProxyPass на нужный адрес через VPN. А вот подобный описанному выше конфигу теперь пришлось развернуть и на внутреннем веб-сервере – для upload.pts.jabberworld.info описываем такое:
SSLProxyEngine on
ProxyPreserveHost On
RequestHeader set Host "upload.pts.jabberworld.info"
ProxyPass /u https://192.168.220.205:5281/
ProxyPassReverse /u https://192.168.220.205:5281/
После этого аплоад будет успешно работать.
Да, для STUN/TURN-сервисов настройка обычная, лишь надо указать для работы внешний адрес VPS’ки. Проверил – звонки ходят (ну, как минимум, в моем сетапе).
По факту остается только корректно вывести наружу сервис прокси, но на пока он не сильно актуален. Думаю, тут все же придется сразу указывать нужный порт в конфиге сервиса, чтобы маппинг в iptables был “1 к 1”. В общем, надо пробовать, как вообще proxy отнесется к тому, что он работает не на внешнем адресе.