现代即时通讯方案 Matrix 部署笔记

本文记录在 Debian Bookworm 上,Matrix(matrix-synapse) 部署时的注意点。Matrix 是个用于安全、去中心化通讯的开放网络。element.io 编写维护的 matrix-synapse,是一种开源的 Matrix homeserver 的实现。结合 Jitsi Meet,一种可作为单独 app 或嵌入咱们的 web 应用的安全、简单和可伸缩视频会议系统,就能建立起功能完整的及时通信方案。

matrix-synapse 部署

需要 Nginx,对 matrix-synapse 进行反向代理,和 element-web web app 的提供;pyenv 提供 Python 3.8.19matrix-synapse 所需);PostgreSQL 提供数据库。

部署完整文档在 Synapse 文档仓库。下面记录需要注意的地方。matrix-synapse 的配置文件为 homeserver.yaml,缩进为 4 个空格,纯 tab 缩进会报错。

TURN 服务器、PostgreSQL 和 matrix-synapse-ldap3

Synapse 需要 TURN 服务器,可参考上面的文档配置,也可以使用 Jitsi 视频会议系统配置的 TURN 服务器。三者的配置如下。

turn_uris: [ "turn:matrix.xfoss.com?transport=udp" ]
turn_shared_secret: "some_pre-shared_key"
turn_user_lifetime: 86400000
turn_allow_guests: true

database:
  name: psycopg2
  args:
    user: "synapse"
    password: "some_secret"
    dbname: "synapse_db"
    host: "localhost"
    cp_min: 5
    cp_max: 10

modules:
 - module: "ldap_auth_provider.LdapAuthProviderModule"
   config:
     enabled: true
     uri: "ldap://10.11.2.12:389"
     # start_tls: true
     base: "dc=xfoss,dc=com"
     attributes:
        uid: "sAMAccountName"
        mail: "mail"
        name: "cn"
     bind_dn: "cn=admin,cn=Users,dc=xfoss,dc=com"
     bind_password: "some_secret"

配置好后,matrix-synapsesource .venv/bin/activate 后的 Python virtual-environment 下,提供了 synctl 命令用于其启动、停止和重启。

完整 homeserver.yaml

# Configuration file for Synapse.
#
# This is a YAML file: see [1] for a quick introduction. Note in particular
# that *indentation is important*: all the elements of a list or dictionary
# should have the same indentation.
#
# [1] https://docs.ansible.com/ansible/latest/reference_appendices/YAMLSyntax.html
#
# For more information on how to configure Synapse, including a complete accounting of
# each option, go to docs/usage/configuration/config_documentation.md or
# https://element-hq.github.io/synapse/latest/usage/configuration/config_documentation.html
server_name: "matrix.xfoss.com"
public_baseurl: "https://matrix.xfoss.com:443"
pid_file: /home/it/synapse/homeserver.pid
listeners:
  - port: 8008
    tls: false
    type: http
    x_forwarded: true
    bind_addresses: ['::1', '127.0.0.1']
    resources:
      - names: [client, federation]
        compress: false
log_config: "/home/it/synapse/matrix.xfoss.com.log.config"



event_cache_size: 15K
caches:
  global_factor: 1.0
  per_cache_factors:
    get_users_who_share_room_with_user: 2.0
  sync_response_cache_duration: 2m
  cache_autotunning:
    max_cache_memory_usage: 1024M
	target_cache_memory_usage: 758M
	min_cache_ttl: 5m

rc_message:
  per_second: 0.5
  burst_count: 15

media_store_path: /home/it/synapse/media_store
max_upload_size: "128M"
max_image_pixels: "32M"

thumbnail_size:
- width: 32
  height: 32
  method: crop
- width: 96
  height: 96
  method: crop
- width: 320
  height: 240
  method: scale
- width: 640
  height: 480
  method: scale
- width: 800
  height: 600
  method: scale

url_preview_enabled: False
max_spider_size: "10M"


registration_shared_secret: "h&b0Cd=YuCG76OXp,#&~5lYzOx2+usB;#sMHWWK:es;b531Jzh"
report_stats: true
macaroon_secret_key: "aOiVs2e~Wuw,Cg=CJ=y^6E.#wcM-AqKRr.cATr2kQg_Xewe9~C"
form_secret: "LWhmPF7Cq6OW1UecL#2tdZ=1&HiHdom1fbN25H6E_XBR1Fv:5i"
signing_key_path: "/home/it/synapse/matrix.xfoss.com.signing.key"
trusted_key_servers:
  - server_name: "matrix.org"
