😀 前言
Matrix 搭建全记录(一)—— 使用 Docker 部署 Dendrite
之前部署的 Dendrite 的坑实在是太多了,开发也停滞,很多的新特性包括 Matrix 2.0 依然没有实现,最后还是决定重新回到 Synapse ……
本文记录了我从头开始部署 Synapse 并且进行一些功能加强(滑动同步,OpenID 登录,中文搜索)的步骤
📙 我的部署哲学
- 使用 Docker:减少对系统的改动,不受架构限制,便于备份、管理以及平滑迁移
- 组件最小化:只搭建服务端必要组件,不部署客户端,使用官方网页/客户端即可
- 非侵入性:尽可能少改动现有服务,不影响其他服务的正常运行
💼 准备工作
- 一个在 Cloudflare 托管的域名和子域名,需要解析并开启 CDN
- Homeserver 域名: 比如我的实例是 matrix.mykeyvans.com
- 根域名: 我的实例是 mykeyvans.com ,作为用户标识的域名
- 有一个云服务器(最少 1H1G),比如我的实例服务器搭建在本地的 Oracle ARM 上
⚒️ 开始部署
事前准备
生成配置文件
首先,创建并进入容器编排目录,比如 /app/matrix
执行以下命令生成配置
docker run -it --rm \
-v $(pwd)/synapse:/data \
-e SYNAPSE_SERVER_NAME=mykeyvans.com \
-e SYNAPSE_REPORT_STATS=no \
-e UID=1000 \ # 可选:如果是非 root 环境
-e GID=1000 \ # 可选:如果是非 root 环境
ghcr.io/element-hq/synapse:latest generate
准备数据库
为了在之后实现中文搜索,我使用了内置 Zhparser 分词功能的 PostgreSQL 镜像
替换 postgres 用户密码后,先创建 postgres
文件夹,在数据路径下执行
$ docker run -it --rm --name postgres \
--user "$(id -u):$(id -g)" \
-e POSTGRES_PASSWORD=<超级密码> \
-e ALLOW_IP_RANGE=0.0.0.0/0 \
-v /etc/passwd:/etc/passwd:ro \
-v $(pwd)/postgres:/var/lib/postgresql/data \
ghcr.io/abcfy2/zhparser:17
新开一个终端,输入指令进入交互模式
$ docker exec -it postgres /bin/bash
# 以下进入容器中
ac10e16d4511:/$ psql -U postgres
# 进入 PostgreSQL 交互命令行
psql (17.2 (Debian 17.2-1.pgdg120+1))
Type "help" for help.
# 创建数据库
postgres=# CREATE USER **synapse** WITH PASSWORD '<Synapse 密码>';
CREATE ROLE
postgres=# CREATE DATABASE **synapse** WITH OWNER = **synapse** ENCODING = 'UTF8' LC_COLLATE = 'C' LC_CTYPE = 'C' TEMPLATE = template0;
CREATE DATABASE
postgres=# GRANT ALL PRIVILEGES ON DATABASE **synapse** TO **synapse**;
GRANT
postgres=# \q
ac10e16d4511:/$ exit
执行完毕后,关闭新开的终端,并且在原执行终端里面按 Ctrl+C 结束执行,创建数据库的步骤就成功了
修改配置
使用 PostgreSQL 数据库
修改 synapse/homserver.yaml
中关于数据库的设置 (参考)
database:
name: psycopg2
txn_limit: 10000
args:
user: **synapse**
password: <Synapse 密码>
dbname: synapse
host: postgres
port: 5432
cp_min: 5
cp_max: 10
使用 Redis 缓存
Redis 是一个高效的缓存数据库,能够显著减少服务端的内存占用,修改 synapse/homserver.yaml
以启用 redis
redis:
enabled: true
host: redis
port: 6379
dbid: 0
设置 Homeserver 域名
由于我的服务器架设在子域名 homeserver.mykeyvans.com
下,因此需要添加以下设置 (参考)
public_baseurl: https://homeserver.mykeyvans.com/
serve_server_wellknown: true
配置 Nginx 反向代理
生成网页证书
由于我们使用 Cloudflare CDN,我建议使用自签的空证书来保证安全性,防止泄露源站IP
⭐ 如果你决定不使用 CDN,你需要自行配置有效的证书,推荐使用 Caddy 来自动管理
以下指令逐行执行,生成证书部分全部回车并采用默认值即可
# 创建证书目录并切换到文件夹
$ mkdir -p ./nginx/certs
$ cd ./nginx/certs
# 生成自签证书
$ openssl ecparam -genkey -name prime256v1 -out ca.key
$ openssl req -new -x509 -days 7305 -key ca.key -out ca.crt
$ openssl ecparam -genkey -name prime256v1 -out empty.key
$ openssl req -new -sha256 -key empty.key -out empty.csr
$ openssl x509 -req -days 7305 -sha256 -CA ca.crt -CAkey ca.key -CAcreateserial -in empty.csr -out empty.crt
$ cat empty.crt ca.crt > fullchain.crt
$ openssl dhparam -dsaparam -out dhparams.pem 4096
写入 Nginx 配置文件
修改你的域名,将以下内容粘贴到 ./nginx/nginx.conf
请记得修改其中的 <Homeserver 域名>
user nginx;
worker_processes auto;
worker_cpu_affinity auto;
error_log /var/log/nginx/error.log notice;
pid /var/run/nginx.pid;
worker_rlimit_nofile 51200;
events {
use epoll;
worker_connections 51200;
multi_accept off;
accept_mutex off;
}
http {
include mime.types;
default_type application/octet-stream;
server_names_hash_bucket_size 128;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;
sendfile on;
sendfile_max_chunk 512k;
tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml application/xml+rss;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
server_tokens off;
access_log off;
# For Cloudflare CDN
real_ip_header CF-Connecting-IP;
set_real_ip_from 0.0.0.0/0;
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name <**Homeserver 域名>**;
ssl_certificate /etc/nginx/certs/fullchain.crt;
ssl_certificate_key /etc/nginx/certs/empty.key;
ssl_dhparam /etc/nginx/certs/dhparams.pem;
ssl_session_timeout 1d;
ssl_session_cache shared:nginx:10m;
ssl_session_tickets off;
ssl_protocols TLSv1.3;
ssl_prefer_server_ciphers off;
add_header Strict-Transport-Security "max-age=63072000" always;
# Matrix Synapse
location ~ ^(/_matrix|/.well-known/matrix) {
proxy_pass http://synapse:8008;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Host $host;
proxy_read_timeout 600;
}
}
}
运行 Docker 镜像
基于 Synapse 提供的 docker-compose.yml 稍作修改,我制作了以下的文件,直接复制粘贴即可
services:
postgres:
hostname: postgres
container_name: matrix-postgres
image: ghcr.io/abcfy2/zhparser:17
restart: always
user: "1000:1000"
volumes:
- ./postgres:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U synapse"]
interval: 5s
timeout: 5s
retries: 5
networks:
- internal
redis:
hostname: redis
container_name: matrix-redis
image: redis:7
restart: always
volumes:
- ./redis:/data
networks:
- internal
healthcheck:
test: ["CMD", "redis-cli","ping"]
interval: 5s
timeout: 5s
retries: 5
command: ["redis-server", "--save", "60", "1", "--appendonly", "yes"]
synapse:
hostname: synapse
container_name: matrix-synapse
image: ghcr.io/element-hq/synapse:latest
user: "1000:1000"
volumes:
- ./synapse:/data
# External Modules
- ./synapse_modules/search.py:/usr/local/lib/python3.12/site-packages/synapse/storage/databases/main/search.py
healthcheck:
test: ["CMD", "curl", "-f", "http://127.0.0.1:8008/_matrix/client/versions"]
interval: 30s
timeout: 10s
retries: 3
start_period: 5s
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
networks:
- internal
- external
restart: unless-stopped
nginx:
hostname: nginx
container_name: matrix-nginx
image: nginx:alpine
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/certs:/etc/nginx/certs
depends_on:
postgres:
condition: service_healthy
networks:
- external
ports:
- 443:443
networks:
internal:
internal: true
external:
attachable: true
当所有的配置完成后,目录结构大致如下:
.
├── compose.yml
├── nginx
│ ├── certs
│ └── nginx.conf
├── redis
├── postgres
└── synapse
├── homeserver.yaml
├── <域名>.log.config
└── <域名>.signing.key
没有任何问题的话,在项目目录下运行 docker compose up -d
,运行上述镜像
首次运行
创建首个账户
当所有镜像成功运行后,我们需要执行 docker compose exec synapse /bin/bash
进入互命令行来创建用户
$ register_new_matrix_user http://localhost:8008 \
-c /data/homeserver.yaml -a -u <用户名> -p <密码>
Sending registration request...
Success!
⭐ 只需要输入用户名部分即可,不需要输入完整的用户名+域名
使用 Cloudflare Worker 提供服务发现信息
🔑 如果需要让主域名成为你的 Matrix 服务域名(如 @me:mykeyvans.com),则这个步骤是必需的。如果只想使用子域名(如 @me:homeserver.mykeyvans.com),则这步可以跳过
服务发现是 Matrix 网络发现服务器位置的一种方式。我们的实际服务运行在子域名上,而我们需要让其他服务器/客户端知道我们想使用主域名,则需要提供 /.well-known/matrix
信息。
由于我们的主域名托管在 Cloudflare 上,同时可能主域名运行着其他一些其他服务,因此使用 Cloudflare Worker 就能够优雅地在不修改其他项目文件的情况下,为主域名添加这个服务发现信息
创建 Cloudflare Worker
在 Cloudflare Dashboard → Workers & Pages 中创建一个新的 Worker
使用 Edit Code 的功能,粘贴以下代码并修改其中的 Homeserver 域名
// Homeserver
const HOMESERVER = '**<你的Homeserver 域名>**'
addEventListener('fetch', event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const url = new URL(request.url);
if (url.pathname === '/.well-known/matrix/server') {
return new Response(JSON.stringify({ "m.server": `${HOMESERVER}:443` }), {
headers: { 'Content-Type': 'application/json' }
});
} else if (url.pathname.startsWith('/.well-known/matrix')) {
const targetUrl = `https://${HOMESERVER}${url.pathname}`;
return fetch(targetUrl, {
method: request.method,
headers: request.headers,
body: request.method !== 'GET' && request.method !== 'HEAD' ? request.body : null
});
} else {
return new Response('Not Found', { status: 404 });
}
}
这段代码的功能是:
- 匹配 /.well-known/matrix 路径
- 提供实际的服务器地址
- 将其他服务发现的网络请求转发到 Matrix 服务器
粘贴并修改完毕之后,点击 Deploy 将代码部署到 Cloudflare 网络上
设置路由规则
在 Workers & Pages → Settings → Triggers 中,添加一个新的路由(Route)
- Route:输入
<主域名>/.well-known/matrix/*
- Zone :选择你的主域名
点击 Add Route 即可添加规则,之后你可以通过在浏览器中访问 https://<主域名>/.well-known/matrix/server
和 https://<主域名>/.well-known/matrix/server
来检查是否已经生效
🏃♂️ 开始使用
在上述所有的步骤都完成之后,就可以正式开始使用 Matrix 了!
在浏览器上打开 https://app.element.io ,切换 Homeserver 到你的根域名
如果配置正确,你就可以输入用户名和密码,登录进你刚配置好的服务器了!
Now we can talk on Matrix!
Matrix - Decentralised and secure communication
🎉 拓展内容
在部署完服务器之后,接下来我还打算设置以下功能
- 使用 Matrix Media Repo 储存文件
- 支持中文搜索
- 导入丰富的 Telegram 表情包
- (还有更多,想到补充……)
敬请期待!