Peerloom:搭个在线协作室
十一假期,给自己折腾了一个在线协作工具:Peerloom
十一放假,终于可以休息几天。作为一个程序员,这时候应该做点什么呢?我决定:卷起来。毕竟,头发卷起来,显得发量多。于是,趁着假期折腾了一下,把一个屏幕共享工具慢慢改成了现在的 Peerloom:打开浏览器,建一个房间,就能共享屏幕、语音聊天、一起写文档、画白板,还能一起看本地视频。假期有没有得到充分休息不好说,工具栏倒是比放假前充实了不少。
打开浏览器,进入同一个房间,就能共享屏幕、语音聊天、一起写文档、画白板,还能一起看本地视频。
它基于开源项目 Screego 二次开发。我在屏幕共享的基础上,补充了一些讨论时常用的功能,以及中文操作界面。
想解决的事情很简单:几个人临时聚在一起,看同一块屏幕,把问题聊明白,顺手记下结论。
至于为什么放假还在写代码——可能程序员的休息,就是换一个自己愿意修的 Bug。
这篇主要介绍两件事:怎么部署,以及部署好以后怎么用。 没接触过这个项目,也可以跟着步骤来。
- 在线体验:打开 Peerloom
- 项目源码:GitHub · eson-sheng/peerloom
01 · 先看看,它能做什么
| 功能 | 可以用来做什么 |
|---|---|
| 屏幕共享 | 展示代码、网页、软件操作和运行结果 |
| 语音与摄像头 | 一边看画面,一边讨论 |
| 协作文档 | 共同整理笔记、讨论结论和待办 |
| 协同白板 | 画草图、理流程、解释思路 |
| 本地音视频同播 | 一起查看视频素材、观看演示或收听音频 |
| 房间管理 | 管理成员、控制媒体权限、查看连接状态 |
| 自托管 | 部署到自己的服务器,按需设置容量 |
进入房间后,主区域用于展示共享画面,右侧可以查看成员信息、媒体席位和房间聊天。

界面截图:尚未开启画面共享时,主区域显示“暂无视频流”,这是正常的等待状态。截图中的容量以演示环境配置为准。
比如远程讨论一个页面,可以先共享屏幕说明问题,再打开白板画调整思路,最后把结论写进协作文档。
大家围绕同一个房间协作,少一些软件切换,也少一些“刚才那个链接再发一下”。
02 · 部署之前,需要准备什么