suppress_key_server_warning: true

turn_uris: [ "turn:matrix.xfoss.com?transport=udp" ]
turn_shared_secret: "5IyELkZXryIlK1td"
turn_user_lifetime: 86400000
turn_allow_guests: true

database:
  name: psycopg2
  args:
    user: "synapse"
    password: "some_secret"
    dbname: "synapse_db"
    host: "localhost"
    cp_min: 5
    cp_max: 10

modules:
 - module: "ldap_auth_provider.LdapAuthProviderModule"
   config:
     enabled: true
     uri: "ldap://10.11.2.12:389"
     # start_tls: true
     base: "dc=xfoss,dc=com"
     attributes:
        uid: "sAMAccountName"
        mail: "mail"
        name: "cn"
     bind_dn: "cn=admin,cn=Users,dc=xfoss,dc=com"
     bind_password: "some_secret"

# vim:ft=yaml

一直同步的问题

若对 homeserver.yamlpublic_baseurl 项目进行了不当配置,那么在用户登陆时将出现一直同步(“Syncing forever...”)问题。报出“If you've joined lots of rooms, this might take a while.” 提示。

解决办法:不配置 public_baseurl,或将其配置为正确的内容,比如 https://matrix.xfoss.com:443

M_LIMIT_EXCEEDED 而无法登录

有用户反馈,在 element-web 网页客户端上登录时,出现 There was a problem communicating with homeserver, please try again later. 原因是服务器返回了 M_LIMIT_EXCEEDED

解决办法:往 homeserver.yaml 中增加如下参数:


...

log_config: "/home/synapse/config/logging.yaml"


rc_messages_per_second: 200000
rc_message_burst_count: 100000

...

检查 homeserver.yaml

it@matrix:~/synapse$ source .venv/bin/activate
(.venv) it@matrix:~/synapse$ python -m synapse.config read your_key -c homeserver.yaml

其中 your_key 可以是任意字符串。

参考

element-web

element-web 是个使用了 Matrix React SDK 的 Matrix web 客户端。本质上是使用现代 ES6 并用到 Node.js 构建系统的模块化 webapp。

通过 Nginx 向用户发布(配置文件见下一小节)。其配置文件为以下两个(相同)。

  • config.json

  • config.matrix.xfoss.com.json

{
    "default_server_config": {
        "m.homeserver": {
            "base_url": "https://matrix.xfoss.com",
            "server_name": "xfoss.com"
        }
    },
    "disable_custom_urls": true,
    "disable_guests": true,
    "disable_login_language_selector": false,
    "disable_3pid_login": true,
    "brand": "Element",
    "integrations_ui_url": "https://scalar.vector.im/",
    "integrations_rest_url": "https://scalar.vector.im/api",
    "integrations_widgets_urls": [
        "https://scalar.vector.im/_matrix/integrations/v1",
        "https://scalar.vector.im/api",
        "https://scalar-staging.vector.im/_matrix/integrations/v1",
        "https://scalar-staging.vector.im/api",
        "https://scalar-staging.riot.im/scalar/api"
    ],
    "default_country_code": "CN",
    "show_labs_settings": false,
    "features": {},
    "default_federate": false,
    "default_theme": "light",
    "room_directory": {
        "servers": ["matrix.org"]
    },
    "enable_presence_by_hs_url": {
        "https://matrix.org": false,
        "https://matrix-client.matrix.org": false
    },
	"settingDefaults": {
		"language": "zh_Hans"
	},
    "setting_defaults": {
        "breadcrumbs": true
    },
    "jitsi": {
        "preferred_domain": "meet.xfoss.com"
    },
    "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}

Nginx 配置文件

Nginx 配置文件主要包含对 matrix-synapse 的反向代理、element-web 程序文件提供,以及根域名(xfoss.com)WWW .well-known 提供配置,如下所示。

xfoss-com.conf

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    server_name xfoss.com;

    location /.well-known/matrix/server {
	    return 200 '{"m.server": "matrix.xfoss.com:443"}';
	    default_type application/json;
	    add_header Access-Control-Allow-Origin *;
    }

    location /.well-known/matrix/client {
	    return 200 '{"m.homeserver": {"base_url": "https://matrix.xfoss.com"}}';
	    default_type application/json;
	    add_header Access-Control-Allow-Origin *;
    }

    ssl_certificate /etc/ssl/certs/xfoss.com/_.xfoss.com.pem;
    ssl_certificate_key /etc/ssl/certs/xfoss.com/_.xfoss.com.privatekey.pem;
}

