Parley 是一个联邦式、去中心化的聊天网络,使用普通 IRC。它没有中心,每个人或团队为自己域名运行小实例。实例通过 DNS 和 well-known 身份文档互相发现,经 HTTPS 交换签名消息,并把整个联邦网络呈现给 irssi、WeeChat、Textual 等普通 IRC 客户端,无需插件。身份像电子邮件:爱丽丝(Alice)在 foo.com 运行 alice@foo.com,鲍勃(Bob)在 bar.com 运行 bob@bar.com。鲍勃输入 /msg alice@foo.com hi 就能工作,即使两个实例此前从未听说过对方。目前是概念验证,尚未加固。
正文
Parley 是一个联邦化、去中心化、直接说标准 IRC 的聊天网络。它没有中心,每个人(或团队)为自己的域名运行一个小型实例。实例之间通过 DNS 和知名身份文档互相发现,通过 HTTPS 交换签名消息,并向普通的 IRC 客户端(如 irssi、WeeChat 或 Textual)呈现整个联邦网络,无需插件。
身份形如电子邮件:alice@foo.com 运行在 foo.com,bob@bar.com 在 bar.com。Bob 输入 /msg alice@foo.com hi 就能打通,即便两个实例此前互不相识。
状态:可用的概念验证。它端到端演示了设计并运行着真实实例,但尚不够健壮。参见局限。
它兼容你现有的客户端
两个实例(foo.com 和 bar.com),两个原版 irssi 会话。
Alice 连上她的实例;Bob 连上他的:


Bob 用 /msg alice@foo.com 开个私聊窗口,两个实例当场联邦化。Alice 看到 Bob 是 bar.com 上的 bob;Bob 看到 Alice 是 foo.com 上的 alice:


两人都加入 #lobby,一个跨实例复制的全局频道:


它的功能
- 前端是普通 IRC。 用任意 IRC 客户端连接,以
PASS或 SASL PLAIN 用密码或 IRC 令牌登录。向需要的客户端提供 IRCv3 的server-time、message-tags、echo-message、multi-prefix和setname;TAGMSG转发客户端专属标签(如输入指示),跨联邦及本地客户端间均如此。消息上的标签会保留,因此+reply从历史中出来仍是回复,draft/multiline让粘贴的段落算一条消息而非八条。 - 随你而非客户端走的滚动回溯。
CHATHISTORY可翻看频道和私信;加入时重放未读内容;draft/read-marker把已读位置存在账号上,手机标已读会清掉桌面端,客户端一加入就知从哪画线。 - 运行中可管理的账号。 账号存于实例数据目录而非配置文件。用
parleyctl、管理页、HTTP API 创建,或让用户经单点登录到来:任何 OpenID Connect 提供者,或反向代理传来的身份头。人们在设置页为客户端生成 IRC 令牌;机器人是带bot角色的账号。 - 通过 DNS + WKID 发现。
_parley._tcp.<domain>SRV 指向实例;https://<host>/.well-known/parley/instance.json发布 ed25519 公钥和收件箱;/.well-known/parley/<user>.json确认用户存在。这镜像了 Salty IM 找人的方式。 - 签名的 HTTP 联邦。 每个事件是个 JSON 文档
POST到对端/inbox,头部带分离的 ed25519 签名。接收方用自己发现的密钥验证。联邦是开放的:任何签名通过的实例都能与你通信。 - 自动配对。 给新域名的某人发消息,两实例自行链接。链接的实例交换已知的 peers(gossip),无需配置即形成网格。
- 两类频道。
#dev是全局的,在有成员的每个链接实例间复制。无人拥有它,故无主题无管理员。¬es是本地的:不出实例,对 peers 不可见,是唯一能有主题的地方。
- 无频道所有权的审核。 没人能被踢出无人拥有的频道,故
/ban变成按掩码封锁:/ban quark@example.com禁一人,/ban *!*@example.com禁整个实例。你的封锁覆盖账号;管理员的覆盖实例。配对本身用parleyctl peers控制。 - 地址映射到普通 IRC 身份。 用户昵称是本地部分,实例是主机,故 alice 显示为
alice!alice@foo.com——前缀、NAMES、WHO、WHOIS一致,在NAMES看到的昵称即可私聊。/whois alice@foo.com查她实例的 WKID 文档。 - 挺过停机且可搜索的历史。 每实例将频道历史存于带全文索引的 SQLite(
parleyctl search),并在/channels/<name>/feed提供。peer 停机恢复后拉取遗漏,客户端JOIN时重放近期历史。
快速起步(同机两实例,无 DNS)
在两个终端中运行实例:-insecure 和 -resolve 仅用于本地开发。生产环境每个实例有真实域名、TLS 证书、SRV 记录,并经 DNS 找 peers。
真实环境:DNS + TLS 演示
demo/ 拉起 CoreDNS(权威解析 foo.com 和 bar.com,带 _parley._tcp SRV 记录)、本地演示 CA 和两个 Docker 实例,然后跑脚本化 IRC 会话并打印证据。见 demo/README.md。
运行你自己的实例
容器镜像是 prologic/parley,docker-compose.example.yml 是起点。为 example.com 服务、可达 chat.example.com 的实例需要:
- 运行之处,持久存储挂
/data(存实例密钥、peer 缓存、频道日志和账号)。然后用parleyctl(镜像里也有)或管理页建账号。无管理员令牌且尚无账号时,parleyd 会打印一次性/setupURL 在浏览器建首个管理员。经 OpenID Connect 或反向代理身份头的单点登录见 docs/AUTH.md;SSO 用户在设置页为客户端生成 IRC 令牌。 chat.example.com的 8443 端口前做 HTTPS。 任意终止 TLS 的反向代理均可;不给-tls-cert和-tls-key的话 parleyd 只服明文 HTTP。- 一条 SRV 记录让别的实例找到你。没有则 peers 回退到
https://example.com/.well-known/parley/。 - 给客户端的 IRC over TLS。 parleyd 的 IRC 监听是明文,故前边终止 TLS。例如在 Caddy 的 layer4 模块终止后,于 irssi 中:
/connect -tls -tls_verify chat.example.com 6697 <password-or-token> alice。端口是代理听的端口;若非 6697,用-irc-port(及-irc-host)启动,或设PARLEY_IRC_PORT/PARLEY_IRC_HOST。着陆页、设置页、parleyctl和实例文档都打印连接行,设置页还打印活令牌。正确主机名下的错端口仍过证书验证,令牌会发往那里监听的别的进程。 - 从外部检查。
parleyctl check像 peer 那样探测实例——SRV 记录、知名文档、广告端点、收件箱和 IRC TLS 端口——并说怎么修。无需令牌,对任意实例可用,故也可用来告诉 peer 它哪错了。常见失败是缺 SRV 记录:实例自身主机完全可达,但解析身份域的谁都找不到它。加-resolve https://chat.example.com在 DNS 仍错时直探主机,-json出机读报告。任一项失败则非零退出。
它如何拼合
- Bob 客户端发
PRIVMSG alice@foo.com :hi。 - bar.com 查
_parley._tcp.foo.com,从所指主机取实例文档,缓存密钥。 - bar.com 签事件并
POST到 foo.com 收件箱。 - foo.com 同样发现 bar.com 验证签名,把消息递给 Alice 客户端,因 bar.com 是生客,回个
hello。双方交换频道名册和 peer 列表。
线格式见 docs/PROTOCOL.md。
配置
无配置文件。配置在两处,各物各居其一。
标志,各有环境变量,用于进程开库前所需、描述机器网络、及身份断言的密钥信任决策。标志优先于变量。仅 -domain 必填。
| 标志 | 环境变量 | 含义 | 默认 |
| --- | --- | --- | --- |
| -domain | PARLEY_DOMAIN | 本实例服务的身份域 | 必填 |
| -data | PARLEY_DATA_DIR | 身份密钥、数据库、peer 和成员状态 | ./data |
| -endpoint | PARLEY_ENDPOINT | 广告基 URL | https://<domain> |
| -irc | PARLEY_IRC_LISTEN | IRC 监听(明文;前终止 TLS) | :6667 |
| -http | PARLEY_HTTP_LISTEN | Web UI、发现、收件箱、feed 的 HTTP(S) 监听 | :8443 |
| -irc-host, -irc-port | PARLEY_IRC_HOST, PARLEY_IRC_PORT | 客户端经 TLS 达 IRC 处 | 端点主机, 6697 |
| -tls-cert, -tls-key | PARLEY_TLS_CERT, PARLEY_TLS_KEY | 直接服 HTTPS | 关 |
| -admin-token | PARLEY_ADMIN_TOKEN | 管理 API 和 parleyctl 的承载令牌 | 关 |
| -admin (可重复) | PARLEY_ADMINS | 不论存储角色均为管理员的昵称 | 无 |
| -seed (可重复) | PARLEY_SEEDS | 启动即链的 peer 域 | 无 |
| -irc-proxy (可重复) | PARLEY_IRC_PROXIES | 允许给 IRC 连接前加 PROXY 头的 CIDR | 无 |
| -http-proxy (可重复) | PARLEY_HTTP_PROXIES | Web 监听信 X-Forwarded-For 的 CIDR | 无 |
| | PARLEY_TRUSTED_PROXIES 等 | 来自列代理的身份头(见 docs/AUTH.md) | 关 |
| | PARLEY_OIDC_* | OpenID Connect 提供者(见 docs/AUTH.md) | 关 |
| | HAVEN_SOCKET | 家用云应用套接字做家庭同步 | 关 |
| -ca, -insecure, -resolve, -debug | PARLEY_DEBUG | 本地开发 | 关 |
设置,在数据库中,给管理员运行时可能改的一切。保存即刻生效无需重启,无标志无变量。在管理页、PUT /api/v1/settings(见 docs/API.md)或 parleyctl 改:
| 设置 | 含义 | 默认 |
| --- | --- | --- |
| motd | 每日消息(空为内置文本) | 内置 |
| history_replay | JOIN 重放消息数(频道私信同)、登录未读私信、同账双客户端 Backlog | 50 |
| history_retention | 历史保留时长(-1 永久) | 8760h |
| message_rate, message_burst | 每账发言限:每秒消息数、瞬时数。0 不限。机器人豁免 | 1, 20 |
| max_conns | 实例并发 IRC 连接(-1 无限) | 1024 |
| max_conns_per_account | 每账并发 IRC 连接(-1 无限) | 8 |
| max_conns_per_addr | 每客户端地址并发 IRC 连接(0 关) | 0 |
| federation.policy | open,或 allowlist 仅邀联邦 | open |
| federation.inbox_rate, federation.inbox_burst | 每 peer 每地址收件箱投递 | 20, 200 |
| federation.feed_rate, federation.feed_burst | 每地址 feed 读 | 2, 20 |
| federation.catch_up_window | 重连实例回溯请求时长 | 168h |
| auth.local | 显用户名密码登录框 | true |
| auth.auto_link | 首次 SSO 登录可认领未链本地昵称 | true |
| auth.session_ttl | Web 登录寿命 | 720h |
| auth.rate_limit.* | 登录限流(见 docs/AUTH.md) | 开 |
| metrics_public | 免验证服 /metrics | false |
| network_name | 实例自称(空为 IRC 域、Web 为 Parley) | 空 |
| theme_color | 手机浏览器栏色 #rrggbb | 内置 |
| operator | 运营者,Web 页脚显 | 空 |
人们于 Web 界面设置头像,或登录时取自身份提供者的 picture 声明并转存此处。它作为 IRCv3 avatar 元数据键发客户端,并于知名用户文档发他实例;见 docs/PROTOCOL.md。
实例徽标不在此表,因非文本:于管理页设置 -> 徽标传至少 512 像素边长 PNG,Parley 派生 favicon、主屏图标和 IRC 客户端显于网络旁的方块。方图最佳,字标亦可——长宽比达 3:1 内居中于透明方而非拒。此前每实例显 Parley 自身图标,故客户端网络列表里俩像。
聊天帮助。 /help(或 /quote HELP <topic>)服 help/*.txt 页,编入二进制。改页重编即变;首行是标题。新文件即新主题——列于 help/index.txt,make test 查。
端点:/healthz 活探针,/api/v1/status JSON 状态(peers 频道),/metrics 给 Prometheus,API 见 docs/API.md。
从配置文件升级。 parleyd -config config.json 不再读文件:它打印文件中每键已成之标志、变量或设置并退出。进程级键移单元或 compose 文件,启实例,再 parleyctl settings import config.json 一气应用余下并名列跳过。
TCP 代理后的真实客户端地址
IRC 监听前终止 TLS 时,每客户端皆来自代理:日志记错主机,每地址限要么无效要么锁所有人。于 irc_proxies 列代理,其须给每连接前加 PROXY 协议头(v1 或 v2)。
这是两处改动,单改皆败。 列不发头的代理弃其所有连接;从未列地址发头来则当垃圾喂 IRC 解析。无安全顺序,故同改且备回退。默认空即全关;填你连接真达之地址,而非 127.0.0.1/32 示例。PARLEY_TRUSTED_PROXIES 是 Web 监听等价物,全然不同决策。
找要列的地址,连一次读日志,每客户端地址首见即报。代理后每客户端共一地址,故单行正名 irc_proxies 所填;永远是套接字地址,非头载地址。代理列且发头后,行重显带 trusted_proxy=true,即两半已合确认。仅列地址受信,其无头连接弃而非当直连——同处受两形等于交还头本阻之地址伪造。此弃计于 parley_irc_proxy_rejected_total,改动时盯此指标。
Web 监听同盲有己设。反向代理后每请求皆来自它,故 Web 登录、联邦收件箱、feed 读之每地址闸共享一桶。列于 http_proxies 则信其 X-Forwarded-For,余不变。用此而非 auth.trusted_headers.proxies,其似可为之却做过头:列上代理可断言用户是谁,带 Remote-User 的 /login 请求免密登。修限流无理由开免密登。身份表隐含地址表,因信至此的代理无需疑地址。逐步版含省一次故障的顺序见 docs/PROXY.md。
得真地址后 max_conns_per_addr 可安全开,开亦将每地址登录桶用于 IRC。未列代理后监听时留 0:客户端共一址,cap 不限特定人反锁所有人。是设置,故 parleyctl settings set max_conns_per_addr 8 开无需重启。每账登录退避两路皆用——见 docs/AUTH.md。
指标
/metrics 服 Prometheus 文本格式:连接、在线账号、频道、链 peers、推送/收件箱事件/feed 读/标签消息/拒收计数器。默认需管理员令牌,因实例人数属运营者事;设 metrics_public 公开服。每样本皆计数——无昵称、无频道名、无 peer 域。
备份实例密钥
<data_dir>/identity.key 是唯一不可再生文件。域身份即密钥对:失之则缓存旧公钥的每 peer 拒实例,唯换新密钥人人重信可修。主机备、离机备。
密钥泄露,换之是受支操作非灾:peers 自恢复。验不通的签名令其重读实例文档一次,即见新公钥,故代价每 peer 一失败请求——若请求是 hello,退避数分再试。旧密钥存 identity.key.<fingerprint>.bak,因唯不可挽回之错是换仍须之钥。后重启 parleyd 服新钥。此直读写数据目录而非经 API,因管理员令牌永不可经网取私钥。于实例主机带 -data-dir 或 PARLEY_DATA_DIR 跑。
升级
无须跑:数据库首启得新表,旧表不动。下述少变,新先。
至 v0.6.0
每账发言现已受限。 message_rate(每秒 1)和 message_burst(瞬时 20)施于除机器人外所有人,按账计,故一人客户端共享预算。拒收消息答 439 指目标且不达。此前实例全无限,故若屋更忙,调大或 message_rate 设 0(旧行为)。是设置,落而无重启。
至 v0.5.0
他实例某人乃 alice:foo.com,非 alice/foo.com。 分隔符借自 draft/relaymsg,错抄半 conventions:严客户端要求昵名有 . 和 : 或皆无方防误作服务名,带域之名有点无冒。此客户端读整前缀为服务名,弃远端用户每 JOIN、PART、QUIT、NICK、AWAY,而 PRIVMSG 静降——故聊天正常名单从不更。ISUPPORT 中 PARLEYSEP 示所用符,机器人应读此非硬编。升级中途网络陷阱:提及文本作字节跨联邦,仍用 / 的 peer 打 alice/foo.com 在其未升级前不匹配,告 peer 莫令自寻。
发往早于 v0.5.0 peer 的反应丢非排队。 那些版对未实现事件类答 422,拒绝对发送者发件箱终局:事件弃且告发失败。自 v0.5.0,未实现类答 200 {"unsupported": true},故此为唯须待全网格毕之变。此间反应及升级实例间不受影响。
GET /api/v1/status 不再发频道名册。 唯免验证端点,曾命每全局频道每成员——含代 peer 用户,而其着陆页只计数从不名。频道仍带 name、成员 members 数及 on(他有成员的他域)。联邦无读此:peers 于签名 hello 快照交成员。
history_replay 现默认 50,原 20。 仅未设之设随默认,故已选数者留。
自带 -user 或 PARLEY_USERS 的版
那些没了。启新版,后导旧列表一次。
项目布局
make test 跑进程内端到端场景,覆全局本地频道、自链私信、peer 交换、停机追、签名拒及 IRC 基础。
局限
已知缺口,大致按应闭序:
- 仅实例级密钥。每用户密钥和端到端加密(Salty 风)可叠上。
- 无频道模式和频道管理员,乃决策非缺口:全局频道无人有,故无管理员。封锁按人和实例——见上
/ban。 - 昵称绑账号;无
/nick。 - 全局频道最终一致且无主题权。
- feed 免验证服(像 twtxt 公开日志)。
- 故意无 Web 聊天客户端。Web 界面管配实例;聊是客户端事,Parley 乃每 IRC 客户端已谈之服。
路线点子
- 经 WKID 发的每用户密钥,含加密私信。
- 更多 IRCv3 客户端可渲者:消息撤回,及余用户元数据注册。
许可
MIT,见 LICENSE。
评论
社区对该去中心化IRC联邦项目抱有兴趣,但普遍担忧垃圾邮件与治理缺陷,并分歧于是否重复发明了XMPP等现有协议。
认为这是联邦化即时通讯的有趣尝试
- 多人表示喜欢将电子邮件式联邦架构用于IRC客户端,认为降低了使用门槛(较多人) > 这就像专门为即时通讯设计的电子邮件(@shreddit)
担忧垃圾邮件和机器人滥用将成为隐患
- 不少评论指出无中心架构会让反垃圾邮件工具难以复用,且可能便利自动化机器人潮(较多人) > 这既酷又令人担忧地便利了我们曾被警告的机器人潮(@padolsey)
质疑项目重复造轮子且未借鉴XMPP等标准
- 有人认为其本质是XMPP的粗糙子集,开发者因LLM辅助而脱离现有生态;另有人建议直接基于atproto等联邦网络构建以避免新账户(较多人) > 这基本是XMPP一半的糟糕实现,仓库里没提现有工作(@Conlectus)
对全局房间治理与网络稳定性的怀疑
- 少数人指出跨实例全局房间会导致持续网裂且只能由服务器管理员封禁,违背IRC开放但封闭的特性(少数人) > 房间在已知实例间全局同步,岂不是永远陷入网裂,只有管理员能禁人?(@singpolyma3)
有价值的补充
- 有开发者计划一天内在面向代理的IRC服务器 airc 中实现该思路,显示社区动手意愿。
- 有用户曾规划类似系统时区分仅本地聊天与全局订阅聊天,以兼顾隐私与联邦,虽未实现但提供架构参考。
- 使用 & 频道等历史IRC特性可能让许多旧版客户端和机器人崩溃,提示兼容性风险。