部署路线示意:先看整体步骤,再按下面的命令逐项完成。
普通使用者只需要浏览器。只有负责部署的人,才需要准备服务器和安装构建工具。
下面的命令以 Linux 服务器为主,使用源码构建方式。建议直接在准备运行 Peerloom 的服务器上编译,避免把其他系统生成的程序拿过来运行。
需要准备:
| 准备项 | 用途 |
|---|---|
| Linux 服务器 | 运行 Peerloom |
| Git | 下载项目源码 |
| Go 1.26.0 或更高版本 | 编译后端程序 |
| Node.js、Yarn | 安装依赖并构建网页界面 |
| 域名和 HTTPS 证书 | 供其他人通过浏览器安全访问 |
| 可配置的防火墙或安全组 | 放通网页和音视频连接需要的端口 |
Node.js 版本需要满足项目当前前端依赖的要求,具体以仓库说明为准。
安装好工具后,可以先在终端检查:
git --version
go version
node --version
yarn --version
如果提示 command not found,说明对应工具尚未安装,或者没有加入系统命令路径,需要先完成这一步。
后面的命令默认在项目目录中执行。代码框里的内容可以复制到终端;其中的服务器 IP、域名和文件路径,需要换成自己的实际值。
03 · 下载代码,生成可运行的程序
先下载项目:
git clone https://github.com/eson-sheng/peerloom.git
cd peerloom
第一条命令会创建一个 peerloom 文件夹,第二条命令进入这个文件夹。
接着下载后端依赖:
go mod download
安装并构建前端:
(cd ui && yarn install --frozen-lockfile)
(cd ui && yarn build)
这里的括号表示临时进入 ui 目录执行命令,完成后仍回到原来的项目目录。
最后编译后端:
go build \
-ldflags "-X main.version=1.0.0 -X main.mode=prod" \
-o peerloom ./main.go
编译完成后,当前目录里会生成一个名为 peerloom 的可执行文件。
检查它能否正常运行:
./peerloom --version
简单解释一下:
./peerloom:运行当前目录里的 Peerloom 程序。--version:查看程序版本。main.version=1.0.0:设置这次构建显示的版本号。main.mode=prod:使用生产模式,避免加载开发环境专用配置。
构建顺序不能颠倒:先构建前端,再编译 Go 程序。
因为生产构建会把前端资源一起放进可执行文件里。以后修改了网页界面,也需要重新构建前端、重新编译程序,才能更新部署后的页面。
每条命令都应成功完成后再执行下一条。遇到报错先处理,不要一路复制到底,最后期待奇迹发生。
04 · 创建配置文件,告诉程序怎么运行
首次部署时,复制一份示例配置:
cp peerloom.config.example peerloom.config.local
这条命令的意思是:保留原来的示例文件,再生成一份自己的配置文件。
已经部署过的朋友,直接编辑现有的 peerloom.config.local,不要重复复制覆盖。
先生成一个随机密钥:
openssl rand -hex 32
终端会输出一长串字符,把它保存下来,稍后填入 PEERLOOM_SECRET。
这个密钥用于登录会话,不是网页登录密码。设置后保持固定,不要每次启动都重新生成。
使用文本编辑器打开配置文件,例如:
nano peerloom.config.local
如果使用 nano,编辑后按 Ctrl + O 保存,按回车确认文件名,再按 Ctrl + X 退出。
把下面这些配置项修改为自己的值,其他项目暂时保留示例中的设置:
# 服务器对访问者可达的 IP,公网部署填写公网 IP
PEERLOOM_EXTERNAL_IP=YOUR_SERVER_IP
# 填入刚才生成的随机密钥
PEERLOOM_SECRET=YOUR_RANDOM_SECRET
# 网页服务监听地址
PEERLOOM_SERVER_ADDRESS=0.0.0.0:5050
# 内置 TURN 服务监听地址
PEERLOOM_TURN_ADDRESS=0.0.0.0:3478
# TURN 中继使用的 UDP 端口范围
PEERLOOM_TURN_PORT_RANGE=50000:50100
PEERLOOM_AUTH_MODE=turn
# 账号文件的绝对路径,下一节会创建
PEERLOOM_USERS_FILE=/absolute/path/to/peerloom/users.local
# 每个房间最多 12 人
PEERLOOM_MAX_ROOM_MEMBERS=12
# 最多 6 个实时媒体席位
PEERLOOM_MAX_MEDIA_SEATS=6
其中,有几个地方需要特别说明。
服务器 IP 怎么填?
公网部署填写客户端能够访问到的服务器公网 IP;局域网部署填写其他设备能够访问到的局域网 IP。
这里填写的是 IP,不是 https://你的域名,也不是网页端口。
账号文件路径怎么找?
在项目目录执行:
pwd
假设输出:
/home/ubuntu/peerloom
那么账号文件路径就填写:
PEERLOOM_USERS_FILE=/home/ubuntu/peerloom/users.local
/absolute/path/to/peerloom/users.local 只是示意,不能原样照抄。
12 人和 6 个媒体席位有什么区别?
12 人是房间总人数上限;6 个媒体席位限制同时发布屏幕、摄像头或同播内容的人数。
语音独立于这些内容席位,但仍受房主设置的媒体权限控制。媒体席位数不能超过房间人数。
配置文件放在哪里?
按本文命令生成的生产程序,会优先读取可执行文件同目录下的 peerloom.config.local。系统环境变量的优先级更高。
修改配置后,需要重启 Peerloom 才能生效。
05 · 创建账号:把这条命令讲清楚
首次创建账号文件,执行:
./peerloom hash --name admin > users.local

