使用 Docker 安装 Matrix

7 minute read

起因是我忘记的自己 Matrix 账号的密码,既然如此就自己建一个吧。就算这样想也拖了很久,毕竟我的属性是每次都失败。

说明一下,Synapse 是 Matrix 的服务端,需要配合另外客户端使用,可以自己搭建 web-client,也可以用现成的。这里是一份 matrix 社区整理的客户端列表

另外,Matrix 还有 Delegation 特性,可以通过 .well-known file 将流量引导至实际提供服务的域名或(和)端口。简而言之 server_name 可以和实际的 homeserver 不同

以下内容均建立在 server_namehomeserver 相同的情况下。

目录结构

 1matrix
 2   ├── synapse
 3   │   ├── data
 4   │   ├── db
 5   │   └── redis
 6   ├── media-repo
 7   │   ├── data
 8   │   ├── db
 9   │   └── redis
10   └── web-client

这边将 Matrix 服务分成了三部分:

  1. Synapse
  2. Media-repo
  3. Web-client

Media-repo 是一个客制化的 Matrix 媒体储存库项目。

下面的操作默认在 matrix/ 下进行,并在 Docker 环境下搭建。

配置 Synapse

生成 Synapse 配置文件

docker run -it --rm \
    -v </root/matrix/synapse/data>:/data \	
    -e SYNAPSE_SERVER_NAME=<example.com> \		
    -e SYNAPSE_REPORT_STATS=no \		
    matrixdotorg/synapse:latest generate

注意:

  1. /root/matrix/synapse/data 为实际目录中 data绝对路径
  2. SYNAPSE_SERVER_NAME 与用户登录时需要输入的服务器地址一致

编辑 Synapse 配置文件

打开配置文件 nano synapse/data/homeserver.yaml

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
# Configuration file for Synapse.

## Server
server_name: "<example.com>"
pid_file: /data/homeserver.pid
#web_client_location: <https://riot.example.com/>
public_baseurl: <https://example.com/>
#serve_server_wellknown: true
#presence:
#	 enable: true
listeners:
	- port: 8008
		tls: false
		type: http
		x_forwarded: true
		bind_addresses: ['::1', '127.0.0.1']
		resources:
			- names: [client, federation]
				compress: false
## Homeserver blocking
#admin_contact: 'mailto:[email protected]'
max_avatar_size: 5M
allowed_avatar_mimetypes: ["image/png", "image/jpeg", "image/gif"]
## Database
database:
#	 name: sqlite3
#	 args:
#		 database: DATADIR/homeserver.db
	name: psycopg2
	args:
		user: <Databse User>
		password: <Databse Pass>
		database: <Databse Name>
		host: db
		cp_min: 5
		cp_max: 10
## Logging
log_config: "[/data/<example.com>.log.config]"
## Media Store
enable_media_repo: false
#media_store_path: "data/media_store"
url_preview_enabled: true
url_preview_ip_range_blacklist:
	- '127.0.0.0/8'
	- '10.0.0.0/8'
	- '172.16.0.0/12'
	- '192.168.0.0/16'
	- '100.64.0.0/10'
	- '192.0.0.0/24'
	- '169.254.0.0/16'
	- '192.88.99.0/24'
	- '198.18.0.0/15'
	- '192.0.2.0/24'
	- '198.51.100.0/24'
	- '203.0.113.0/24'
	- '224.0.0.0/4'
	- '::1/128'
	- 'fe80::/10'
	- 'fc00::/7'
	- '2001:db8::/32'
	- 'ff00::/8'
	- 'fec0::/10'
url_preview_url_blacklist:
	# blacklist all plain HTTP URLs
	- scheme: 'http'
	# blacklist any URL with a literal IPv4 address
	- netloc: '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'
max_spider_size: 5M
url_preview_accept_language:
	- zh
	- en
## Registration
enable_registration: true
session_lifetime: 72h
#registrations_require_3pid:
#   - email
#   - msisdn
registration_requires_token: true
registration_shared_secret: <PRIVATE STRING>
allow_guest_access: false
enable_set_displayname: true
enable_set_avatar_url: true
#auto_join_rooms:
#   - "#exampleroom:example.com"
#   - "#anotherexampleroom:example.com"
default_identity_server: https://matrix.org
auto_join_rooms: 
	- "#public:example.com"
## Metrics
report_stats: false
## API Configuration
macaroon_secret_key: <Macaroon Secret Key>
form_secret: <Form Secret>
## Signing Keys
signing_key_path: "/data/<example.com>.signing.key"
#key_refresh_interval: 1d
trusted_key_servers:
	- server_name: "matrix.org"
suppress_key_server_warning: true
password_config:
	enabled: true
	policy: 
		enable: true
			minimum_length: 8
user_directory:
	prefer_local_users: true
redis:
	enabled: true
	host: redis
	port: 6379
