最近打算向身边的朋友推广开源通信软件和开放的通信协议,因此打算自建一个稳定好用的通信服务。XMPP和Matrix是目前较为流行的两个开放的、支持端对端加密的通信协议。 我个人其实更喜欢XMPP,因为它有成熟且资源占用更小的服务端软件,能够在很少资源的VPS上承载很大的通信流量(省钱)。 但是支持XMPP的客户端除了Android平台上Conversations之外少有美观好用的,桌面端更是如此。另外我身边的朋友们更喜欢Element的跨平台的一致体验和Matrix更丰富的功能,所以我最终选择Matrix协议。
Matrix官方的Go语言服务端Dendrite相比官方的Python服务端Synapse更加高效,且占用资源更少,但目前还处于Beta阶段且缺少很多功能。虽然Synapse在用户加入规模大的群聊时会占用很多的内存,但胜在稳定和功能全面,资料丰富,而且我的服务器仅用于小规模的朋友之间的通信,不太可能遇到加入规模大的群聊的情况。因此,为了朋友们有更好的体验以便推广开源开放的通信软件,我选择部署Synapse。
Ansible是一个自动化的运维工具。通过热心开发者提供的Ansible Playbook ,我能方便地自动化部署Matrix服务端软件Synapse和其他相关服务。
除了配置SSH时需要登陆到VPS上操作,其余操作均在本地完成。
获取Playbook
通过git下载仓库。通过本地的包管理器下载安装Ansible。
git clone https://github.com/spantaleev/matrix-docker-ansible-deploy.git
设置DNS
默认的DNS设置
主要的两条DNS记录。由于我需要matrix服务器来托管基础域名,因此还需要将基础域名地址指向matrix服务器。
Type | Host | Priority | Weight | Port | Target |
---|---|---|---|---|---|
A | matrix |
- | - | - | matrix-server-IP |
CNAME | element |
- | - | - | matrix.<your-domain> |
其他DNS设置
我需要配置dimension
用于插件管理,stats
用于查看服务器状态,ntfy
用于消息推送。
Type | Host | Priority | Weight | Port | Target |
---|---|---|---|---|---|
SRV | _matrix-identity._tcp |
10 | 0 | 443 | matrix.<your-domain> |
CNAME | dimension |
- | - | - | matrix.<your-domain> |
CNAME | jitsi |
- | - | - | matrix.<your-domain> |
CNAME | stats |
- | - | - | matrix.<your-domain> |
CNAME | goneb |
- | - | - | matrix.<your-domain> |
CNAME | sygnal |
- | - | - | matrix.<your-domain> |
CNAME | ntfy |
- | - | - | matrix.<your-domain> |
CNAME | hydrogen |
- | - | - | matrix.<your-domain> |
CNAME | cinny |
- | - | - | matrix.<your-domain> |
CNAME | buscarron |
- | - | - | matrix.<your-domain> |
根据需求修改配置文件
创建配置文件
在 inventory/host_vars
中建立以matrix.<your-domain>
为名的文件夹。复制模板到该文件夹cp examples/vars.yml inventory/host_vars/matrix.<your-domain>/vars.yml
。根据模板中的注释填入基本的配置信息。
复制模板(cp examples/hosts inventory/hosts
)并根据自己的服务器SSH信息修改hosts
文件。
配置 Synapse
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
配置workers实现负载均衡,对每个支持的服务类型都使用workers matrix_synapse_workers_enabled: true matrix_synapse_workers_preset: one-of-each
禁用 Element
由于我的服务器不打算提供 Web APP,因此禁用Element,也不开启 Hydrogen 和 Cinny。
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_client_element_enabled: false
配置 Synapse Admin
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_synapse_admin_enabled: true
Synapse Admin需要Synapse的Admin APIs来运行,添加该配置项后会自动开放相关API。
配置用于存储媒体文件的对象存储
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_s3_media_store_enabled: true
matrix_s3_media_store_bucket_name: "your-bucket-name"
matrix_s3_media_store_aws_access_key: "access-key-goes-here"
matrix_s3_media_store_aws_secret_key: "secret-key-goes-here"
matrix_s3_media_store_custom_endpoint_enabled: true
matrix_s3_media_store_custom_endpoint: "your-custom-endpoint"
配置SSL证书
如果使用集成的Nginx,那么该 Ansible playbook 会根据配置文件中指定开启的服务来自动获取各个服务或插件对应域名的SSL证书。因此我这里仅仅指定证书的加密算法。
matrix_ssl_lets_encrypt_key_type: ecdsa
基础域名服务
由于运行Synapse的联邦发现服务需要服务器委托(在基础域名下提供/.well-known/matrix/*
等文件)。相比较为麻烦的自建网页服务器方案,我选择通过matrix集成的网页服务器来托管基础域名。
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_nginx_proxy_base_domain_serving_enabled: true
由于我需要使用自定义的主页,因此需要额外添加以下配置: matrix_nginx_proxy_base_domain_homepage_enabled: false
有了这个配置,Ansible就不会再处理/matrix/nginx-proxy/data/matrix-domain/index.html
文件。
然后,可以将任何静态网站文件上传到/matrix/nginx-proxy/data/matrix-domain
。更复杂的网站建议使用自建网页服务器的方案。
TURN 服务器
为了方便客户端能在 NAT-ed 网络环境中视频/语音通话,需要配置 TURN 服务器。默认情况下该 Ansible playbook 会自动配置,因此无需额外配置。
遥测数据
该 Ansible playbook 会自动配置为不发送服务器的使用情况,因此无需额外配置。
更改联邦通信的端口到443
修改此项内容会导致matrix-nginx-proxy.service
服务因为443端口被docker-pr占用而无法正常启动,故暂时不配置此项内容。
为了防止可能的DOS/DDOS攻击,我需要使用CDN。将用于联邦通信的端口改到443后,将能正常使用CDN。
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_synapse_http_listener_resource_names: ["client","federation"]
matrix_federation_public_port: 443
matrix_synapse_federation_port_enabled: false
以下修改是为了适应一些CDN而做出的,可以先尝试一下,看看在设置以下内容为true
的情况下,联邦通信是否工作。如果不行再修改为false
。
matrix_synapse_tls_federation_listener_enabled: true
邮件设置
可以通过matrix_mailer_sender_address
变量来指定Matrix服务的发件人。默认为matrix@<your-domain-name>
,这里我保持默认。
身份服务
我的服务不打算开启ma1sd身份服务,因此不额外配置。
设置反垃圾信息服务
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_synapse_ext_spam_checker_synapse_simple_antispam_enabled: true
matrix_synapse_ext_spam_checker_synapse_simple_antispam_config_blocked_homeservers:
- example.com
- another.com
防火墙设置
需要开放的端口有80和443用于Web,8448用于联邦通信,3478、5349、49152-49172用于TURN。如果配置了其他服务,其他可能用到端口可以在服务启动后通过docker ps
命令查看。
安装
运行以下命令安装:
ansible-playbook -i inventory/hosts setup.yml --tags=setup-all
安装过程中可能需要输入SSH登陆信息。
Notes:
- 如果你 不使用 SSH keys 来登陆服务器, 而是使用一般的密码,那在
ansible-playbook
指令后添加--ask-pass
。 - 如果你 使用 SSH keys 来登陆服务器, 并且 登陆用户不是root,而是能使用sudo的用户,你可能需要在
ansible-playbook
指令后添加-K
(--ask-become-pass
) 来让Ansible运行特权指令。
检查服务是否正确安装
运行以下命令开启服务:
ansible-playbook -i inventory/hosts setup.yml --tags=start
在Federation Tester上输入你的服务器域名后可以测试联邦通信服务是否正常工作。
运行以下命令检查服务:
ansible-playbook -i inventory/hosts setup.yml --tags=self-check
创建用户
接下来的很多组件需要用到已有的账户,因此在配置安装这些组件前需要先创建他们。通过以下命令可以创建账户:
ansible-playbook -i inventory/hosts setup.yml --extra-vars='username=<your-username> password=<your-password> admin=<yes|no>' --tags=register-user
通过以下命令可以获取账户的访问令牌:
curl -X POST --header 'Content-Type: application/json' -d '{
"identifier": { "type": "m.id.user", "user": "YourBotUsername" },
"password": "YourBotPassword",
"type": "m.login.password"
}' 'https://matrix.YOURDOMAIN/_matrix/client/r0/login'
注意修改 YourBotUsername
, YourBotPassword
, 和 YOURDOMAIN
为合适的值。
配置安装其他组件
设置 Dimension
创建名为dimension
的非管理员用户,并获取令牌。
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_dimension_enabled: true
matrix_dimension_admins:
- "@dimension:{{ matrix_domain }}"
matrix_dimension_access_token: "YOUR ACCESS TOKEN HERE"
服务器运行情况图表
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件。
matrix_prometheus_enabled: true
# You can remove this, if unnecessary.
matrix_prometheus_node_exporter_enabled: true
# You can remove this, if unnecessary.
matrix_prometheus_postgres_exporter_enabled: true
matrix_grafana_enabled: true
matrix_grafana_anonymous_access: false
# This has no relation to your Matrix user id. It can be any username you'd like.
# Changing the username subsequently won't work.
matrix_grafana_default_admin_user: "some_username_chosen_by_you"
# Changing the password subsequently won't work.
matrix_grafana_default_admin_password: "some_strong_password_chosen_by_you"
默认的管理员账户和密码与matrix服务器的账户无关,自行选择设置即可。安装后可登陆https://stats.DOMAIN
查看服务器资源占用情况和历史数据。
设置注册机器人 matrix-registration-bot
出于安全和服务器承载能力的考虑,我不打算开放注册。因此需要工具来管理邀请令牌。matrix-registration缺乏维护且存在bug,因此我选择部署matrix-registration-bot服务。
创建一个管理员用户,名称不限,并获取令牌。该服务默认使用的管理员账户名称是@bot.matrix-registration-bot:DOMAIN
。
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件,添加以下内容。
matrix_bot_matrix_registration_bot_enabled: true
# Token obtained via logging into the bot account (see above)
matrix_bot_matrix_registration_bot_bot_access_token: "syt_bW9hbm9z_XXXXXXXXXXXXXr_2kuzbE"
# Enables registration
matrix_synapse_enable_registration: true
# Restrict registration to users with a token
matrix_synapse_registration_requires_token: true
如果需要用自定义的管理员账户,添加
matrix_bot_matrix_registration_bot_matrix_user_id_localpart: XXX
该服务安装完成后,创建一个非加密的聊天室,邀请你创建的机器人的账号进入该聊天室。注意不要直接查找机器人账号后开启聊天,这种方式创建的聊天室是加密的,机器人无法在加密的聊天室中使用。
在该聊天室中发送help
命令即可了解详细的使用方法。
其他信息可以查看 使用说明.
如果更换过机器人的账户或者机器人账户的令牌,再次部署前需要删除/matrix/matrix-registration-bot/data/session.txt
,否则会部署失败。
ReCaptcha验证
本次使用的Ansible Playbook对于Synapse只支持Google的ReCaptcha,如果使用Dendrite的话额外支持hCapcha。因此我只能选择部署ReCaptcha服务。
首先需要通过以下链接申请ReCaptcha的公钥和私钥。
http://www.google.com/recaptcha/admin
注意reCAPTCHA类型要选择 第2版 和 “进行人机身份验证”复选框。
之后复制公钥(发送给用户)和私钥(用于Synapse服务器和Google的reCAPTCHA服务器之间通信)。
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件,添加以下内容。
matrix_synapse_enable_registration_captcha: true
matrix_synapse_recaptcha_public_key: 'YOUR_SITE_KEY'
matrix_synapse_recaptcha_private_key: 'YOUR_SECRET_KEY'
备份 borg backup
TODO
推送服务
ntfy是一个使用UnifiedPush标准的推送服务器,可以替代Google的FCM或者Apple的APN服务。
修改inventory/host_vars/matrix.DOMAIN/vars.yml
文件,添加以下内容。
# Enabling it is the only required setting
matrix_ntfy_enabled: true
# Some other options
matrix_server_fqn_ntfy: "ntfy.{{ matrix_domain }}"
matrix_ntfy_configuration_extension_yaml: |
log_level: DEBUG
再次配置服务
修改配置文件后运行以下命令再次配置服务。
ansible-playbook -i inventory/hosts setup.yml --tags=setup-all,start
更新服务
用git pull
更新仓库后阅读changelog,确认配置文件无误后运行以下命令。
ansible-playbook -i inventory/hosts setup.yml --tags=setup-all,ensure-matrix-users-created,start
总结
虽然研究如何修改Ansible Playbook花费了不少时间,但修改完成后的自动部署就非常方便了,输入部署命令后只需要开着终端等待就行。刚开始因为一些配置问题导致部署失败,但根据软件仓库的issue信息找到问题并解决了。目前大部分有关Matrix服务器的教程都没有用到Ansible,因此我记录下我的部署过程作为参考,希望能给读者提供另一种部署Matrix服务的思路。固然直接部署灵活性更高,且如果仅仅部署Synapse本体,花费时间未必比使用Ansible多,但如果需要部署大量配套服务,还是Ansible更加方便省力。个人认为这个Ansible Playbook的唯一问题就是部署时间长,在单核VPS上每次部署都要等待20分钟以上。
补充
2022-12-28:
- 如果在MacOS下运行Ansible时可能会在配置PostgreSQL时遇到
crypt.crypt not supported on Mac OS X/Darwin
错误,按提示安装Python包py-passlib
; - 由于matrix-docker-ansible-deploy项目的更新,老用户的
inventory/host_vars/matrix.<your-domain>/vars.yml
文件中的matrix_postgres_
开头的模块需要替换为devture_postgres_
开头才能正常使用,新用户不受影响。