命令说明示意:首次创建用 >,新增账号用 >>;账号文件修改后需要重启服务。
这条命令看起来短,里面其实有四件事:
| 部分 | 含义 |
|---|---|
./peerloom |
运行当前目录里的程序 |
hash |
生成密码哈希,也就是用于验证密码的记录 |
--name admin |
指定用户名为 admin |
> users.local |
把生成的账号记录写入文件 |
执行后,终端会提示:
Enter Password:
输入你准备使用的登录密码,然后按回车。
输入时不会显示字符,也不会显示星号,这是正常现象。 不用怀疑键盘,更不用多按几遍。
完成后,账号记录会写入 users.local。因为结果已经写进文件,所以终端没有再显示一大段内容也是正常的。
以后网页登录时使用:
- 用户名:
admin - 密码:刚才输入的密码
文件里保存的是密码哈希,不是明文密码。登录时填写自己设置的原始密码,不要复制文件中的哈希字符串。
另外,admin 只是示例用户名,这个名字本身不会赋予额外的系统管理员权限。你也可以改成:
./peerloom hash --name eson > users.local
上面两条首次创建命令选一条执行即可。
新增第二个账号
如果账号文件已经存在,希望再添加一个用户,应使用两个大于号:
./peerloom hash --name alice >> users.local
再根据提示输入 Alice 的密码即可。新增用户名应与现有账号不同。
这里一定要分清:
| 符号 | 效果 |
|---|---|
> |
覆盖文件,原有内容会被清空 |
>> |
在文件末尾追加,保留原有内容 |
首次创建用 >,新增账号用 >>。
少一个大于号,可能就把同事的账号一起“优化”掉了。
修改密码
当前通过账号文件维护用户。修改密码时,可以先备份:
cp users.local users.local.bak
然后为指定用户生成新的账号记录:
./peerloom hash --name admin
输入新密码后,终端会输出一整行新的记录。
打开 users.local:
nano users.local
找到以 admin: 开头的那一行,用刚生成的完整记录替换它,然后保存。
只替换目标用户那一行,保留其他账号。修改完毕后重启服务。
删除账号
同样先备份文件,再删除该用户对应的一整行,保存后重启。
账号文件在服务启动时读取,所以新增账号、修改密码和删除账号,都需要重启才能重新加载。重启也会影响正在进行的房间会话,尽量在没人使用时操作。
账号和访客有什么关系?
按照本文配置:
- 有账号的人登录后可以创建房间。
- 朋友收到房间链接后,可以以访客身份加入已经存在的房间。
- 不存在的房间不会因为访客打开链接就自动创建。
因此,不需要为每位临时参加讨论的朋友都创建账号。
06 · 启动服务,先确认程序跑起来
在项目目录运行:
./peerloom serve
serve 的意思是启动服务,开始接受浏览器连接。
如果配置正确,程序会持续运行,并在终端输出日志。
终端没有回到命令输入状态,不是卡住了,而是服务正在工作。
如果 Peerloom 就运行在你的电脑上,可以访问:
http://localhost:5050
如果程序运行在远程服务器上,你电脑里的 localhost 指的是你自己的电脑。远程使用需要访问服务器地址,正式使用则应配置下一节介绍的 HTTPS 域名。
此时按 Ctrl + C 可以停止服务。
这种启动方式适合首次检查。关闭终端或断开连接后,服务可能随之停止;需要长期运行时,再配置后面的后台服务。
07 · 公网访问:网页和音视频都要打通
让朋友通过互联网使用,还需要完成三件事:
- 将域名解析到服务器。
- 配置 HTTPS 和网页反向代理。
- 放通 TURN 和中继端口。