# vim:ft=yaml

注意修改高亮的地方,其他可以酌情自定义

另外,血泪教训:不要随便删除默认文档里的任何东西,最好备份一份,编辑时最好用注释来去除不需要的设置。

配置 Media-Repo

编辑 Media-repo 配置文件 nano media-repo/data/media-repo.yaml

 1repo:
 2    # Generally the bind address should be local as the media repo should be
 3    # behind a reverse proxy.
 4    bindAddress: '0.0.0.0'
 5    port: 8000
 6database:
 7    # Currently only PostgreSQL is supported. This is *not* the same as your
 8    # homeserver's database.
 9    postgres: "postgres://<Databse_User_Media>:<Databse_Pass_Media>@media_db/<Databse_Name_Media>?sslmode=disable"
10homeservers:
11    - name: <example.com>
12      csApi: "http://synapse:8008"
13admins:
14    - "@<admin_username>:<example.com>"
15datastores:
16	- type: s3
17		enabled: true
18			forKinds: ["all"]
19			opts:
20				tempPath: "/tmp/mediarepo_s3_upload"
21				endpoint: <sfo2.digitaloceanspaces.com>
22				accessKeyId: "<ACCESS_KEY>"
23				accessSecret: "<ACCESS_SECRET>"
24				ssl: true
25				bucketName: "<your-media-bucket>"
26				region: "<sfo2>"
27thumbnails:
28	maxSourceBytes: 10485760 # 10MB default, 0 to disable
29	numWorkers: 100
30	expireAfterDays: 0
31	sizes:
32		- width: 32
33			height: 32
34		- width: 96
35			height: 96
36		- width: 320
37			height: 240
38		- width: 640
39			height: 480
40		- width: 800
41			height: 600
42 	dynamicSizing: false
43 	allowAnimated: true
44 	defaultAnimated: false
45 	maxAnimateSizeBytes: 10485760 # 10MB default, 0 to disable
46 	stillFrame: 0.5
47 	types:
48		- "image/jpeg"
49		- "image/jpg"
50		- "image/png"
51		- "image/gif"
52		- "image/heif"
53		- "image/webp"
54		#- "image/svg+xml" # Be sure to have ImageMagick installed to thumbnail SVG files
55urlPreviews:
56	previewUnsafeCertificates: false
57	disallowedNetworks:
58		- "127.0.0.1/8"
59		- "10.0.0.0/8"
60		- "172.16.0.0/12"
61		- "192.168.0.0/16"
62		- "100.64.0.0/10"
63		- "169.254.0.0/16"
64		- '::1/128'
65		- 'fe80::/64'
66		- 'fc00::/7'
67	allowedNetworks:
68		- "0.0.0.0/0"

这里我用的是 S3 储存,也可以选择存储在本地服务器。

注意:

1homeservers: 
2	- name: example.com

这里 example.com 需要和 server_name 一致,特别是如果用到 Delegation 功能。

docker-compose 配置

编辑 docker-compose 配置文件 nano docker-compose.yml

 1version: "3.4"
 2services:
 3	synapse:
 4		hostname: matrix
 5		image: matrixdotorg/synapse:latest
 6		restart: always
 7		container_name: matrix_server
 8		depends_on:
 9			- db
10			- redis
11			- media_repo
12		ports:
13			- "127.0.0.1:8008:8008"
14		volumes:
15			- ./synapse/data:/data
16		networks:
17			- synapse_network
18			- external_network
19		healthcheck:
20			test: ["CMD-SHELL", "curl -s localhost:8008/health || exit 1"]
21
22	db:
23		image: postgres:14.4-alpine
24		restart: always
25		container_name: matrix_db
26		volumes:
27			- ./synapse/db:/var/lib/postgresql/data
28		environment:
29			POSTGRES_USER: <Databse User>
30			POSTGRES_PASSWORD: <Databse Pass>
31			POSTGRES_DB: <Databse Name>
32			POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
33		networks:
34			- synapse_network
35		healthcheck:
36			test: ["CMD", "pg_isready", "-U", "<Databse User>"]
37
38	redis:
39		image: redis:6.0-alpine
40		restart: always
41		container_name: matrix_redis
42		volumes:
43			- ./synapse/redis:/data
44		networks:
45			- synapse_network
46		healthcheck:
47			test: ["CMD", "redis-cli", "ping"]
48
49	media_repo:
50		hostname: media_repo
51		image: turt2live/matrix-media-repo:latest
52		restart: always
53		container_name: matrix_media_repo
54		depends_on:
55			- media_db
56		ports:
57			- "127.0.0.1:8000:8000"
58		volumes:
59			- ./media-repo/data:/data
60		networks:
61			- media_network
62			- external_network
63
64	media_db:
65		image: postgres:13.2-alpine
66		restart: always
67		container_name: matrix_media_db
68		volumes:
69			- ./media-repo/db:/var/lib/postgresql/data
70		environment:
71			POSTGRES_USER: <Databse_User_Media>
72			POSTGRES_PASSWORD: <Databse_Pass_Media>
73			POSTGRES_DB: <Databse_Name_Media>
74			POSTGRES_INITDB_ARGS: "--encoding='UTF8' --lc-collate='C' --lc-ctype='C'"
75		networks:
76			- media_network
77		healthcheck:
78			test: ["CMD", "pg_isready", "-U", "<Databse_User_Media>"]
79
80	media_redis:
81		image: redis:6.0-alpine
82		restart: always
83		container_name: matrix_media_redis
84		volumes:
85			- ./media-repo/redis:/data
86		networks:
87			- media_network
88		healthcheck:
89			test: ["CMD", "redis-cli", "ping"]
90
91networks:
92	synapse_network:
93		internal: true
94	media_network:
95		internal: true
96	external_network:

