Pleroma 2.11.0 Docker Compose 部署指南
Ubuntu 24.04 用 Docker Compose 部署 Pleroma 2.11.0 全纪实:官方 registry 制品路线、两服务栈编排、入口脚本迁移实录、Web/Nodeinfo/OAuth 发贴闭环验证,含 Docker Hub 鉴权墙、redirect_uris 复数参数、HTTPS 出厂假设等 7 条排障实录,全部回显 2026-11-02 实测。
Pleroma 2.11.0 Docker Compose 部署指南
本文在 Ubuntu 24.04.5 上用 Docker Compose 以官方镜像路线部署 Pleroma 2.11.0(两服务栈:PostgreSQL 15 + Pleroma),从制品获取、栈编排、启动迁移、Web 验证到管理员账号与 Mastodon API 发贴闭环,全部命令与回显为 2026-11-02 实测,含 7 条排障实录。
一、环境与制品信息
1.1 实验环境
| 项目 | 值 |
|---|---|
| 主机 OS | Ubuntu 24.04.5 LTS(内核 7.0.0-38-generic,x86_64) |
| Docker | 29.9.2, build a82e528 |
| Docker Compose | v5.6.1 |
| 组件版本 | Pleroma 2.11.0(镜像内版本号 2.11.0-develop,stable 分支 2026-10-24 构建) |
| 依赖数据库 | PostgreSQL 15(官方镜像路线出厂默认对接) |
| Web 端口 | 127.0.0.1:8148 → 应用内 4000 |
| 实测日期 | 2026-11-02 |
1.2 官方制品路线(先厘清一个常见误区)
Pleroma 官方仓库 README 写着 "While we don't provide docker files",该说法已滞后:官方仓库现有 Dockerfile 与 Woodpecker CI(.woodpecker/docker.yml),每次 stable 分支推送/打 tag 由 kaniko 构建并推送镜像到 git.pleroma.social/pleroma/pleroma 自有 registry,标签体系为 stable/latest/develop + v<版本>-<arch>(amd64/arm64/armv7),实查标签清单见本专栏选型篇。
⚠️ 排障实录 ①:官方镜像不在 Docker Hub。按惯常思路去拉 Docker Hub 的
pleroma/pleroma会直接撞鉴权墙:$ curl -s https://registry-1.docker.io/v2/pleroma/pleroma/tags/list {"errors":[{"code":"UNAUTHORIZED","message":"authentication required","detail":[{"Type":"repository","Class":"","Name":"pleroma/pleroma","Action":"pull"}]}]}正确制品地址是
git.pleroma.social/pleroma/pleroma(匿名可拉):$ docker pull git.pleroma.social/pleroma/pleroma:stable stable: Pulling from pleroma/pleroma Digest: sha256:d2016be89c0466dde7785ab2e4cc82e671216ef7f439b5d7c64ebc85e7fa9a5e Status: Image is up to date for git.pleroma.social/pleroma/pleroma:stable git.pleroma.social/pleroma/pleroma:stable多架构核对(
docker manifest inspect实测,amd64/arm64/arm 三平台,amd64 摘要1f1ae185...):$ docker manifest inspect git.pleroma.social/pleroma/pleroma:stable { "schemaVersion": 2, "mediaType": "application/vnd.oci.image.index.v1+json", "manifests": [ { "mediaType": "application/vnd.oci.image.manifest.v1+json", "size": 1526, "digest": "sha256:1f1ae185bca8d46419607ae32aa9ba6f71bdb8e61645ccf0402153f3ffe0aec0", "platform": { "architecture": "amd64", "os": "linux" } }, ...(arm64 摘要 e0a4c17e...、arm/v7 摘要 5efcc312... 略) ] }
1.3 镜像内部结构(决定后续所有路径与端口)
从镜像 config 与 Dockerfile 实查(docker inspect + 官方仓库 Dockerfile):
- 运行期系统包仅 6 个:
exiftool ffmpeg vips libmagic ncurses postgresql-client——没有 Redis、没有 Elasticsearch,联邦社交依赖链就 PostgreSQL 一环; - 发布制品在
/opt/pleroma(HOME),数据目录/var/lib/pleroma,内置配置/etc/pleroma/config.exs(即仓库config/docker.exs); - 入口脚本
/opt/pleroma/docker-entrypoint.sh:等库 →pleroma_ctl migrate→exec bin/pleroma start; EXPOSE 4000,出厂监听0.0.0.0:4000;- 出厂
docker.exs按环境变量组装配置:DOMAIN/INSTANCE_NAME/ADMIN_EMAIL/NOTIFY_EMAIL/DB_HOST/DB_PORT/DB_NAME/DB_USER/DB_PASS,并自动生成/var/lib/pleroma/secret.exs(Cookie 签名密钥与 VAPID 推送密钥对)。
二、Compose 栈编排
2.1 完整 docker-compose.yml(实测在跑版本)
name: pleroma-2.11.0-stack
services:
db:
image: postgres:15
container_name: pleroma-2.11.0-db
restart: unless-stopped
environment:
POSTGRES_DB: pleroma
POSTGRES_USER: pleroma
POSTGRES_PASSWORD: q1w2e3r4
volumes:
- ./pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U pleroma -d pleroma"]
interval: 5s
timeout: 3s
retries: 20
networks: [pleroma-net]
pleroma:
image: git.pleroma.social/pleroma/pleroma:stable
container_name: pleroma-2.11.0-app
restart: unless-stopped
depends_on:
db:
condition: service_healthy
environment:
DOMAIN: localhost
INSTANCE_NAME: "Pleroma Demo"
ADMIN_EMAIL: admin@example.com
NOTIFY_EMAIL: notifications@example.com
DB_HOST: db
DB_PORT: "5432"
DB_NAME: pleroma
DB_USER: pleroma
DB_PASS: q1w2e3r4
ports:
- "127.0.0.1:8148:4000"
volumes:
- ./data:/var/lib/pleroma
networks: [pleroma-net]
networks:
pleroma-net:
driver: bridge
ipam:
config:
- subnet: 10.89.72.0/24
2.2 编排要点解读
name:显式项目名:多组件共用宿主机时防止docker compose down互删;depends_on+ healthcheck:pg_isready探活 +condition: service_healthy,配合入口脚本自身的-- Waiting for database...双保险;DOMAIN=localhost+ 端口回环绑定:实验环境无域名无 TLS,用127.0.0.1:8148:4000最小暴露面;生产必须换成真实域名并前置反代(见 2.3);./data:/var/lib/pleroma必须持久化:secret.exs(Cookie 签名密钥)与config.exs(用户配置)都落在这里,丢了等于实例身份丢失、所有会话失效;- 网络显式 subnet:
10.89.72.0/24为实验环境统一规划槽位,生产可删。
2.3 出厂 HTTPS 假设与本地 HTTP 适配
⚠️ 排障实录 ②:出厂
docker.exs写死url: [host: DOMAIN, scheme: "https", port: 443]——官方假设你必然在反代后面。本实验直接 HTTP 端口转发访问时,实例自报的 actor/对象 URL 会全错(https://localhost/...)。适配方法:在持久化的/var/lib/pleroma/config.exs(出厂自动生成,晚于 docker.exs 导入、优先级更高)里覆盖 Endpoint url:$ docker exec pleroma-2.11.0-app cat /var/lib/pleroma/config.exs import Config # For additional configuration outside of environmental variables config :pleroma, Pleroma.Web.Endpoint, url: [host: "localhost", scheme: "http", port: 8148]改完重启应用服务生效:
docker compose restart pleroma。日志横幅随即变为Access Pleroma.Web.Endpoint at http://localhost:8148。
三、部署步骤实测
3.1 起栈
$ docker compose up -d
Network pleroma-2110-stack_pleroma-net Creating
Network pleroma-2110-stack_pleroma-net Created
Container pleroma-2.11.0-db Creating
Container pleroma-2.11.0-db Created
Container pleroma-2.11.0-app Creating
Container pleroma-2.11.0-app Created
Container pleroma-2.11.0-db Starting
Container pleroma-2.11.0-db Started
Container pleroma-2.11.0-db Waiting
Container pleroma-2.11.0-db Healthy
Container pleroma-2.11.0-app Starting
Container pleroma-2.11.0-app Started
$ docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
pleroma-2.11.0-app git.pleroma.social/pleroma/pleroma:stable "/opt/pleroma/docker…" pleroma 26 seconds ago Up 20 seconds 127.0.0.1:8148->4000/tcp
pleroma-2.11.0-db postgres:15 "docker-entrypoint.s…" db 26 seconds ago Up 25 seconds (healthy) 5432/tcp
💡 说明:compose 项目名
pleroma-2.11.0-stack中的点号会被自动剥离,网络实际叫pleroma-2110-stack_pleroma-net。
3.2 入口脚本三步曲(首次启动日志实录)
$ docker compose logs pleroma | head -8
pleroma-2.11.0-app | -- Waiting for database...
pleroma-2.11.0-app | db:5432 - accepting connections
pleroma-2.11.0-app | -- Running migrations...
pleroma-2.11.0-app | warning: missing `:on` in join, defaulting to `on: true`.
pleroma-2.11.0-app | opt/pleroma/lib/pleroma-2.11.0-develop/priv/repo/migrations/20191029172832_fix_blocked_follows.exs:108: ...
pleroma-2.11.0-app | 08:47:39.066 [info] == Running 20170320193800 Pleroma.Repo.Migrations.CreatePleroma.User.change/0 forward
pleroma-2.11.0-app | 08:47:39.068 [info] create table if not exists users
pleroma-2.11.0-app | 08:47:39.073 [info] == Migrated 20170320193800 in 0.0s
迁移从 2017 年第一张表一路跑到最新(共 2050+ 行日志,末条迁移 20260725000000),随后进入第三步:
pleroma-2.11.0-app | 08:47:41.099 [info] == Migrated 20260725000000 in 0.0s
pleroma-2.11.0-app | -- Starting!
pleroma-2.11.0-app | 08:47:43.257 [info] PromEx is starting a standalone metrics server on port 4021 over http
pleroma-2.11.0-app | 08:47:43.276 [info] Running Pleroma.Web.Endpoint with cowboy 2.19.0 at 0.0.0.0:4000 (http)
pleroma-2.11.0-app | 08:47:43.276 [info] Access Pleroma.Web.Endpoint at http://localhost:8148
pleroma-2.11.0-app | 08:47:43.277 [info] Gopher server disabled
💡 说明:
PromEx ... port 4021是内置 Prometheus 指标端点(PromEx 库),默认不映射到宿主机,需要监控时在 compose 加4021端口即可;紧随其后的PromEx.LifecycleAnnotator failed to create start annotation in Grafana: :unkown与:econnrefused警告是未配 Grafana 推送的正常噪音,可忽略。
3.3 数据库落表核对
$ docker exec pleroma-2.11.0-db psql -U pleroma -d pleroma -c "select nickname, is_admin, is_active from users order by id;"
nickname | is_admin | is_active
----------------+----------+-----------
internal.fetch | f | t
admin | t | t
relay | f | t
tester | f | t
(4 rows)
internal.fetch 与 relay 是系统内置账号(联邦拉取代理与中继处理器),无需管理。
四、Web 与 API 闭环验证
4.1 Web 界面
$ curl -s -o /dev/null -w '%{http_code} %{size_download}\n' http://127.0.0.1:8148/
200 14259
$ curl -s http://127.0.0.1:8148/ | head -c 200
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1,user-scalable=no">
<link rel="preload" href="/static/config.json" as="fetch" crossorigin />
官方镜像出厂内置 pleroma-fe(前端静态资源打包在发布制品 priv 目录内,/var/lib/pleroma/static 初始为空也不影响),开箱即有浏览器界面,无需先跑 mix pleroma.frontend install。
4.2 Nodeinfo 与实例信息
$ curl -s http://127.0.0.1:8148/.well-known/nodeinfo
{"links":[{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.0","href":"http://localhost:8148/nodeinfo/2.0.json"},{"rel":"http://nodeinfo.diaspora.software/ns/schema/2.1","href":"http://localhost:8148/nodeinfo/2.1.json"}]}
$ curl -s http://127.0.0.1:8148/nodeinfo/2.0.json | head -c 300
{"version":"2.0","protocols":["activitypub"],"metadata":{"private":false,"features":["pleroma_api","mastodon_api","mastodon_api_grouped_notifications","mastodon_api_streaming","polls","v2_suggestions","pleroma_explicit_addressing","shareable_emoji_packs","multifetch",...
$ curl -s http://127.0.0.1:8148/api/v1/instance | head -c 200
{"version":"2.7.2 (compatible; Pleroma 2.11.0-develop)","description":"Pleroma: An efficient and flexible fediverse server","pleroma":{"metadata":{"features":["pleroma_api","mastodon_api",...
version 字段的 2.7.2 (compatible; ...) 是 Mastodon API 兼容版本号,真实版本看括号内 Pleroma 2.11.0-develop。features 清单里可以看到 chat、pleroma_emoji_reactions、quote_posting、editing 等主线特性。
⚠️ 排障实录 ③:nodeinfo 路径必须带
.json后缀。/nodeinfo/2.1返回:{"error":"Nodeinfo schema version not handled"}而
/nodeinfo/2.1.json正常返回 200。.well-known/nodeinfo给出的 href 才是权威路径。
4.3 管理员账号创建(CLI 路线)
镜像入口只负责起服务,不会自动建管理员(ADMIN_EMAIL 仅写入实例配置)。用发布制品自带的 pleroma_ctl:
⚠️ 排障实录 ④:容器工作目录是
/,直接docker exec pleroma-2.11.0-app bin/pleroma ...报bin/pleroma: not found,必须用绝对路径/opt/pleroma/bin/pleroma_ctl(或先cd /opt/pleroma)。
$ docker exec pleroma-2.11.0-app /opt/pleroma/bin/pleroma_ctl user new admin admin@example.com --password q1w2e3r4 --admin -y
A user will be created with the following information:
- nickname: admin
- email: admin@example.com
- password: q1w2e3r4
- name: admin
- bio:
- moderator: false
- admin: true
...(中间为逐条 SQL debug 日志,略)
User admin created
重复执行同一命令(账号已存在)时,2.11.0 的 user 任务不做友好提示、直接抛异常(实测原样):
⚠️ 排障实录 ⑤:
** (MatchError) no match of right hand side value: {:error, #Ecto.Changeset<action: :insert, ..., errors: [email: {"has already been taken", [constraint: :unique, constraint_name: "users_email_index"]}], ...>} (pleroma 2.11.0-develop) lib/mix/tasks/pleroma/user.ex:76: Mix.Tasks.Pleroma.User.run/1结论:先查重再建号(
psql -c "select nickname from users where nickname='admin'"),或按 email 冲突信息判断。异常栈中会打印完整 changeset(含 RSA 私钥与明文口令回显),生产日志注意脱敏。
4.4 OAuth 应用与令牌(Mastodon API 路线)
⚠️ 排障实录 ⑥:
POST /api/v1/apps传旧版单数参数redirect_uri被拒(400):$ curl -s -X POST -d 'client_name=diag1&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scopes=read write follow' http://127.0.0.1:8148/api/v1/apps {"error":"Missing field: redirect_uris.","errors":[{"message":"Missing field: redirect_uris","title":"Invalid value","source":{"pointer":"/redirect_uris"}}]}应用日志同步给出严格校验证据:
[error] Strict ApiSpec: request denied to /api/v1/apps with params %{"client_name" => "cli-test", "redirect_uri" => ...}。改用复数redirect_uris即 200:$ curl -s -X POST -d 'client_name=diag3&redirect_uris=urn:ietf:wg:oauth:2.0:oob&scopes=read write follow' http://127.0.0.1:8148/api/v1/apps {"id":"2","name":"diag3","website":null,"redirect_uri":"urn:ietf:wg:oauth:2.0:oob","client_secret":"ZwIzyISUpwffBUrRuaoeIi62Ko9pZR9-eUWw7Ar8TWE","client_id":"ziPjtW7_sGTg_Ed1EH8ggkw2AGmqHB6jQqYFwyuiX9U","vapid_key":"BFKp_ykgdcexcq3Wq-..."}
用 client_credentials 换管理员口令令牌(password grant):
$ curl -s -X POST -u 'ziPjtW7_sGTg_Ed1EH8ggkw2AGmqHB6jQqYFwyuiX9U:ZwIzyISUpwffBUrRuaoeIi62Ko9pZR9-eUWw7Ar8TWE' \
-d 'grant_type=password&username=admin&password=q1w2e3r4&scope=read write follow' \
http://127.0.0.1:8148/oauth/token
{"id":2,"scope":"read write follow","me":"http://localhost:8148/users/admin","expires_in":3153600000,"access_token":"vZ7u39IMjbfGN3_R2B_Zx-T5TzlsTDCdwnyAChffh_M","refresh_token":"Sp_fmbreRYdLBZijkfET5BbzCTvLRt8foPnH1Gt8PRI","token_type":"Bearer","created_at":1793621533}
凭据核对与发贴、拉时间线:
$ curl -s -H "Authorization: Bearer vZ7u39IMjbfGN3_R2B_Zx-T5TzlsTDCdwnyAChffh_M" http://127.0.0.1:8148/api/v1/accounts/verify_credentials | head -c 200
{"id":"BC25ecq6F8aSoEYBoe","header":"http://localhost:8148/images/banner.png","pleroma":{"email":"admin@example.com",...,"is_admin":true,...
$ curl -s -X POST -H "Authorization: Bearer vZ7u39IMjbfGN3_R2B_Zx-T5TzlsTDCdwnyAChffh_M" \
-d 'status=S8 batch takeover check from Pleroma 2.11.0 compose stack' \
http://127.0.0.1:8148/api/v1/statuses | head -c 300
{"id":"BC2NPYWLocV0FMHEcS","sensitive":false,"application":null,"pleroma":{"local":true,"context":"http://localhost:8148/contexts/76331ed5-2f59-4e64-b529-bd4f43a4a628",...
$ curl -s -H "Authorization: Bearer vZ7u39IMjbfGN3_R2B_Zx-T5TzlsTDCdwnyAChffh_M" http://127.0.0.1:8148/api/v1/timelines/public | head -c 200
[{"id":"BC2NPYWLocV0FMHEcS","sensitive":false,"application":{"name":"cli-test","website":null},"pleroma":{"local":true,...
发贴 200、公开时间线能查到该贴,部署闭环完成。
⚠️ 排障实录 ⑦:直连端口(无反代)时每个 API 请求都会刷一条警告:
[warning] Rate limiter disabled due to forwarded IP not being found. Please ensure your reverse proxy is providing the X-Forwarded-For header or disable the RemoteIP plug/rate limiter.原因是限流器依赖
X-Forwarded-For识别来源 IP。生产按官方 nginx 模板配好proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;即消失;实验环境可无视。
五、生产化差异清单
本实验为「无域名直连」形态,上生产需按下表改造(细节见配置篇):
| 项 | 实验形态 | 生产形态 |
|---|---|---|
| DOMAIN | localhost | 真实域名(开放联邦后不可更改) |
| Endpoint url | config.exs 手工覆盖 http:8148 | 删除覆盖,恢复出厂 scheme: "https", port: 443 |
| TLS | 无 | nginx/caddy 反代终结,转发 X-Forwarded-For |
| 端口暴露 | 127.0.0.1:8148 | 仅反代可达应用 4000,DB 不出网 |
| registrations_open | 出厂 false(关注册) | 公共实例显式开或走邀请制 |
| DB 口令 | compose 明文 | secret.exs/环境注入 + 强口令 |
| 数据备份 | bind 目录 | 定期 pg_dump + 打包 /var/lib/pleroma(secret.exs 必含) |
六、升级与回滚
- 升级:改 compose 镜像标签(如
v2.11.0-amd64)→docker compose pull && docker compose up -d,入口脚本自动执行pleroma_ctl migrate补跑新迁移;裸 OTP 路线则用bin/pleroma_ctl update(内置从git.pleroma.social/api/packages/pleroma/generic拉pleroma-otp-<branch>-<flavour>制品、解包替换的完整逻辑,flavour 自动探测 amd64/arm64/arm/musl)。 - 回滚:先
pleroma_ctl rollback [VERSION]回退迁移,再换回旧镜像标签。版本跨度大时先查 release notes 的 Upgrade notes 段。 - 制品核对提醒:registry 各版本标签架构完备度不一(实测 v2.11.0 有 amd64/arm64/armv7,v2.11.1 当时仅 arm64/armv7),升级前先
docker manifest inspect确认目标架构标签存在。
七、清理实录
$ docker compose down
Container pleroma-2.11.0-app Stopping
Container pleroma-2.11.0-app Stopped
Container pleroma-2.11.0-app Removing
Container pleroma-2.11.0-app Removed
Container pleroma-2.11.0-db Stopping
Container pleroma-2.11.0-db Stopped
Container pleroma-2.11.0-db Removing
Container pleroma-2.11.0-db Removed
Network pleroma-2110-stack_pleroma-net Removing
Network pleroma-2110-stack_pleroma-net Removed
$ docker volume ls | grep -i pleroma # 本栈数据全为 bind 挂载,卷列表零残留
$ rm -rf ./data ./pgdata # 如需彻底清数据
八、站内阅读
- 选型与版本溯源:《Pleroma 2.11.0 介绍与选型指南》
- 配置项逐组详解:《Pleroma 2.11.0 配置参数详解》
pleroma_ctl/mix 任务族:《Pleroma 2.11.0 常用 CLI 命令详解》- 同架构分支对照:《Akkoma 3.20.1 Docker Compose 部署指南》
实测说明:本文回显均产生于 2026-11-02 的 Ubuntu 24.04.5 + Docker 29.9.2 环境;长 SQL debug 日志与异常栈中的密钥内容已按行截断/脱敏,其余逐行照抄。