网络示意:网页走 HTTPS 和 WebSocket,媒体尝试直连,必要时通过 TURN 中继。
先配置域名和 HTTPS
例如准备使用:
https://meet.example.com
先在域名服务商处添加解析,让该域名指向服务器公网 IP,然后在服务器上配置对应的 HTTPS 证书。
浏览器使用屏幕共享、麦克风和摄像头等功能需要安全上下文。正式远程使用应配置 HTTPS,不要只停留在“公网 IP 加 HTTP 端口能打开页面”这一步。
如果通过服务器面板部署,可以创建网站、绑定域名、申请证书,并把反向代理目标设置为:
http://127.0.0.1:5050
这里假设反向代理和 Peerloom 运行在同一台服务器上。
反向代理要支持 WebSocket
Peerloom 的 /stream 连接需要支持 WebSocket。
如果使用 Nginx,可以在已经配置好域名和证书的 HTTPS server 块中,加入或调整下面的代理配置:
location / {
proxy_pass http://127.0.0.1:5050;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
}
这是代理部分的示例,不是包含证书设置的完整 Nginx 配置文件。使用面板时,应按面板提供的反向代理和 WebSocket 设置填写。
再放通网络端口
按照前面的配置,需要检查:
| 端口 | 协议 | 用途 |
|---|---|---|
443 |
TCP | HTTPS 网页访问 |
80 |
TCP | 按证书签发、HTTP 跳转方案需要开放 |
3478 |
TCP、UDP | 内置 TURN 服务 |
50000–50100 |
UDP | 本文示例设置的 TURN 中继端口范围 |
如果云服务器有安全组,同时系统启用了防火墙,需要两边都允许对应流量。
5050 是 Peerloom 网页服务端口。同机反向代理通过它连接程序时,通常不需要向公网开放;也可以将程序监听地址改为 127.0.0.1:5050,仅供同机代理访问。
如果服务器位于路由器后面,还需要配置相应端口映射。
特别注意:普通 HTTP 反向代理只能处理网页相关流量,不能代替 TURN 转发。
所以,“页面能打开,但别人看不到共享画面”,完全可能发生。网页和音视频需要分别验证。
08 · 让它在后台长期运行
首次启动检查通过后,Linux 服务器可以使用 systemd 管理 Peerloom,实现开机启动和进程异常退出后的自动重启。
下面假设:
- 程序目录是
/home/ubuntu/peerloom - 运行账号是
ubuntu - 服务器使用 systemd
请按实际情况修改路径和用户名,并确保该用户能读取配置与账号文件、执行程序。
如果之前还在终端运行 ./peerloom serve,先按 Ctrl + C 停止,避免两个进程争用端口。
创建服务文件:
sudo nano /etc/systemd/system/peerloom.service
写入:
[Unit]
Description=Peerloom collaboration server
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu/peerloom
ExecStart=/home/ubuntu/peerloom/peerloom serve
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
保存后执行:
sudo systemctl daemon-reload
sudo systemctl enable --now peerloom
第一条让 systemd 读取新配置,第二条启动服务并设置开机自动启动。
以后常用的命令如下:
# 查看运行状态
sudo systemctl status peerloom
# 重启服务:修改配置或账号后使用
sudo systemctl restart peerloom
# 停止服务
sudo systemctl stop peerloom
# 持续查看日志
sudo journalctl -u peerloom -f
查看日志时按 Ctrl + C,只是退出日志查看,不会停止后台服务。
至此,服务器终于可以自己上班了。
09 · 部署好了,怎么使用?
可以先用两台设备做一次完整测试:一台创建房间,另一台通过链接加入,再验证语音和画面。
第一步:登录并创建房间
打开部署好的 HTTPS 地址,使用前面创建的账号登录。

登录页实拍:输入通过 hash 命令创建的用户名和密码。截图未填写登录信息。
例如:
用户名:admin
密码:运行 hash 命令时设置的密码
按页面提示填写房间信息并创建。

创建房间实拍:填写房间号,并确认“你离开后关闭房间”选项。
创建时注意“房主离开时关闭房间”相关选项。如果启用,房主离开会影响房间里其他成员继续使用。
第二步:邀请朋友
创建成功后,将房间链接发给朋友。
对方打开链接,按页面提示填写昵称,即可作为访客加入已有房间。
如果提示房间不存在,请先确认房主已经创建房间,且房间尚未关闭。

成员列表实拍:展开右侧成员列表可以查看身份和在线状态;下方工具栏提供各项协作入口。
第三步:开启语音
通过工具栏开启麦克风,浏览器弹出权限请求时选择允许,并确认使用了正确的输入设备。
两台设备放在同一个房间测试时,建议佩戴耳机,避免声音来回播放产生回声。
第四步:共享屏幕
点击屏幕共享入口,浏览器会让你选择共享内容,例如整个屏幕、某个窗口或浏览器标签页。具体选项取决于浏览器和系统。
选中内容后确认共享,其他成员就可以在房间里看到画面。
结束时点击停止共享。语音与内容共享分开处理,结束画面共享后,仍可以继续聊天。
摄像头也可以通过工具栏开启。不过,同一位成员同时只能发布屏幕、摄像头或同播中的一种内容,切换时先结束当前内容。

设置面板实拍:可以查看首选编码、显示模式和帧率。初次使用可先保留默认设置。
第五步:一起写文档、画白板
打开“协作文档”,即可共同编辑房间里的文档。

界面截图:协作文档示例。上方是格式工具栏,下方可以共同整理讨论目标、安排和下一步事项。
可以记录:
- 本次讨论的目标。
- 发现的问题。
- 确认的解决方案。
- 接下来由谁做什么。
编辑器支持标题、加粗、斜体、列表、待办、引用和代码块等常用格式。
需要画流程、解释页面布局或梳理关系时,再打开协同白板。

白板实拍:在演示站用画笔绘制页面布局和确认流程,上方提供颜色、粗细、缩放和撤销等工具。
不需要画得专业,只要对方看得懂。毕竟是讨论方案,不是现场参加美术联考。
重要结论请及时复制或另行保存,房间协作内容不适合作为长期资料库。
第六步:一起看本地音视频
打开“同播”,可以选择电脑上的音频或视频文件。

