yarn.social v0.16.0 Docker Compose 部署指南

yarnd v0.16.0 单服务 Compose 编排实录:国内加速源拉取、uid=1000 数据目录、store 绝对路径大坑排障、Setup 向导、登录发帖、PoW 注册第二用户、重启持久化、tar 备份与生产加固,全部命令输出实测回显。

yarn.socialDocker ComposeDocker自托管FediverseGo2026/11/02

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 网段冲突);
  • 数据目录:./data bind mount 进 /data,权限必须交给 uid=1000(官方镜像内 yarnd 以 uid/gid 1000 运行,README 明示 chown -R 1000:1000 /data)。

2. 环境要求

项目要求
OSLinux x86_64(实测 Debian 系,ARM64 官方镜像同样支持)
Docker20.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。按本次部署填写:

字段值
baseURLhttp://127.0.0.1:8129(生产填公网域名)
adminUser / adminPasswordadmin / q1w2e3r4(示例,生产换强口令)
podName / podDescriptionyarn.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 实体 &#43;,脚本化时必须先做实体解码,否则一律 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 feedhttp://127.0.0.1:8129/user/admin/twtxt.txttwtxt 头部 + twt 行
Prometheus 指标curl -sS http://127.0.0.1:8129/metricsyarnd_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-web31.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. 生产加固要点

  1. TLS:yarnd 内置 --tls(留空证书路径则走 Let's Encrypt 自动签发),或前置 Nginx/Caddy 反代——反代时务必把 -u 设为公网 https 地址,否则 feed 头部 URL 错误;
  2. 三密钥:COOKIE_SECRET/MAGICLINK_SECRET/API_SIGNING_KEY 默认值是字面量 INVALID CONFIG VALUE - PLEASE CHANGE THIS VALUE,官方 README 要求生产必须换 64 位随机值且只经环境变量注入;
  3. 注册策略:-R 开放 / -I 邀请制 / 默认关闭,配合 PoW 与蜜罐字段 pooh 防机器人;
  4. SMTP:SMTP_HOST/PORT/USER/PASS/FROM 决定密码找回与 /support、/abuse 邮件能力;
  5. 更多参数逐项含义见 《yarn.social v0.16.0 配置参数详解》。

15. 卸载

# cd /opt/yarn-social/deploy
# docker compose down
# rm -rf data    # 数据目录自行决定是否保留

16. 相关文档

yarn.social v0.16.0 Docker Compose 部署指南 - Quzuo