Предисловие
Если вам вдруг захотелось перестать пользоваться проприетарными мессенджерами типа Telegram, или просто просто посмотреть как это работает, то можете воспользоваться данной инструкцией.
По гайду можно настроить собственный сервер XMPP Prosody на Ubuntu 20.04, с веб-версией и закрытой регистрацией, аудио и видео вызовами.
Пароли, где они потребуются, ОБЯЗАТЕЛЬНО нужно записывать себе, чтобы их не забывать, лучше использовать менеджер паролей Keepass, а чтобы проще генерировать их, можно установить pwgen и запускать его командой:
pwgen -1 64
В интернете есть множество гайдов по настройке Prosody, но так как некоторые сайты постепенно или резко умирают - лишним не будет.
После настройки можно проверить свой сервер на https://compliance.conversations.im - результат должен быть 100%, то есть данная конфигурация сервера полностью соответствует современным видениям необходимых XEPов для работы с XMPP.
Железячная сторона вопроса - сервер кушает в районе 30-70мб ОЗУ на 30-100 пользоваталей, то есть для семьи и друзей вам хватит даже самой дешевой VPS или можете держать хост дома, если есть белый IP. Несмотря на высказывания про древность XMPP как технологии и перерерасход ресурсов, трафика это всё потребляет мало, работает стабильно даже в 2G сети, что в общем скорее хорошо, чем плохо.
Если у вас что-то не получилось, или нужны какие-нибудь пояснения - пишите в комментариях, обязательно отвечу.
Настройка домена у регистратора
Для начала нам нужно прописать DNS записи для домена у вашего регистратора домена
4 А-записи:
conference
proxy
pubsub
upload
2 SRV записи:
_xmpp-client._tcp.example.com. example.com. 5 0 5222
_xmpp-server._tcp.example.com. example.com. 5 0 5269
2 TXT записи:
_xmppconnect "_xmpp-client-websocket=wss://example.com/xmpp-websocket"
_xmppconnect "_xmpp-client-xbosh=https://example.com/http-bind"
NGINX+модули
Следом добавим репозиторий Prosody в систему, чтобы всегда иметь свежую версию серверной части:
определяем дистрибутив и добавляем репозиторий Prosody
echo deb http://packages.prosody.im/debian $(lsb_release -sc) main | sudo tee /etc/apt/sources.list.d/prosody.list
sudo wget https://prosody.im/files/prosody-debian-packages.key -O/etc/apt/trusted.gpg.d/prosody.gpg
sudo apt update
и всё, теперь Prosody будет устанавливаться из репозитория разработчиков.
Установка NGINX и модуль загрузки файлов:
sudo apt install nginx libnginx-mod-http-perl
Создадим технические домены и заполним:
mkdir /var/www/tech
chown -R www-data:www-data /var/www/tech
sudo nano /etc/nginx/sites-enabled/example.com
---здесь и далее, после nano вставляем нижеидущий код
server {
server_name example.com;
location / {
root /var/www/tech;
#proxy_pass http://localhost:80;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off;
# proxy_protocol: on;
tcp_nodelay on;
}
}
location /http-bind {
proxy_pass http://localhost:5280/http-bind;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off;
tcp_nodelay on;
}
location /xmpp-websocket {
proxy_pass http://localhost:5280/xmpp-websocket;
proxy_http_version 1.1;
proxy_set_header Connection "Upgrade";
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_read_timeout 900s;
}
location /register_web {
proxy_pass http://localhost:5280/register_web;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off;
tcp_nodelay on;
auth_basic "Private area";
auth_basic_user_file /var/www/protect/.htpasswd;
}
location /web {
proxy_pass http://localhost:5280/conversejs;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_buffering off;
tcp_nodelay on;
}
}
Технические домены:
upload
sudo nano /etc/nginx/sites-enabled/upload.example.com
server {
listen 80;
server_name upload.example.com;
root /upload;
location / {
perl upload::handle;
}
}
pubsub
sudo nano /etc/nginx/sites-enabled/pubsub.example.com
server {
listen 80;
server_name pubsub.example.com;
root /var/www/tech;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
proxy
sudo nano /etc/nginx/sites-enabled/proxy.example.com
server {
listen 80;
server_name proxy.example.com;
root /var/www/tech;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
conference
sudo nano /etc/nginx/sites-enabled/conference.example.com
server {
listen 80;
server_name conference.example.com;
root /var/www/tech;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
Создаем пароль для закрытой регистрации пользователей:
perl -le 'print crypt("пароль_для_регистрации", "любые_символы_для_хэширования")'
Далее записываем сгенерированный пароль и вписываем его в /var/www/protect/.htpasswd в формате login:password
mkdir /var/www/protect
sudo nano /var/www/protect/.htpasswd
login:password
Подключаем модуль upload для NGINX:
mkdir /upload
chown -R www-data:www-data /upload/
mkdir -p /usr/local/lib/perl
wget -O /usr/local/lib/perl/upload.pm https://git.io/fNZgL
Добавим модуль в конфиг:
sudo nano /etc/nginx/nginx.conf
perl_modules /usr/local/lib/perl;
perl_require upload.pm;
client_max_body_size 4096m;
Впишем пароль в конфиг perl:
sudo nano /usr/local/lib/perl/upload.pm
CTRL+W пишем external_secret ENTER и вписываем пароль
$external_secret = 'ПАРОЛЬ'
Перезапускаем NGINX и проверяем его работу:
sudo systemctl restart nginx.service
sudo systemctl status nginx.service
Если стартанул без ошибок жмем CTRL+C и едем дальше
Сертификаты Let's Encrypt+БД
UPDATE: на сегодняшний день сертбот поставляется через snap, версия на питоне считается устаревшей, т.е вам нужно установить snap и certbot, далее получить сертификаты на 5 доменов, которые ниже по инструкции отсюда https://certbot.eff.org/instructions?ws=nginx&os=ubuntufocal
sudo apt install python3-certbot-nginx
certbot --nginx --rsa-key-size 4096 -d example.com
certbot --nginx --rsa-key-size 4096 -d upload.example.com
certbot --nginx --rsa-key-size 4096 -d conference.example.com
certbot --nginx --rsa-key-size 4096 -d proxy.example.com
certbot --nginx --rsa-key-size 4096 -d pubsub.example.com
После этого можно зайти на домены и посмотреть, работают ли сертификаты
Далее устанавливаем базу данных и редактируем конфиг:
sudo apt install postgresql postgresql-contrib
sudo nano /etc/postgresql/14/main/postgresql.conf
и там вписываем listen_addresses = '127.0.0.1'
(внимание, версия Postgesql может быть иная, от этого зависит расположение конфига в цифре, вместо 14 может быть например 10 или 16)
Перезапускаем БД:
sudo systemctl restart postgresql.service
Создаем пользователя БД:
su - postgres
createuser --pwprompt prosodyuser
Создаем саму БД:
psql
и вставляем это
CREATE DATABASE prosodyuser
OWNER prosodyuser;
Выходим из БД \q
Установка Prosody
sudo apt install prosody lua-event lua-dbi-postgresql
Устанавливаем модули:
(в версии 12 модули вроде как ставятся по умолчанию, но я не разбирался в таких тонкостях)
cd /opt
sudo apt install mercurial
hg clone https://hg.prosody.im/prosody-modules/ prosody-modules
chown -R prosody:prosody /opt/prosody-modules
Создадим директорию для PID файла:
mkdir /var/run/prosody
chown -R prosody:prosody /var/run/prosody
Создаем ключ Диффи-Хелмана:
cd /etc/prosody/certs/
openssl dhparam -out dh-2048.pem 2048
chown prosody:prosody dh-2048.pem
chmod u=rw,go= dh-2048.pem
Установим пакет для импорта сертификатов Prosody:
sudo apt install lua-sec
Теперь переходим к настройке конфига самого Prosody:
sudo nano /etc/prosody/prosody.cfg.lua
И туда вставляем следующий конфиг:
pidfile = "/var/run/prosody/prosody.pid";
---администраторы сервера---
admins = { "user@example.com" }
---Отключаем регистрацию через клиенты---
allow_registration = false
---Хранить всё в БД---
default_storage = "sql"
sql = {
driver = "PostgreSQL";
database = "prosodyuser";
host = "127.0.0.1";
port = 5432;
username = "prosodyuser";
password = "ПАРОЛЬ_ОТ_ПОЛЬЗОВАТЕЛЯ_БД";
}
sql_manage_tables = true
---Сертификаты---
certificates = "/etc/prosody/certs"
---http
http_host = "127.0.0.1"
http_ports = { 5280 }
https_ports = { }
http_interfaces = { "127.0.0.1" }
trusted_proxies = { "127.0.0.1" }
---Методы шифрования---
ssl = {
--key = "/etc/prosody/certs/example.com.key";
--certificate = "/etc/prosody/certs/example.com.crt";
options = { "no_sslv3", "no_sslv2", "no_ticket", "no_compression", "cipher_server_preference", "single_dh_use", "single_ecdh_use" };
ciphers="EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA384:EECDH+ECDSA+SHA256:EECDH+aRSA+SHA384:EECDH+aRSA+SHA256:EECDH+aRSA+RC4:EECDH:EDH+aRSA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS:!RC4:AES256-GCM-SHA384";
protocol = "tlsv1_1+";
dhparam = "/etc/prosody/certs/dh-2048.pem";
}
---Обязательное шифрование Клиент сервер и Сервер и сервер
c2s_require_encryption = true;
s2s_require_encryption = true;
s2s_secure_auth = true;
---Модули---
plugin_paths = { "/opt/prosody-modules/" }
---Глобальные модули---
modules_enabled = {
-- Wichtige Module
"roster";
"saslauth";
"tls";
"dialback";
"disco";
-- Empfohlene Module
"private";
"profile";
"offline";
"admin_adhoc";
"admin_telnet";
--"http_files";
"legacyauth";
"version";
"uptime";
"time";
"ping";
"register";
"posix";
"bosh";
"announce";
-- "proxy65";
"pep";
"smacks";
"carbons";
"blocklist";
"csi";
"csi_battery_saver";
"mam";
"lastlog";
"list_inactive";
"cloud_notify";
"compat_dialback";
"throttle_presence";
"log_auth";
"server_contact_info";
"websocket";
"bookmarks";
"privacy_lists";
--"pubsub";
"filter_chatstates";
"vcard_legacy";
"pinger";
-- "turncredentials";
"http_upload_external";
"register_web";
"http_altconnect";
"conversejs";
"turn_external";
};
---Выключаем логи---
log = {
--debug = "/var/log/prosody/debug.log";
--info = "/var/log/prosody/info.log";
--warn = "/var/log/prosody/warn.log";
--error = "/var/log/prosody/error.log";
}
---Настройка архива сообщений, можно выставить в днях, или отключить вовсе---
default_archive_policy = true;
archive_expires_after = "1d";
---EXTERNAL HTTP UPLOAD---
http_upload_external_base_url = "https://upload.example.com/"
http_upload_external_secret = "ПАРОЛЬ_ОТ_UPLOAD"
http_upload_external_file_size_limit = 536870912 --4Gb
---шаблон для веб регистрации---
register_web_template = "/etc/prosody/register-templates/Prosody-Web-Registration-Theme"
---Websocket---
consider_websocket_secure = true;
--cross_domain_websocket = true;
---настройки веб клиента---
conversejs_options = {
debug = false;
view_mode = "fullscreen";
}
conversejs_tags = {
-- Load libsignal-protocol.js for OMEMO support (GPLv3; be aware of licence implications)
[[<script src="https://cdn.conversejs.org/3rdparty/libsignal-protocol.min.js"></script>]];
}
---cross_domain_bosh = true;
consider_bosh_secure = true;
---TURN STUN для звонков---
turn_external_host = "example.com"
turn_external_port = 3478
turn_external_secret = "ПАРОЛЬ"
contact_info = {
abuse = { "mailto:user@example.com", "xmpp:user@example.com" };
admin = { "mailto:user@example.com", "xmpp:user@example.com" };
feedback = { "mailto:user@example.com", "xmpp:user@example.com" };
sales = { "mailto:user@example.com", "xmpp:user@example.com" };
security = { "mailto:user@example.com", "xmpp:user@example.com" };
support = { "mailto:user@example.com", "xmpp:user@example.com" };
};
---domain---
c2s_direct_tls_ports = { 5223 }
c2s_direct_tls_ssl = {
certificate = "/etc/prosody/certs/example.com.crt";
key = "/etc/prosody/certs/example.com.key";
}
VirtualHost "example.com"
http_host = "example.com"
http_external_url = "https://example.com/"
authentication = "internal_hashed"
Component "conference.example.com" "muc"
name = "example.com chatrooms"
restrict_room_creation = "local"
muc_room_default_public = false
muc_room_default_members_only = true
muc_room_default_language = "ru"
max_history_messages = 500
modules_enabled = {
"muc_mam",
"vcard_muc",
"muc_cloud_notify";
}
muc_log_by_default = true
disco_items = {
{ "conference.example.com", "example.com MUC" };
}
Component "pubsub.example.com" "pubsub"
Component "proxy.example.com" "proxy65"
proxy65_acl = { "example.com" }
После изменения конфига перезапускаем Prosody:
sudo systemctl restart prosody.service
sudo systemctl status prosody.service
Импортируем сертификаты, которые создали с помощью Let's Encrypt:
sudo prosodyctl --root cert import /etc/letsencrypt/live
Создаем веб интерфейс для регистрации:
mkdir /etc/prosody/register-templates/
cd /etc/prosody/register-templates
git clone https://gitlab.com/mimi89999/Prosody-Web-Registration-Theme.git
Настройка звонков
Установка Coturn для звонков через Conversation и Dino
sudo apt install coturn
Далее правим конфиг:
sudo nano /etc/turnserver.conf
use-auth-secret
static-auth-secret=ПАРОЛЬ_ДЛЯ_КОТЮРНА
realm=example.com
# VoIP traffic is all UDP. There is no reason to let users connect to arbitrary TCP endpoints via the relay.
no-tcp-relay
# don't let the relay ever try to connect to private IP address ranges within your network (if any)
# given the turn server is likely behind your firewall, remember to include any privileged public IPs too.
denied-peer-ip=10.0.0.0-10.255.255.255
denied-peer-ip=192.168.0.0-192.168.255.255
denied-peer-ip=172.16.0.0-172.31.255.255
# special case the turn server itself so that client->TURN->TURN->client flows work
allowed-peer-ip=10.0.0.1
# consider whether you want to limit the quota of relayed streams per user (or total) to avoid risk of DoS.
user-quota=12 # 4 streams per video call, so 12 streams = 3 simultaneous relayed calls per user.
total-quota=1200
И еще один:
sudo nano /etc/default/coturn
расскоментируйте строчку enable 1
и
sudo systemctl enable --now coturn
sudo systemctl restart coturn
sudo systemctl status coturn
Импорт сертификатов с помощью Cron:
sudo crontab -e
0 5 * * 1 /usr/bin/certbot renew --renew-hook "prosodyctl --root cert import /etc/letsencrypt/live" --quiet
Включаем файрволл:
sudo ufw allow 3478
sudo ufw allow 5222
sudo ufw allow 5000
sudo ufw allow 5269
sudo ufw allow ssh
sudo ufw allow 443
sudo ufw allow 80
sudo ufw enable
Удаление файлов пользователей
Так как автоочистки файлов нет, можно удалять их через Cron в зависимости от времени:
sudo nano /etc/cron.daily/deletefiles
Вставляем:
#!/bin/sh
find /upload/ -type f -mtime +30 -exec rm -v {} \;
После этого скрипт будет проверять даты файлов и удалять все что старше 30 дней
Делаем файл исполняемым:
chmod +x deletefiles
Регистрация пользователей происходит на странице https://example.com/register_web, если вы предварительно выслали им логин и пароль для захода
Веб клиент Converse.js находится тут https://example.com/web
Клиенты
Клиенты для смартфонов:
Conversations https://conversations.im/ Android
Blabber https://blabber.im/en.html Android
Monal https://monal.im/ iOS
Siskin https://siskin.im/ iOS
Клиенты для ПК:
Gajim https://gajim.org/ GNU/Linux и Windows
DINO https://dino.im/ GNU/Linux
Web клиент:
Статья распространяется под лицензией GNU FDL 1.3, полный текст лицензии доступен на https://www.gnu.org/licenses/fdl-1.3.html
Комментарии
17:11
20:06
10:25
17:49
18:11
18:16
18:17
18:28
21:03
08:18
09:36
12:21
16:54
...
:(
17:17
17:47
17:22
04:59
07:48
08:09
10:29
2) Не надо скрещивать в гибрид классические "в холодильнике мышь повесилась" с "за компанию и жид удавился".
3) С остальными тезисами полностью согласен.
:)
12:04
12:07
12:28
14:14
nginx: [emerg] unexpected end of file, expecting "}" in /etc/nginx/sites-enabled/testtest.ru:54
nginx: configuration file /etc/nginx/nginx.conf test failed
14:27
http {
##
# Basic Settings
##
perl_modules /usr/local/lib/perl;
perl_require upload.pm;
client_max_body_size 4096m;
19:18
07:38
05:41
02:37
17:22
19:56
17:21
15:24
20:51
10:39
02:22
Спасибо.
15:48
09:50
Модуль lua-dbi-sqlite3 установлен, в конфиге раскоментировал строку с сиквеллайтом, указал storage = sql, ничего не получается.
15:44
11:29
Couldn't write pidfile at /run/prosody/prosody.pid; /run/prosody/prosody.pid: No such file or directory
Error in SQL transaction: commit failed
База на sqlite, автоматом создается.
13:53
15:10
15:39
18:25
У самих разработчиков Prosody поддерживается дистрибутив на 11 Дебиане, но в Астре можно раскатить через репозиторий Дебиана 10 (на вики описано, я так и ставил Prosody).
Сейчас запустил с внутренней базой (не SQlite3) все работает, самоподписанные сертификаты подтянулись. Не понятно как общий список контактов (ростер) для всех сделать. Добавлял файл sharedgroups.txt как в мануале, прописывал модуль "groups" и строчку где брать текст с группами groups-file = "/etc/prosody/sharedgroups.txt" - не видят пользователи друг друга. В ежабере прямо в веб-админке можно ткнуть группу @all@, а как в Просодии прописать, чтобы она видела, не получается пока.
Спасибо за статью, я периодически к ней возвращаюсь чтобы почерпнуть разные части конфига, приходится листать разные сайты. Пока нужен конечно локальный чат, внутренний для предприятия, внутри сети.
16:36
А у вас работают голосовые звонки? Проверил Ejabberd и Prosody и ни в какую не могу заставить их обрабатывать звук.
11:51
23:59
Feb 28 20:23:32 prosody systemd[1]: Starting A high performance web server and a reverse proxy server...
Feb 28 20:23:32 prosody nginx[10047]: nginx: [emerg] "location" directive is not allowed here in /etc/nginx/sites-enabled/examle.com:14
Feb 28 20:23:32 prosody nginx[10047]: nginx: configuration file /etc/nginx/nginx.conf test failed
Feb 28 20:23:32 prosody systemd[1]: nginx.service: Control process exited, code=exited, status=1/FAILURE
Feb 28 20:23:32 prosody systemd[1]: nginx.service: Failed with result 'exit-code'.
Feb 28 20:23:32 prosody systemd[1]: Failed to start A high performance web server and a reverse proxy server.
Чего ему надо? Спасибо за помощь!
19:33
server {
server_name домен;
location / {
т.е там отступы)
UPD: парсер скушал форматирование в комментарии, в статье не скушал вроде - посмотрите внимательно на форматирование)
21:12
21:18
Если через TOR его можно отправить через torsocks/torify то научить понимать onion я его не смог.