这篇记录一个很实用的小组件:在 Matrix Synapse 同一台 Docker 主机上单独跑一个 Element Web,用来登录管理员账号、获取 access token、验证 Synapse 登录和 MatrixRTC 配置。
它不是 Element Call。这里的 web-call 只是本地目录名,实际跑的是 Element Web 客户端,也就是浏览器版 Matrix 客户端。它适合下面这些场景:
- 临时登录管理员账号,获取 Synapse Admin API token。
- 不想在公网 Element、桌面端或手机端里折腾管理员账号。
- 需要一个固定指向自己 Synapse 的内网 Matrix Web 客户端。
- 浏览器访问
http://10.20.20.8:8181提示不支持、白屏或一直转圈。
本文示例用:
Docker 主机内网 IP: 10.20.20.8
Matrix server_name: 666666.xyz
Synapse 客户端地址: https://matrix.666666.xyz:12335
Element Web 域名: https://element.666666.xyz:12335
部署路径: /root/data/docker_data/web-call实际使用时,把 666666.xyz 换成自己的域名。
一、为什么不直接访问 IP
Element Web 对浏览器安全上下文比较敏感。你直接打开:
http://10.20.20.8:8181可能会看到:
Element does not support this browser或者点了继续后一直转圈。这通常不是容器坏了,而是浏览器把普通内网 IP 的 HTTP 页面当成不安全上下文。一些 Web API、存储能力或加密相关能力在这种上下文里会受限制。
SSH 本地转发能用,是因为:
http://localhost:8181浏览器会把 localhost 当成特殊可信来源。所以临时拿 token 或排障时,可以先用 SSH 本地转发;长期使用再让 NPM 提供 HTTPS 域名访问 Element Web。
如果公网 443 没被封,可以直接用:
https://element.666666.xyz/如果公网 443 被运营商封了,NPM 可以继续用非标准 HTTPS 端口,例如:
https://element.666666.xyz:12335/关键点是:浏览器看到的是 HTTPS 域名,而不是明文 IP。
二、准备目录
如果这个目录以前已经存在,想重新部署,可以先删掉再建:
rm -rf /root/data/docker_data/web-call
mkdir -p /root/data/docker_data/web-call
cd /root/data/docker_data/web-call注意,这只删除 Element Web 客户端目录,不会删除 Synapse 数据库、媒体文件或 Matrix 用户数据。
三、写 Element Web 配置
新建 config.json:
vi /root/data/docker_data/web-call/config.json写入:
{
"default_server_config": {
"m.homeserver": {
"base_url": "https://matrix.666666.xyz:12335",
"server_name": "666666.xyz"
}
},
"disable_custom_urls": false,
"disable_guests": true,
"disable_3pid_login": false,
"brand": "Element",
"default_theme": "light",
"features": {},
"setting_defaults": {
"breadcrumbs": true
},
"show_labs_settings": true,
"integrations_ui_url": "",
"integrations_rest_url": "",
"integrations_widgets_urls": [],
"hosting_signup_link": null,
"map_style_url": ""
}这里最重要的是:
"base_url": "https://matrix.666666.xyz:12335",
"server_name": "666666.xyz"base_url 是客户端访问 Synapse 的地址。它必须是浏览器能访问到的 Synapse Client-Server API 地址。
server_name 是 Matrix ID 后面的服务器名。比如你的账号是:
@admin:666666.xyz那这里就写:
666666.xyz四、写 docker-compose.yaml
新建:
vi /root/data/docker_data/web-call/docker-compose.yaml写入:
services:
web-call:
image: vectorim/element-web:latest
container_name: web-call
restart: unless-stopped
ports:
- "8181:80"
volumes:
- ./config.json:/app/config.json:ro
logging:
driver: "json-file"
options:
max-size: "20m"
max-file: "3"启动:
cd /root/data/docker_data/web-call
docker compose up -d检查容器:
docker ps --filter name=web-call本机验证:
curl -I http://127.0.0.1:8181/
curl -s http://127.0.0.1:8181/config.json | head如果返回 200 OK,说明 Element Web 容器本身没问题。
五、临时方式:SSH 本地转发访问
如果只是临时登录管理员账号、拿一次 Admin API token,或者还没来得及配置 NPM,可以直接从自己的电脑建立 SSH 本地转发:
ssh -N -L 8181:127.0.0.1:8181 root@10.20.20.8保持这个 SSH 终端不要关闭,然后在浏览器打开:
http://localhost:8181/这里的访问路径是:
浏览器 localhost:8181
-> 本机 SSH 隧道
-> 10.20.20.8 的 127.0.0.1:8181
-> web-call 容器这种方式的优点是简单,不需要 DNS、证书和 NPM;而且 localhost 在浏览器里属于特殊可信来源,通常不会触发直接访问内网 IP 时的安全限制。
如果本机 8181 已经被占用,可以换一个本地端口:
ssh -N -L 18181:127.0.0.1:8181 root@10.20.20.8浏览器对应打开:
http://localhost:18181/如果 SSH 连接断开,浏览器页面也会失效。这个方式适合临时使用,不适合作为长期入口。
六、长期方式:NPM 反代配置
进入 Nginx Proxy Manager 的 UI,添加一个 Proxy Host。
Details
Domain Names: element.666666.xyz
Scheme: http
Forward Hostname / IP: 10.20.20.8
Forward Port: 8181
Cache Assets: 关
Block Common Exploits: 开
Websockets Support: 开
Access List: PublicElement Web 是静态前端,反代本身不复杂。Websockets Support 开着即可,虽然 Element Web 访问 Synapse 的请求会直接走 matrix.666666.xyz:12335,不是走这个 element 反代。
SSL
如果你已经有通配符证书,比如:
*.666666.xyz, 666666.xyz直接选择它。然后打开:
Force SSL: 开
HTTP/2 Support: 开如果还没有证书,建议用 DNS Challenge 申请通配符证书。公网 80/443 被封时,不要指望普通 HTTP 验证稳定通过。
Advanced
Element Web 通常不需要额外 Advanced 配置,保持空即可。
如果以后想加安全响应头,也要谨慎,尤其不要随意写死过严的 CSP,否则 Element 的登录、加密、跨域请求可能被自己拦掉。
七、NPM 使用非标准 HTTPS 端口
如果公网 443 被封,可以让 NPM 的容器继续把内部 443 映射到宿主机的非标准端口。
例如 /root/data/docker_data/npm/docker-compose.yml:
services:
app:
image: 'docker.io/jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
ports:
- '12332:80'
- '81:81'
# NPM 内部仍然监听 443,宿主机用 12335 暴露
- '0.0.0.0:12335:443'
- '[::]:12335:443'
# 其他服务也可以继续复用 NPM 443,由 SNI 区分域名
- '0.0.0.0:12336:443'
- '[::]:12336:443'
- '0.0.0.0:12337:443'
- '[::]:12337:443'
- '0.0.0.0:12338:443'
- '[::]:12338:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt这种写法的含义是:
浏览器访问 https://element.666666.xyz:12335
-> 宿主机 12335
-> NPM 容器 443
-> 根据 SNI/Host 匹配 element.666666.xyz
-> 反代到 10.20.20.8:8181所以即使多个域名都走 :12335,NPM 也能靠域名区分不同 Proxy Host:
https://matrix.666666.xyz:12335
https://element.666666.xyz:12335只要它们都在 NPM 里有对应 Proxy Host 即可。
改完 NPM compose 后重建:
cd /root/data/docker_data/npm
docker compose up -d检查端口:
ss -lntp | grep -E ':12335|:8181'不要再额外映射宿主机标准 443:443,除非你确定公网或内网确实要用标准 443,而且它不会和其他服务冲突。
八、DNS 怎么指
内网想直接打开:
https://element.666666.xyz:12335/DNS 至少要满足一个条件:
- 内网 DNS 把
element.666666.xyz解析到10.20.20.8。 - 或者公网 DNS 解析到公网 IP,同时路由器支持 NAT Loopback / Hairpin NAT,并把
12335转发回10.20.20.8:12335。
如果你的电脑解析出来的是公网 IP,但路由器不支持回流,就会出现服务器上测试正常、内网电脑打不开的情况。自用环境最省事的是在内网 DNS 或 DDNS 里直接把 element.666666.xyz 指到 10.20.20.8。
可以在客户端电脑上检查:
nslookup element.666666.xyz期望看到类似:
element.666666.xyz -> 10.20.20.8九、验证访问
在服务器上可以先强制解析到本机测试:
curl -k -I \
--resolve element.666666.xyz:12335:127.0.0.1 \
https://element.666666.xyz:12335/正常会看到:
HTTP/1.1 200 OK
Server: openresty
X-Served-By: element.666666.xyz再验证配置文件:
curl -k -s \
--resolve element.666666.xyz:12335:127.0.0.1 \
https://element.666666.xyz:12335/config.json确认里面有:
"base_url": "https://matrix.666666.xyz:12335"也可以验证 Synapse:
curl -k -I \
--resolve matrix.666666.xyz:12335:127.0.0.1 \
https://matrix.666666.xyz:12335/_matrix/client/versions正常返回:
HTTP/2 200最后在浏览器打开:
https://element.666666.xyz:12335/用管理员账号登录即可。
十、获取管理员 access token
登录管理员账号后,可以在浏览器开发者工具里取 token。不同 Element Web 版本界面略有差异,常见方法是:
- 打开浏览器开发者工具。
- 进入 Application / Storage。
- 找到当前站点的 Local Storage 或 IndexedDB。
- 搜索
access_token。
拿到 token 后,可以测试 Admin API:
curl -s \
-H "Authorization: Bearer ACCESS_TOKEN_HERE" \
https://matrix.666666.xyz:12335/_synapse/admin/v1/server_version如果服务器只在内网访问,也可以在 Synapse 主机上用本地地址测试:
curl -s \
-H "Authorization: Bearer ACCESS_TOKEN_HERE" \
http://127.0.0.1:8008/_synapse/admin/v1/server_versiontoken 很敏感,不要写进公开文章、截图、群聊或 shell 历史。生产环境建议保存到 root 只能读的文件,例如:
mkdir -p /root/.config/synapse-admin
vi /root/.config/synapse-admin/access_token
chmod 600 /root/.config/synapse-admin/access_token后续脚本里再这样读取:
TOKEN="$(cat /root/.config/synapse-admin/access_token)"十一、老客户端的会话和密钥问题
如果这个 Element Web 只是临时管理客户端,用完以后不要简单地清浏览器数据就算退出。
Matrix 的端到端加密会把每次登录看成一个设备会话。老版本 Element Web 的“设置 -> 安全与隐私 -> 管理会话”里,有时只能看到其它会话,却无法正常登出其它会话。这样会留下很多旧设备。下次清除浏览器数据、重新登录后,客户端又会把自己当成新设备,并要求重新验证原来的加密密钥或交叉签名。
比较稳妥的做法是:
- 临时管理账号尽量只用来拿 Admin API token,不参与加密房间聊天。
- 清浏览器数据或重装客户端之前,先在当前仍可用的客户端里确认密钥备份、恢复密钥或安全密钥可用。
- 如果老 Element Web 不能删除其它会话,换一个较新的 Element Web、Element Desktop 或 Element X 登录同一账号,在可用的“会话管理”里清理旧设备。
- 清理旧设备后,再清除这个临时 Element Web 的浏览器数据。
如果已经清了浏览器数据,又被要求验证旧密钥,就需要从仍然可信的已登录设备验证新会话,或者使用之前保存的恢复密钥/安全密钥恢复。没有可信设备,也没有恢复密钥时,加密房间的旧消息可能无法再解密。
所以这类管理用 Element Web 更适合作为“临时拿 token 的工具”,不要把它当成长期主力加密聊天客户端。
十二、常见问题
打开 IP 提示浏览器不支持
不要用:
http://10.20.20.8:8181改用:
https://element.666666.xyz:12335/页面一直转圈
先检查 Element Web 的 config.json:
curl -k -s https://element.666666.xyz:12335/config.json重点看 base_url 是否能从浏览器所在网络访问。如果写成了内网容器名、错误端口或公网不可达地址,就会转圈。
登录时报 homeserver 连接失败
验证:
curl -k -I https://matrix.666666.xyz:12335/_matrix/client/versions如果这里不通,先修 Synapse 的 NPM 反代,不要先怀疑 Element Web。
NPM UI 看不到反代
不要手写 /data/nginx/proxy_host/*.conf 来长期管理。应该在 NPM UI 里添加 Proxy Host。这样证书、WebSocket、状态、日志和后续修改都能在 UI 里看到。
证书申请失败
公网 80/443 被封时,HTTP-01 验证经常失败。建议使用 Cloudflare DNS Challenge 申请通配符证书,然后所有内网子域名复用这张证书。
十三、最后的推荐形态
最终推荐保持这样:
/root/data/docker_data/web-call/
docker-compose.yaml
config.json
Element Web:
web-call -> 8181:80
NPM Proxy Host:
element.666666.xyz -> http://10.20.20.8:8181
访问地址:
https://element.666666.xyz:12335/
Synapse:
https://matrix.666666.xyz:12335这套方式的好处是:Element Web 容器简单,NPM UI 可见,证书统一管理,不依赖 SSH 隧道,也不要求运营商放行公网标准 443。