Настройка XMPP сервера Prosody. Как перестать пользоваться проприетарными мессенджерами

Материал из ВИКИЦМИТ
Версия от 10:04, 2 августа 2023; MihaYu (обсуждение | вклад)
(разн.) ← Предыдущая версия | Текущая версия (разн.) | Следующая версия → (разн.)
Перейти к навигации Перейти к поиску

Предисловие

Если вам вдруг захотелось перестать пользоваться проприетарными мессенджерами типа 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 клиент:

https://conversejs.org/

Статья распространяется под лицензией GNU FDL 1.3, полный текст лицензии доступен на https://www.gnu.org/licenses/fdl-1.3.html