注意 PostgreSQL 和 redis 的版本,最好使用最新的稳定版本。

启动服务 docker-compose up -d

反代配置

 1map $http_upgrade $connection_upgrade {
 2    default upgrade;
 3    ''      close;
 4}
 5
 6upstream matrix_backend {
 7    server 127.0.0.1:8008 fail_timeout=0;
 8}
 9
10upstream matrix_media_repo {
11    server 127.0.0.1:8000 fail_timeout=0;
12}
13
14proxy_cache_path /var/cache/nginx levels=1:2 keys_zone=CACHE:10m inactive=7d max_size=1g;
15
16server {
17    listen 80;
18    listen [::]:80;
19    server_name example.com;
20    
21    location / {
22		return 301 https://$host$request_uri;
23	}
24}
25
26server {
27    listen 443 ssl http2;
28    listen [::]:443 ssl http2;
29    server_name example.com;
30
31    # SSL protocol settings    
32    ssl_protocols TLSv1.2 TLSv1.3;
33    ssl_ciphers HIGH:!MEDIUM:!LOW:!aNULL:!NULL:!SHA;
34		
35    ssl_certificate    /etc/ssl/example.com.pem; 
36    ssl_certificate_key /etc/ssl/example.com.key;
37		
38		 ssl_session_cache shared:ssl_session_cache:10m;	
39    ssl_prefer_server_ciphers on;
40
41    gzip on;
42    gzip_disable "msie6";
43    gzip_vary on;
44    gzip_proxied any;
45    gzip_comp_level 4;
46    gzip_buffers 16 8k;
47    gzip_http_version 1.1;
48    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
49
50    # well-known
51    location /.well-known/matrix/server {
52        # Allow access from *
53        add_header Access-Control-Allow-Origin '*';
54        default_type application/json;
55        return 200 '{ "m.server": "example.com:443" }';
56    }
57
58    location /.well-known/matrix/client {
59        # Allow access from *
60        add_header Access-Control-Allow-Origin '*';
61        default_type application/json;
62        return 200 '{"m.homeserver": { "base_url": "https://example.com" } }';
63    }
64
65
66# Matrix reverse proxy
67
68    # Matrix HomeServer
69    location ~* ^(\/_matrix|\/_synapse\/client) {
70        proxy_pass http://matrix_backend;
71        proxy_set_header X-Forwarded-For $remote_addr;
72        proxy_set_header X-Forwarded-Proto $scheme;
73        proxy_set_header Host $host;
74
75        client_max_body_size 100M;
76    }
77
78    # Matrix Media API
79    location ^~ /_matrix/media {
80        proxy_read_timeout 60s;
81        proxy_set_header Host $host;
82
83        proxy_set_header X-Real-IP $remote_addr;
84        proxy_set_header X-Forwarded-For $remote_addr;
85        proxy_pass http://matrix_media_repo;
86    }
87
88}

配置客户端

我这么懒怎么可能再整一个客户端。再说开放的客户端这么多,随便选一个用用啦。

然后虽然启动了 Synapse-Admin 服务,但是好像也没太多用处。

后记

大多数教程都建议服务器内存要4G,我的服务器只有2G,现在感觉确实要炸了。

每次安装点什么都会有奇奇怪怪的小毛病,这次当然也不例外。居然!不能上传用户头像!

表现为客户端发起请求 PUT /_matrix/client/r0/profile/%40alice%3Aexample.com/avatar_url HTTP/1.1 后,返回 code 403

1{
2  "errcode": "M_FORBIDDEN",
3  "error": "This avatar is not allowed"
4}

我完全不知道发生了什么,只能两眼一闭,自此本站 Public Room 改名为无头骑士交流会

参考


联合部署 Mastodon 与 Synapse

[Matrix] 使用 docker 搭建 Synapse 记录

使用docker搭建Synapse[Matrix]

Matrix踩坑记(一)

Synapse Doc

Matrix-Media-Repo Doc