matrix.conf

server {
    listen 443 ssl;
    listen [::]:443 ssl;

    # For the federation port
    listen 8448 ssl default_server;
    listen [::]:8448 ssl default_server;

    server_name matrix.xfoss.com;

    location ~* ^(\/_matrix|\/_synapse\/client|\/_synapse\/admin) {
        # note: do not add a path (even a single /) after the port in `proxy_pass`,
        # otherwise nginx will canonicalise the URI and cause signature verification
        # errors.
        proxy_pass http://localhost:8008;
        proxy_set_header X-Forwarded-For $remote_addr;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header Host $host;

        # Nginx by default only allows file uploads up to 1M in size
        # Increase client_max_body_size to match max_upload_size defined in homeserver.yaml
        client_max_body_size 50M;

        # Synapse responses may be chunked, which is an HTTP/1.1 feature.
        proxy_http_version 1.1;
    }

    location /web {
	    alias /home/it/element-v1.11.76;
    }

    ssl_certificate /etc/ssl/certs/xfoss.com/_.xfoss.com.pem;
    ssl_certificate_key /etc/ssl/certs/xfoss.com/_.xfoss.com.privatekey.pem;
}

可以看出,matrix-synapseelement-web 均运行或存在于普通用户 it 下,因此需要将 it 账号加入 www-data 组。

参考

Jitsi 部署

Jitsi Meet 是给到用户使用和部署具有最先进视频质量和功能,的视频会议平台的一套开源项目。配置较为复杂,因此选择 Docker 方式,jitsi/docker-jitsi-meet, 部署是较简单的方式。

docker-compose 与国内镜像

Debian Bookworm 上运行 sudo apt install -y docker-compose,即可安装上 Docker Compose。但由于 hub.docker.com 已被屏蔽,因此要使用国内的镜像仓库。修改 /etc/docker/daemon.json,加入国内镜像仓库地址:

{
    "registry-mirrors": [
        "https://docker.jobcher.com"
    ]
}

docker-compose 用到的 .env 配置

# 在克隆 https://github.com/jitsi/docker-jitsi-meet 代码仓库后,通过 `cp env.example .env` 得到这个 `.env` 文件。
#
# 指定将 Jitsi Meet 配置文件,保存在当前用户主目录下的 `.jitsi-meet-cfg` 隐藏目录下。
CONFIG=~/.jitsi-meet-cfg
# 指定 HTTP/HTTPS 端口
HTTP_PORT=9080
HTTPS_PORT=443
TZ=Asia/Shanghai
# 若 PUBLIC_URL 与上面的 HTTPS 不匹配,Jitsi Meet 将无法正常工作,因为其用到的 WebRTC,使用了 `wss://` (WebSocket Secure)协议。导致在开会时会议室中只能有一个人,第二个人进入时会连接会断开。
PUBLIC_URL=https://meet.xfoss.com
# 经测试在内网下,若不指定 JVB_ADVERTISE_IPS,会导致出现超过 3 人会议中没有声音的问题。
JVB_ADVERTISE_IPS=10.11.2.32
ENABLE_GUESTS=1
AUTH_TYPE=internal
ENABLE_XMPP_WEBSOCKET=1
ENABLE_HTTP_REDIRECT=1
# 这些配置项在运行 `bash gen-password.sh` 将获得随机密码。
JICOFO_AUTH_PASSWORD=
JVB_AUTH_PASSWORD=
JIGASI_XMPP_PASSWORD=
JIGASI_TRANSCRIBER_PASSWORD=
JIBRI_RECORDER_PASSWORD=
JIBRI_XMPP_PASSWORD=
# 指定后运行 `docker-compose up -d` 将拉取 stable 镜像。
JITSI_IMAGE_VERSION=stable

使用自己的 SSL 证书

为消除浏览器证书告警,需要对 Jitsi Meet 使用自己的 SSL 证书。操作方式简单粗暴,如下所示。

