yarn.social v0.16.0 Docker Compose 部署指南
yarnd v0.16.0 单服务 Compose 编排实录:国内加速源拉取、uid=1000 数据目录、store 绝对路径大坑排障、Setup 向导、登录发帖、PoW 注册第二用户、重启持久化、tar 备份与生产加固,全部命令输出实测回显。
yarn.social v0.16.0 Docker Compose 部署指南
本文在真实服务器上以 Docker Compose 部署 Yarn.social Pod 服务器 yarnd v0.16.0(构建串 yarnd 0.16.0@1e81cc4e 2026-07-13T14:54:06+10:00 go1.26.5),覆盖镜像获取、编排文件、初始化向导、账号体系、功能验收、持久化与备份的完整闭环。文中所有命令与输出均为实测回显,逐行照抄。yarnd 无外部数据库依赖(内嵌 Bitcask),编排只有一个服务,这是它与 Mastodon 系部署最大的体感差异。
延伸阅读:《yarn.social v0.16.0 介绍与选型指南》
1. 部署架构与端口规划
主机 :8129 ──> yarnd :8000 ──> ./data(Bitcask + feeds 纯文本 + config.yml)
└── 独立 bridge 网络 10.89.56.0/24
- 应用监听端口:yarnd 默认
-b 0.0.0.0:8000,主机侧映射到 8129; - 专用网络:
10.89.56.0/24(显式指定 subnet,避免与主机既有 Docker 网段冲突); - 数据目录:
./databind mount 进/data,权限必须交给 uid=1000(官方镜像内 yarnd 以 uid/gid 1000 运行,README 明示chown -R 1000:1000 /data)。
2. 环境要求
| 项目 | 要求 |
|---|---|
| OS | Linux x86_64(实测 Debian 系,ARM64 官方镜像同样支持) |
| Docker | 20.10+(含 compose v2 插件) |
| 内存 | ≥256MB 可用即可(实测空闲 Pod 常驻约 31MiB) |
| 磁盘 | ≥1GB(feed 为纯文本,增长极慢) |
| 出网 | 拉取镜像;Pod 上线后需主动抓取关注源(pull 模型) |
3. 获取镜像(含国内网络实况)
官方镜像为 Docker Hub prologic/yarnd(README 标注 AMD64/ARM64 双平台)。国内直连 Docker Hub 被重置,实测走加速源的完整过程:
第一个候选源 daocloud 直接拒绝——该镜像不在其白名单:
# timeout 150 docker pull docker.m.daocloud.io/prologic/yarnd:latest
Error response from daemon: error from registry: 🚫 👀-> https://github.com/DaoCloud/public-image-mirror/issues/2328 🔗 这镜像不在白名单. this image is not in the allowlist.
改用 docker.1ms.run 成功:
# timeout 420 docker pull docker.1ms.run/prologic/yarnd:latest
latest: Pulling from prologic/yarnd
Digest: sha256:4e7873cb4c34d13d030e4979a96464ddb0c7a354add370c2a6c5c1c2a55e3e14
Status: Downloaded newer image for docker.1ms.run/prologic/yarnd:latest
docker.1ms.run/prologic/yarnd:latest
核对体积并打上官方引用名,便于 compose 直接写 prologic/yarnd:latest:
# docker images --format '{{.Repository}}:{{.Tag}} {{.Size}}' | grep -i yarnd
docker.1ms.run/prologic/yarnd:latest 249MB
# docker tag docker.1ms.run/prologic/yarnd:latest prologic/yarnd:latest
查看镜像自报版本(入口为 s6-overlay 的 /init,默认 CMD 为 yarnd):
# docker run --rm --entrypoint /usr/local/bin/yarnd prologic/yarnd:latest --version
2026-11-02 10:38:07 INFO memory is not limited, skipping package=github.com/KimMachineGun/automemlimit/memlimit
yarnd 0.16.0@1e81cc4e 2026-07-13T14:54:06+10:00 go1.26.5
排障实录①:若守护进程配置的 registry-mirror 链中某个源对"已发起的同一镜像引用"响应缓慢,
docker pull会整条链路挂起且无进度输出(实测默认引用prologic/yarnd:latest挂起 3 分钟以上)。处置:ps aux | grep 'docker pull'找到残留进程 kill 掉,再显式指定可用加速源引用拉取,成功后docker tag归一。
4. 目录规划
# mkdir -p /opt/yarn-social/deploy/data
# cd /opt/yarn-social/deploy
# chown 1000:1000 data
5. 编排文件
docker-compose.yml(完整实测文件):
name: yarn-social-v0.16.0-stack
services:
yarnd:
image: prologic/yarnd:latest
container_name: yarn-v0.16.0-web
restart: unless-stopped
command:
- yarnd
- -d
- /data
- -s
- bitcask:///data/yarn.db
- -n
- yarn.local
- -u
- http://127.0.0.1:8129
- -R
- -O
- --cookie-secret
- ${YARN_COOKIE_SECRET}
- --magiclink-secret
- ${YARN_MAGICLINK_SECRET}
- --api-signing-key
- ${YARN_API_SIGNING_KEY}
ports:
- "8129:8000"
volumes:
- ./data:/data
networks:
- yarn-net
networks:
yarn-net:
driver: bridge
ipam:
config:
- subnet: 10.89.56.0/24
参数要点(详解见配置篇):
-s bitcask:///data/yarn.db必须用绝对路径(见第 6 节排障);-R开放注册、-O开放主页,供后续注册第二用户;生产可按需关闭;- 三个
*_SECRET为生产必备(官方 README:非 debug 模式 MUST 配置),用.env注入,值生成方式:
# cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 64 | head -n 1
9oawILICDTBIj4GdUcq141FE7WLQqslPzrzJcCDInZwTI2NZ3JW4qG9E2ndn2dkl
.env(与 compose 同目录,权限 600,勿入版本库):
YARN_COOKIE_SECRET=<上面生成的 64 位随机串>
YARN_MAGICLINK_SECRET=<同上,另生成一个>
YARN_API_SIGNING_KEY=<同上,另生成一个>
排障实录②:compose 会把项目名中的点号规范化掉——
name: yarn-social-v0.16.0-stack实际生效为yarn-social-v0160-stack,网络名随之变为yarn-social-v0160-stack_yarn-net。写清理脚本或运维手册引用项目名时以docker compose ls实际输出为准。
6. 首次启动与 store 路径排障
# docker compose up -d
Network yarn-social-v0160-stack_yarn-net Created
Container yarn-v0.16.0-web Creating
Container yarn-v0.16.0-web Created
Container yarn-v0.16.0-web Started
# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
yarn-v0.16.0-web prologic/yarnd:latest "/init yarnd -d /dat…" yarnd 6 seconds ago Restarting (1) 1 second ago
状态是 Restarting,看日志:
# docker logs yarn-v0.16.0-web | tail -5
time="2026-11-02T10:48:40Z" level=info msg="using data directory for storage" cache_db=/data/cache.db data_dir=/data
time="2026-11-02T10:48:40Z" level=info msg="data directory owner" data_dir=/data gid=1000 uid=1000
time="2026-11-02T10:48:40Z" level=warning msg="error loading peering state" error="open /data/peers.json: no such file or directory"
time="2026-11-02T10:48:40Z" level=error msg="error creating store" error="mkdir yarn.db: permission denied"
time="2026-11-02T10:48:40Z" level=fatal msg="error creating server" error="mkdir yarn.db: permission denied"
排障实录③(本部署最关键的一坑):
-s bitcask://yarn.db这种相对路径的 store 会被解析到进程工作目录(镜像 WORKDIR 为/),而不是-d指定的数据目录,于是以 uid=1000 运行的进程试图在根目录mkdir yarn.db,权限拒绝、崩溃重启循环。而镜像默认 CMD(不显式传-s)时 store 落在/data/yarn.db,两种行为不一致,极易误判为挂载权限问题。官方 README 的配置示例-s bitcask:///path/to/data/twtxt.db用的正是三斜杠绝对路径。处置:改为bitcask:///data/yarn.db,清空半成品数据目录后重建。
# docker compose down
# rm -rf data && mkdir -p data && chown 1000:1000 data
# docker compose up -d
Container yarn-v0.16.0-web Starting
Container yarn-v0.16.0-web Started
# docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
yarn-v0.16.0-web prologic/yarnd:latest "/init yarnd -d /dat…" yarnd 7 seconds ago Up 6 seconds (health: starting) 0.0.0.0:8129->8000/tcp, [::]:8129->8000/tcp
启动日志确认关键信息(节选):
time="2026-11-02T10:49:15Z" level=info msg="serving metrics endpoint at http://127.0.0.1:8129/metrics"
time="2026-11-02T10:49:15Z" level=info msg="Instance Name: yarn.local"
time="2026-11-02T10:49:15Z" level=warning msg="No TLS configured"
注意 metrics 端点直接按 -u 的 base URL 打印,说明基础 URL 已生效。
7. 完成 Setup 向导
yarnd 首次启动无 config.yml 时,所有页面 302 到 /setup:
# curl -sS -D- -o /dev/null http://127.0.0.1:8129/ | grep -i location
Location: /setup
浏览器打开 http://<主机IP>:8129/setup,表单字段:baseURL、podName、podDescription、adminUser、adminPassword(两次确认)、dataPath、storePath。按本次部署填写:
| 字段 | 值 |
|---|---|
| baseURL | http://127.0.0.1:8129(生产填公网域名) |
| adminUser / adminPassword | admin / q1w2e3r4(示例,生产换强口令) |
| podName / podDescription | yarn.local / Yarn.social 测试 Pod |
| dataPath / storePath | /data / bitcask:///data/yarn.db |
提交成功后向导把实例配置写入数据目录(密码进库、不进文件):
# cat data/config.yml
base_url: http://127.0.0.1:8129
admin_user: admin
data: /data
store: bitcask:///data/yarn.db
pod_name: yarn.local
pod_description: Yarn.social 测试 Pod
setup_complete: true
8. 登录与第一条 twt
Web UI 登录 admin 后,首页即发帖框(表单 POST /post,字段 text)。用 curl 走同一表单验证(htmx 页面里 CSRF 值含 HTML 实体 +,脚本化时必须先做实体解码,否则一律 400):
LOGIN: HTTP/1.1 302 Found -> /
POST: HTTP/1.1 302 Found -> /
twtxt 协议的核心验证——feed 就是一个纯文本文件。twtxt.txt 尾部实测回显:
# curl -sS http://127.0.0.1:8129/user/admin/twtxt.txt
# Twtxt is an open, distributed microblogging platform that
# uses human-readable text files, common transport protocols,
# and free software.
#
# Learn more about twtxt at https://github.com/buckket/twtxt
#
# This is hosted by a Yarn.social pod yarn.local running yarnd 0.16.0@1e81cc4e 2026-07-13T14:54:06+10:00 go1.26.5
# Learn more about Yarn.social at https://yarn.social
#
# nick = admin
# url = http://127.0.0.1:8129/user/admin/twtxt.txt
# avatar = http://127.0.0.1:8129/user/admin/avatar
# description =
#
# following = 1
##
# follow = admin http://127.0.0.1:8129/user/admin/twtxt.txt
2026-11-02T10:49:38Z Hello yarn.social from compose 🧶
数据目录里同名文件逐字节一致(这就是"数据可带走"的实物):
# cat data/feeds/admin
2026-11-02T10:41:20Z Hello from yarn.social test pod 🧶
排障实录④:
/user/admin.txt形态的 URL 返回Feed Not Found。yarnd 0.16.0 的 raw feed 路径是/user/<nick>/twtxt.txt,可从/user/<nick>/的 JSON 里URI字段确认,勿沿用老版 twtxt 服务的.txt直觉路径。
9. 注册第二个用户(PoW 防滥用实录)
开放注册(-R)下访问 /register,表单除 username/email/password/passwordConfirm/agree 外,还有五个隐藏工作量证明字段与一个蜜罐:
# curl -sSL http://127.0.0.1:8129/register | grep -oE 'name="(pow_[a-z]+|pooh)" value="[^"]*"'
name="pow_challenge" value="005a773a6279a550c45187234a54ee1a"
name="pow_timestamp" value="1793616913"
name="pow_signature" value="2896de6100e7fec20aed9d5112d63c6b114f68e083d172579ca7d06ffc8ec797"
name="pow_difficulty" value="16"
name="pow_nonce" value=""
浏览器由前端 JS 自动求解(sha256(pow_challenge + nonce) 摘要需以 difficulty 个 0 比特开头);脚本化注册时自行求解 nonce 即可:
nonce solved: 194318 difficulty: 16
REGISTER: HTTP/1.1 302 Found -> /login
随后以新用户 root(密码 q1w2e3r4,示例账号)登录发帖同样 302 成功:
# curl -sS http://127.0.0.1:8129/user/root/twtxt.txt | tail -1
2026-11-02T10:55:52Z root 用户的第一条 twt
10. 功能验收清单
| 检查项 | 命令/入口 | 实测结果 |
|---|---|---|
| 首页时间线 | curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1:8129/ | 200(向导完成后) |
| raw feed | http://127.0.0.1:8129/user/admin/twtxt.txt | twtxt 头部 + twt 行 |
| Prometheus 指标 | curl -sS http://127.0.0.1:8129/metrics | yarnd_cache_feed_fetch_duration_seconds{quantile="0.5"} 0.001065749 等 |
| 后台任务 | 启动日志 | UpdateFeeds (@every 5m)、RotateFeeds (0 0 1 * *)、SyncStore (@every 1m) 等 6 项 |
| 资源占用 | docker stats --no-stream yarn-v0.16.0-web | 31.67MiB / 15.57GiB (0.20%),PIDS 9 |
11. 重启与持久化
# docker compose restart
Container yarn-v0.16.0-web Started
# curl -sS -o /dev/null -w 'GET / after restart: %{http_code}\n' http://127.0.0.1:8129/
GET / after restart: 200
重启后不再进向导(config.yml 的 setup_complete: true 生效),数据目录完整结构:
# ls -la data/
total 408
-rw-r--r-- 1 yahui yahui 4096 Nov 2 18:49 cache.db
-rw-r--r-- 1 yahui yahui 32768 Nov 2 18:49 cache.db-shm
-rw-r--r-- 1 yahui yahui 346112 Nov 2 18:49 cache.db-wal
-rw------- 1 yahui yahui 175 Nov 2 18:49 config.yml
drwxr-xr-x 2 yahui yahui 4096 Nov 2 18:49 feeds
-rw-r--r-- 1 yahui yahui 3 Nov 2 18:49 followers.json
-rw-r--r-- 1 yahui yahui 5 Nov 2 18:49 peers.json
-rw-r--r-- 1 yahui yahui 18 Nov 2 18:49 websub.json
drwx------ 2 yahui yahui 4096 Nov 2 18:49 yarn.db
各文件含义:cache.db* 关注源抓取缓存(SQLite);feeds/ 每个用户一个纯文本 feed;yarn.db/ Bitcask 主存储(用户/会话/twt 索引);peers.json/followers.json/websub.json 对等与订阅状态。
排障实录⑤:Bitcask 对数据目录加文件锁,同一
data目录被第二个实例启动时直接error: database locked并 fatal 退出。误以为进程残留时可用fuser -v data/yarn.db/*定位持锁 PID;正常运维中严禁两套编排指向同一数据目录。
12. 备份与恢复
官方 README 强调"务必定期备份数据目录,tar + scp 就够"。实测:
# tar czf yarn-backup-$(date +%F).tar.gz data
# ls -la yarn-backup-2026-11-02.tar.gz
-rw-r--r-- 1 root root 10118 Nov 2 18:56 yarn-backup-2026-11-02.tar.gz
# tar tzf yarn-backup-2026-11-02.tar.gz | head -8
data/
data/cache.db
data/cache.db-shm
data/websub.json
data/followers.json
data/feeds/
data/feeds/root
data/feeds/admin
恢复:停服务 → 解压回原位 → chown -R 1000:1000 data → 起服务。因 feed 是纯文本,单用户迁移甚至只需拷走 data/feeds/<nick> 文件。
13. 升级
# docker compose pull # 国内环境同第 3 节,需走加速源再 docker tag
# docker compose up -d
yarnd 0.16.0 启动时自动做 schema/数据迁移;升级前先做一次第 12 节的 tar 备份。
14. 生产加固要点
- TLS:yarnd 内置
--tls(留空证书路径则走 Let's Encrypt 自动签发),或前置 Nginx/Caddy 反代——反代时务必把-u设为公网 https 地址,否则 feed 头部 URL 错误; - 三密钥:
COOKIE_SECRET/MAGICLINK_SECRET/API_SIGNING_KEY默认值是字面量INVALID CONFIG VALUE - PLEASE CHANGE THIS VALUE,官方 README 要求生产必须换 64 位随机值且只经环境变量注入; - 注册策略:
-R开放 /-I邀请制 / 默认关闭,配合 PoW 与蜜罐字段pooh防机器人; - SMTP:
SMTP_HOST/PORT/USER/PASS/FROM决定密码找回与/support、/abuse邮件能力; - 更多参数逐项含义见 《yarn.social v0.16.0 配置参数详解》。
15. 卸载
# cd /opt/yarn-social/deploy
# docker compose down
# rm -rf data # 数据目录自行决定是否保留