界面截图:音视频同播的文件选择界面。点击“选择文件”,或者直接把文件拖入虚线区域,即可选择要分享的内容。
按顺序操作:
- 点击选择文件,或者将本地音频、视频拖入选择区域。
- 等待文件加载。
- 点击“开始同播”。
- 其他成员在房间主区域观看画面或收听音频。
- 分享结束后,点击“结束同播”。
这里有几个规则:
- 同一房间同时只能有一位成员发起同播。
- 暂停只是暂停播放,仍保留同播控制权。
- 想换一个人分享,需要先点击“结束同播”。
- 同播占用媒体席位,席位已满时需要先释放。
- 发起者正在共享屏幕或摄像头时,需要先结束当前内容。
- 文件能否播放、浏览器能否捕获媒体,取决于浏览器及媒体编码支持。
“暂停”和“结束同播”是两个不同操作。前者相当于“等一下”,后者才是“下一位”。
10 · 常见问题,先从这里找
遇到连接问题,可以先打开工具栏中的“连接状态”,查看房间连接、服务器请求和媒体状态。

连接状态实拍:本次截图时只有一位成员,尚未开启媒体,因此媒体路径显示“待检测”、码率为零。这张图展示面板信息,不代表已完成跨设备音视频连通测试。
| 遇到的问题 | 优先检查 |
|---|---|
./peerloom 提示文件不存在 |
是否在项目目录,编译是否成功 |
提示 Exec format error |
程序是否为当前系统和 CPU 架构编译 |
| 启动时提示账号文件读取失败 | PEERLOOM_USERS_FILE 路径是否正确、文件是否存在、运行用户是否有读取权限 |
| 新增账号后无法登录 | 是否使用 >> 追加,是否重启了服务,登录时是否输入原始密码 |
| 启动提示地址被占用 | 是否已经有 Peerloom 或其他程序占用了 5050、3478 |
| 页面能打开,但无法正常进入房间 | 检查房间是否存在,以及反向代理的 WebSocket 配置 |
| 麦克风或屏幕共享不可用 | 检查 HTTPS、浏览器权限和操作系统权限 |
| 成员能进房,但没有声音或画面 | 检查外部 IP、TURN 端口、中继 UDP 范围、安全组及端口映射 |
| 无法开始同播 | 检查是否有人正在同播、媒体席位是否已满、本人是否正在共享其他内容 |
| 本地文件无法播放 | 检查浏览器是否支持该文件的媒体编码,先用可正常播放的文件测试 |
| 关闭终端后网站不能访问 | 是否只用了前台启动,是否已经配置后台服务 |
| 修改前端后网页没有变化 | 是否重新构建前端、重新编译并替换程序、重启服务 |
排查时建议分三步:先确认程序启动,再确认网页和房间连接,最后检查音视频。
不要一上来把所有配置一起改掉,否则原本只有一个问题,很容易被调试成一套问题。
11 · 使用范围与后续更新
Peerloom 使用 WebRTC 传输媒体,并内置 TURN 服务。
网络条件允许时,成员之间可以直接传输;无法直接连接时,可以通过 TURN 中继。因此,实际体验与参与者网络、设备性能和服务器带宽都有关系。
当前媒体使用 WebRTC mesh 方式,人数增加时,客户端连接数量和带宽负担也会增加,更适合小范围讨论、远程演示和团队协作。
还有几点使用边界:
- 房间聊天不保存历史。
- 协作文档、白板的重要内容应及时另行保存。
- 屏幕、麦克风和摄像头需要浏览器及系统授权。
- 本地音视频同播能力取决于浏览器支持情况。
更新版本前,先备份自己的配置文件和账号文件。获取新版源码后,重新安装需要的依赖、构建前端、编译程序,再替换运行文件并重启服务。
具体参数和后续变动,以项目 README及当前版本源码为准。
Peerloom 基于 Screego 二次开发,感谢原项目及相关开源依赖的贡献者。项目保留 GPL v3 许可证,欢迎体验、提交 Issue,也欢迎参与改进。
结语:卷起来。毕竟,头发卷起来,显得发量多。
这个假期,休息得够不够不好说,至少以后找人一起看 Bug,不用再隔着聊天框描述“右边那个,再往上一点”了。
Thanks♪(・ω・)ノ 感谢你长得那么好看还来看我的博客!see you around ~