sudo cp ~/PEM/_.xfoss.com.crt ~/.jitsi-meet-cfg/web/keys/cert.crt
sudo cp ~/PEM/_.xfoss.com.key ~/.jitsi-meet-cfg/web/keys/cert.key

随后打开 Jitsi Meet 网站 https://meet.xfoss.com,不再显示证书告警。

docker-jitsi-meetdocker-compose.yaml 中自带了基于 Nginx 的 web 镜像/容器,因此不必再使用 Nginx 对其进行反向代理。

参考

Element-desktop 客户端加载定制配置

由于 Element Desktop 主要就是 Element Web,不过是打包为了桌面应用程序,该 config.json 与 ESS 为咱们配置和部署的 https://<element_web_fqdn>/config.json 中的 config.json 相同,因此建议直接使用该文件设置 Element Desktop。

由此可见,咱们可以直接将 Element web 客户端的 config.json 用作 Element-desktop 的配置文件。在 Windows 上,Element Desktop 会加载 %APPDATA%\$NAME\config.json 处的该文件。为此,编写如下 Powershell 脚本,简化该配置文件的建立。

$config = '{
    "default_server_config": {
        "m.homeserver": {
            "base_url": "https://matrix.xfoss.com",
            "server_name": "matrix.xfoss.com"
        }
    },
    "disable_custom_urls": true,
    "disable_guests": true,
    "disable_login_language_selector": false,
    "disable_3pid_login": true,
    "brand": "XFOSS-Intranet-IM",
    "integrations_ui_url": "https://scalar.vector.im/",
    "integrations_rest_url": "https://scalar.vector.im/api",
    "integrations_widgets_urls": [
        "https://scalar.vector.im/_matrix/integrations/v1",
        "https://scalar.vector.im/api",
        "https://scalar-staging.vector.im/_matrix/integrations/v1",
        "https://scalar-staging.vector.im/api",
        "https://scalar-staging.riot.im/scalar/api"
    ],
    "default_country_code": "CN",
    "show_labs_settings": false,
    "features": {},
    "default_federate": false,
    "default_theme": "light",
    "room_directory": {
        "servers": ["matrix.org"]
    },
    "enable_presence_by_hs_url": {
        "https://matrix.org": false,
        "https://matrix-client.matrix.org": false
    },
	"settingDefaults": {
		"language": "zh_Hans"
	},
    "setting_defaults": {
        "breadcrumbs": true
    },
    "jitsi": {
        "preferred_domain": "meet.xfoss.com"
    },
    "map_style_url": "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"
}'

$element_dir = "$($env:APPDATA)\Element"

Write-Output "`n  --- Import Element configuration file to make it easy to use. --- `n"

Write-Output "Config to import:`n`n$($config)`n`n"
Write-Output "To: $($element_dir)`n"

Write-Host -NoNewLine 'Press any key to continue...';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');

if (Test-Path $element_dir) {
  # 这里是往 config.json 写入正确 JSON 配置的语句,否则 Element 不能加载该配置而无法生效。
  # 原因在于 Unix/Dos 文件编码的问题。
  (Write-Output "$($config)") -replace "r`n","`n" | Set-Content "$($element_dir)\config.json" -NoNewline
}
else {
	Write-Output "`n`nCaution: The `"$($element_dir)`" does not exist. You should install it first."
}

for ($i = 1; $i -le 100; $i++ ) {
    Write-Progress -Activity "Generating the configuration..." -Status "$i% Complete:" -PercentComplete $i
    Start-Sleep -Milliseconds 50
}

Write-Host "`nPress Any Key To Exit..."
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

(Get-Host).SetShouldExit(0)

安装与配置说明

这个 Element 的 Matrix 客户端,是 webapp 封装的本地应用,无法在 system-wide 级别安装,只能每用户安装。步骤如下。

  • 运行 Element Setup.exe 安装。安装后该客户端会自动运行;

  • 从桌面右下角的 “任务栏的系统托盘区”,右击绿色的 “Element” 图标选择退出该程序;

  • create_element_config.ps1 Powershell 脚本程序上点击鼠标右键,选择 “使用 Powershell 运行”,以 创建适应服务器 matrix.xfoss.com 的客户端配置文件。

然后双击桌面的 Element 程序图标,此时将以新创建的客户端配置文件运行。完成!

参考

Last change: 2024-10-21, commit: 046207d