Akkoma 3.20.1 Docker Compose 部署指南

Akkoma 3.20.1 官方 Docker Compose 源码构建路线全纪实:从克隆构建、实例生成、数据库初始化、迁移与前端安装到 Web 登录与 API 闭环验证,含 root 宿主 addgroup 撞 gid、依赖网络重试等排障实录,全部命令回显 2026-11-02 实测。

AkkomaAkkomaFediverseElixirDockerDocker ComposePostgreSQL2026/11/02

Akkoma 3.20.1 Docker Compose 部署指南

目标:在一台 Linux 主机上,用 Akkoma 官方仓库自带的 Docker Compose 编排,把 Akkoma 3.20.1 从零部署到「浏览器可登录、API 可发贴」的可用状态。本文全部命令与回显均为 2026-11-02 实测记录,包括 root 权限下官方构建脚本必失败的坑与修复方法。认知与选型背景见 《Akkoma 3.20.1 介绍与选型指南》,配置参数逐项解说见 《Akkoma 3.20.1 配置参数详解》,日常运维命令见 《Akkoma 3.20.1 常用 CLI 命令与工具详解》。

一、环境信息

本章为实测环境口径,供读者复核。

  • 组件与版本:Akkoma 3.20.1(mix.exs 声明 version("3.20.1"),stable 分支 HEAD 为 bc62dd80,2026-09-27 "Merge branch 'develop' into stable";运行时自报版本字符串 3.20.1-0-gbc62dd8)。
  • 运行时:Elixir 1.15.4(OTP 26)、Erlang/OTP 26 [erts-14.0.2]、PostgreSQL 14.24(均为实测回显,见 12.4 节)。
  • 编排:官方仓库根目录 docker-compose.yml + docker-resources/ 构建脚本,Compose v2(docker compose 子命令形态)。
  • 宿主:Linux x86_64,Docker Engine + Compose v2 可用;本实测宿主端口段 8128-8132 分配给 Akkoma(4000 端口被占用,Web 入口实测用 8129)。
  • 重要事实(实测确证):Akkoma 3.20.1 不再需要 Redis。官方 compose 只有 db 与 akkoma 两个服务;对源码 mix.exs/mix.lock/config/lib 全文检索 redis 零命中。
  • 重要事实(实测确证):Docker Hub 上的 akkoma/akkoma 预构建产物不可用于 3.20.1——其标签只有 buildx/latest/next/test(无 stable),且 latest 的创建时间停留在 2023-07-27(约 v3.9/3.10 时代)。官方 Docker 路线 = 用仓库内 docker-resources/build.sh 从源码构建,本文即按该路线实测。

二、部署架构总览

官方 compose 定义两个服务,职责如下:

服务名构建来源角色关键参数
db./docker-resources/database(基于 postgres:14-alpine 加建 akkoma 用户)PostgreSQL 14 数据服务shm_size: 4gb,数据 bind 到 ./pgdata,库/用户/密码均为 akkoma
akkoma仓库根 Dockerfile(基于 hexpm/elixir:1.15.4-erlang-26.0.2-alpine-3.18.2)Akkoma 应用服务源码树 bind 挂载到 /opt/akkoma,nofile ulimit 524288,Web 监听 4000

源码 bind 挂载(. → /opt/akkoma)意味着:配置、依赖、编译产物、上传文件、静态前端全部落在宿主源码树里,构建产物只是「依赖壳」,升级时重新拉代码即可,这与预构建产物打包代码的路线根本不同。

三、获取源码

git clone --depth 1 -b stable https://akkoma.dev/AkkomaGang/akkoma.git akkoma-src

实测回显:

Cloning into 'akkoma-src'...
CLONE_RC=0

克隆后目录约 32M。确认版本:

grep version\( mix.exs

回显含 version("3.20.1")。

四、Compose 编排文件核对

官方 docker-compose.yml 原文(实测部署所用文件,仅端口映射一行按宿主占用情况从 127.0.0.1:4000:4000 改为 127.0.0.1:8129:4000,另按环境加了 name/container_name/子网,均不影响流程):

services:
  db:
    image: akkoma-db:latest
    build: ./docker-resources/database
    shm_size: 4gb
    restart: unless-stopped
    user: ${DOCKER_USER}
    environment: {
      POSTGRES_DB: akkoma,
      POSTGRES_USER: akkoma,
      POSTGRES_PASSWORD: akkoma,
    }
    env_file:
      - .env
    volumes:
      - type: bind
        source: ./pgdata
        target: /var/lib/postgresql/data

  akkoma:
    image: akkoma:latest
    build: .
    restart: unless-stopped
    env_file:
      - .env
    links:
      - db
    ports: [
      "127.0.0.1:8129:4000",
    ]
    volumes:
      - .:/opt/akkoma
    ulimits:
      nofile: 524288

注意三点:

  1. version: "3.7" 属性在 Compose v2 下已废弃,每次调用都会打印一行警告 the attribute version is obsolete, it will be ignored,无害,后文回显中该行不再重复摘录。
  2. 数据库口令在 compose 里明文写死为 akkoma,官方注释说明该库只在编排内部网络可达、不对外暴露,建议保持默认。
  3. 没有 Redis 服务,也没有任何队列/缓存服务——单应用服务 + 单数据库即完整拓扑。

五、准备 .env

cd akkoma-src
cp docker-resources/env.example .env
echo DOCKER_USER=$(id -u):$(id -g) >> .env

env.example 实测内容:

MIX_ENV=prod
ERL_EPMD_ADDRESS=127.0.0.1
DB_NAME=akkoma
DB_USER=akkoma
DB_PASS=akkoma

本实测环境为 root 宿主(uid/gid=0),不能直接用 id -u 的结果,原因见下一章;最终 .env 追加行为 DOCKER_USER=1000:1000。

六、构建:官方脚本在 root 宿主必失败(排障实录)

直接执行官方 docker-resources/build.sh:

#!/bin/sh
docker compose build --build-arg UID=$(id -u) --build-arg GID=$(id -g) akkoma
docker compose build --build-arg UID=$(id -u) --build-arg GID=$(id -g) db

root 下 id -u/id -g 均为 0,构建在创建 akkoma 用户步骤失败,实测回显(节选):

#6 [2/6] RUN apk add git gcc g++ musl-dev make cmake file-dev exiftool ffmpeg imagemagick libmagic ncurses postgresql-client
...
#6 45.30 OK: 572 MiB in 184 packages
#6 DONE 45.5s

#7 [3/6] RUN addgroup -g 0 akkoma
#7 0.222 addgroup: gid '0' in use
#7 ERROR: process "/bin/sh -c addgroup -g $GID $UNAME" did not complete successfully: exit code: 1
------
 Dockerfile:25
  25 | >>> RUN addgroup -g $GID $UNAME
------
failed to solve: process "/bin/sh -c addgroup -g $GID $UNAME" did not complete successfully: exit code: 1
BUILD_RC=1

db 服务同样卡死在 addgroup -g 0 akkoma。根因:gid 0 已被 root 组占用,无法再建同名组。官方文档的 DOCKER_USER=$(id -u):$(id -g) 写法隐含「非 root 宿主」前提。

修复:显式传非特权 UID/GID,并让宿主源码树对该 UID 可写(bind 挂载后应用进程要写 _build/deps/config/uploads/static):

chown -R 1000:1000 .
docker compose build --build-arg UID=1000 --build-arg GID=1000 akkoma
docker compose build --build-arg UID=1000 --build-arg GID=1000 db

实测成功回显(节选):

#7 [3/6] RUN addgroup -g 1000 akkoma
#7 DONE 0.2s
#8 [4/6] RUN adduser -u 1000 -G akkoma -D -h /opt/akkoma akkoma
#8 DONE 0.3s
#10 [6/6] RUN mix local.hex --force &&    mix local.rebar --force
#10 3.985 * creating .mix/archives/hex-2.6.0
#10 7.385 * creating .mix/elixir/1-15/rebar3
#11 naming to docker.io/library/akkoma:latest done
 Image akkoma:latest Built
AKKOMA_RC=0
#6 [2/3] RUN addgroup -g 1000 akkoma
#6 DONE 0.6s
#7 [3/3] RUN adduser -u 1000 -G akkoma -D -h $HOME akkoma
#7 DONE 0.2s
#8 naming to docker.io/library/akkoma-db:latest done
 Image akkoma-db:latest Built
DB_RC=0

顺带实测结论:db 的 Dockerfile 里 adduser ... -h $HOME 的 $HOME 在 postgres:14-alpine 基础上并未定义,但 adduser -D 对此不报错(回显 DONE 0.2s),疑点排除。

构建完成后两个产物的大小(实测):

akkoma-db:latest 414MB
akkoma:latest 911MB

七、拉取应用依赖(deps.get,含网络踩坑)

后续所有 mix 任务都通过官方 docker-resources/manage.sh 进入应用服务执行:

#!/bin/sh
docker compose run --rm akkoma $@

第一步拉依赖:

./docker-resources/manage.sh mix deps.get

首次实测失败——从 GitHub 拉 search_parser 时传输层中断:

* Getting search_parser (https://github.com/FloatingGhost/pleroma-contrib-search-parser.git - origin/main)
fatal: unable to access 'https://github.com/FloatingGhost/pleroma-contrib-search-parser.git/': Error in the HTTP2 framing layer
** (Mix) Command "git --git-dir=.git fetch --force --quiet --progress" failed
DEPS_RC=1

直接重试即成功(瞬时网络故障,非仓库问题):

* Getting cowboy (Hex package)
* Getting cowboy_telemetry (Hex package)
* Getting websock_adapter (Hex package)
* Getting websock (Hex package)
Found retired packages, see above for details
Found packages with security advisories, see above for details
You have added/upgraded packages you could sponsor, run `mix hex.sponsor` to learn more
DEPS_RC=0

值得留意的实测细节:mix deps.get 会顺带做安全审计,本次输出列出了若干带 CVE 的依赖(节选):

Unchanged:
  cowboy 2.17.0 VULNERABLE!
    EEF-CVE-2026-65624 (MEDIUM)
    Cowboy HTTP/1.1 max_headers Bypass via Duplicate Header Names Enables Memory Exhaustion
  decimal 3.1.1 VULNERABLE!
    EEF-CVE-2026-97853 (MEDIUM)
    Unbounded allocation in decimal Decimal.round/3 driven by the places argument enables DoS
  earmark 1.4.46 RETIRED! VULNERABLE!
    (deprecated) Earmark is no longer maintained. Migrate to a replacement, for example MDEx

这与 3.20.1 本身是「随依赖安全更新的重构建补丁」的定位一致:上游补丁未合并前,这些告警属于已知状态。

八、编译

./docker-resources/manage.sh mix compile

顺序陷阱(实测):若在 deps.get 未完成时抢跑 compile,会得到一长串未满足依赖清单后中止:

Unchecked dependencies for environment prod:
* bcrypt_elixir (Hex package)
  the dependency is not available, run "mix deps.get"
...
* search_parser (https://github.com/FloatingGhost/pleroma-contrib-search-parser.git - origin/main)
  lock mismatch: the dependency is out of date. To fetch locked version run "mix deps.get"
...
** (Mix) Can't continue due to errors on dependencies
COMPILE_RC=1

依赖齐全后正式编译(605 个 .ex 文件,含 NIF/C 扩展,约 2 分钟):

==> restarter
Compiling 2 files (.ex)
Generated restarter app
make: Entering directory '/opt/akkoma/deps/eblurhash/c_src'
cc -o /opt/akkoma/deps/eblurhash/c_src/../priv/blurhash blurhash_stb.c encode.c -lm
...
01:56:37.497 [debug] Elixir.Pleroma.Web.ActivityPub.MRF.NoOpPolicy is excluded from config descriptions, because does not implement `config_description/0` method.
Compiling lib/pleroma/web/gettext.ex (it's taking more than 10s)
Generated pleroma app
COMPILE_RC=0

九、生成实例配置

mkdir -p pgdata
./docker-resources/manage.sh mix pleroma.instance gen

该任务交互式询问实例域名、名称、管理员邮箱、数据库参数等(若数据库服务尚未建库,口令就填 compose 里的 akkoma;数据库主机填 db;监听 IP 必须改成 0.0.0.0,否则 bind 挂载环境下应用只监听回环地址,宿主端口映射进不去)。实测回显:

fatal: No names found, cannot describe anything.
warning: `config/prod.secret.exs` not found. You may want to create one by running `mix pleroma.instance gen`

Writing config to config/generated_config.exs.
Writing the postgres script to config/setup_db.psql.
Writing /opt/akkoma/static/robots.txt.

 All files successfully written! Refer to the installation instructions for your platform for next steps.

生成物要点(实测核对):

  • config/generated_config.exs(权限 0640):含 url: [host: "localhost", scheme: "https", port: 8129]、http: [ip: {0, 0, 0, 0}, port: 4000]、随机生成的 secret_key_base/signing_salt/vapid 密钥对、config :pleroma, Pleroma.Repo, hostname: "db"、configurable_from_database: false 等。
  • config/setup_db.psql:两行建角色/建库 + 连接 + 三个 CREATE EXTENSION。
  • static/robots.txt:按「允许索引」生成,实测内容 User-Agent: * / Disallow:(空值即允许)。

按官方流程改名为正式配置:

cp config/generated_config.exs config/prod.secret.exs

十、初始化数据库

先单独起一个数据库连接会话执行建库脚本(官方文档写法):

./docker-resources/manage.sh psql -h db -U akkoma -f config/setup_db.psql

实测回显:

psql:config/setup_db.psql:1: ERROR:  role "akkoma" already exists
psql:config/setup_db.psql:2: ERROR:  database "akkoma" already exists
You are now connected to database "akkoma" as user "akkoma".
CREATE EXTENSION
CREATE EXTENSION
CREATE EXTENSION

前两行的 ERROR 不是故障:db 服务的环境变量(POSTGRES_USER/POSTGRES_PASSWORD/POSTGRES_DB=akkoma)在首次启动时已经自动建好了角色和库,脚本重复执行自然冲突;关键是后面三个扩展(pg_trgm、btree_gist、plpgsql 一类)成功创建。全新环境首次执行时这两行则会是 CREATE ROLE / CREATE DATABASE。

十一、执行数据迁移

./docker-resources/manage.sh mix ecto.migrate

实测回显(首尾节选,全量迁移从 2017 年第一张表一路跑到 2021 年,数百条):

02:11:12.827 [info] == Running 20170320193800 Pleroma.Repo.Migrations.CreatePleroma.User.change/0 forward
02:11:12.829 [info] create table if not exists users
02:11:12.837 [info] == Migrated 20170320193800 in 0.0s
02:11:12.850 [info] == Running 20170321074828 Pleroma.Repo.Migrations.CreatePleroma.Activity.change/0 forward
02:11:12.850 [info] create table if not exists activities
02:11:12.854 [info] create index if not exists activities_data_index
...
02:11:13.970 [info] == Running 20210222183840 Pleroma.Repo.Migrations.RemoveHashtagsObjectsDuplicateIndex.up/0
02:11:13.970 [info] drop index if exists hashtags_objects_hashtag_id_object_id_index
02:11:13.970 [info] index "hashtags_objects_hashtag_id_object_id_index" does not exist, skipping
02:11:13.971 [info] == Running 20210222184616 Pleroma.Repo.Migrations.ChangeHashtagsNameToText.up/0
02:11:13.971 [info] alter table hashtags

十二、安装前端并启动服务

12.1 安装前端

主前端 pleroma-fe 与管理端 admin-fe(实测回显):

./docker-resources/manage.sh mix pleroma.frontend install pleroma-fe --ref stable
Downloading pleroma-fe (stable)...
02:12:22.102 [info] Downloading pre-built bundle for pleroma-fe
02:12:22.113 [debug] Outbound: get https://akkoma-updates.s3-website.fr-par.scw.cloud/frontend/stable/akkoma-fe.zip
Installing pleroma-fe (stable) to /opt/akkoma/static/frontends/pleroma-fe/stable
Frontend pleroma-fe (stable) installed to /opt/akkoma/static/frontends/pleroma-fe/stable
./docker-resources/manage.sh mix pleroma.frontend install admin-fe --ref stable
Downloading admin-fe (stable)...
02:12:29.640 [info] Downloading pre-built bundle for admin-fe
02:12:29.646 [debug] Outbound: get https://akkoma-updates.s3-website.fr-par.scw.cloud/frontend/stable/admin-fe.zip
Installing admin-fe (stable) to /opt/akkoma/static/frontends/admin-fe/stable
Frontend admin-fe (stable) installed to /opt/akkoma/static/frontends/admin-fe/stable

Mastodon 风格前端踩坑(排障实录):按配置里 mastodon: %{"name" => "mastodon-fe", ...} 直觉执行 install masto-fe 会失败:

** (RuntimeError) Configured third-party frontend without a bugtracker; refusing install.
    (pleroma 3.20.1-0-gbc62dd8) lib/pleroma/frontend.ex:37: Pleroma.Frontend.install/2

masto-fe 是仓库名不是安装名;用 available 表里的键 mastodon-fe 即成功:

Downloading mastodon-fe (akkoma)...
03:18:44.375 [info] Downloading pre-built bundle for mastodon-fe
03:18:44.382 [debug] Outbound: get https://akkoma-updates.s3-website.fr-par.scw.cloud/frontend/akkoma/masto-fe.zip
Installing mastodon-fe (akkoma) to /opt/akkoma/static/frontends/mastodon-fe/akkoma
Frontend mastodon-fe (akkoma) installed to /opt/akkoma/static/frontends/mastodon-fe/akkoma

12.2 启动

docker compose up -d

实测回显:

 Container akkoma-3.20.1-db Running
 Container akkoma-3.20.1-app Creating
 Container akkoma-3.20.1-app Created
 Container akkoma-3.20.1-app Starting
 Container akkoma-3.20.1-app Started

应用服务入口脚本 docker-entrypoint.sh 的行为(实测源码):先 pg_isready 轮询等库就绪,再自动跑一遍 mix ecto.migrate(幂等),最后以 elixir --erl "+sbwt none +sbwtdcpu none +sbwtdio none" -S mix phx.server 启动。BEAM 不是 JVM,无需任何堆内存参数。

12.3 Web 验证

curl -sI http://127.0.0.1:8129/

实测回显(节选):

HTTP/1.1 200 OK
access-control-allow-credentials: true
access-control-allow-origin: *
cache-control: max-age=0, private, must-revalidate
content-length: 7283
content-security-policy: upgrade-insecure-requests;style-src 'self' 'nonce-0mTOjrzCzBmbML-';...
server: Cowboy
x-frame-options: DENY
curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:8129/web

实测回显:

302
<html><body>You are being <a href="/web/login">redirected</a>.</body></html>

/web 302 到 /web/login 即前端 bundle 正常、实例可用。

12.4 运行时核对

docker compose ps
NAME                IMAGE              COMMAND                  SERVICE   CREATED             STATUS          PORTS
akkoma-3.20.1-app   akkoma:latest      "/opt/akkoma/docker-…"   akkoma    About an hour ago   Up 32 minutes   127.0.0.1:8129->4000/tcp
akkoma-3.20.1-db    akkoma-db:latest   "docker-entrypoint.s…"   db        2 hours ago         Up 32 minutes   5432/tcp

版本与资源实测:

Erlang/OTP 26 [erts-14.0.2] [source] [64-bit] [smp:6:6] [ds:6:6:10] [async-threads:1] [jit]
Elixir 1.15.4 (compiled with Erlang/OTP 26)
postgres (PostgreSQL) 14.24
NAME                CPU %     MEM USAGE / LIMIT
akkoma-3.20.1-app   0.67%     212.7MiB / 15.57GiB
akkoma-3.20.1-db    0.37%     101MiB  / 15.57GiB

空闲态应用服务仅 ~213MiB 常驻,印证 A1 里「BEAM 单机轻量」的选型结论。

十三、创建管理员账号

./docker-resources/manage.sh mix pleroma.user new root root@localhost --password q1w2e3r4 --admin -y

实测回显(节选,SQL debug 行略):

A user will be created with the following information:
  - nickname: root
  - email: root@localhost
  - password: q1w2e3r4
  - name: root
  - bio:
  - moderator: false
  - admin: true
...
User root created
...
Admin status of root: true

要点:-y 跳过交互确认;带 --password 时不再随机生成口令;CLI 建的用户 is_confirmed: true,免邮箱确认。至此可用 root / q1w2e3r4 在 /web/login 登录。

十四、部署后功能验证(API 实测)

实例元数据(GET /api/v1/instance 节选):

{"version":"2.7.2 (compatible; Akkoma 3.20.1-0-gbc62dd8)","description":"Akkoma: The cooler fediverse server","title":"Akkoma Test","stats":{"domain_count":0,"remote_user_count":1,"status_count":0,"user_count":0},"uri":"localhost","max_toot_chars":5000,"upload_limit":16000000,"registrations":true,"poll_limits":{"max_options":20,"max_option_chars":200,"min_expiration":0,"max_expiration":31536000},"post_formats":["text/plain","text/html","text/markdown","text/bbcode","text/x.misskeymarkdown"]}

NodeInfo 2.0(GET /nodeinfo/2.0.json 节选):

{"software":{"name":"akkoma","version":"3.20.1-0-gbc62dd8"},"protocols":["activitypub"],"openRegistrations":true,"metadata":{"features":["pleroma_api","akkoma_api","mastodon_api","mastodon_api_streaming","polls","quote_posting","editing","pleroma_emoji_reactions","profile_directory"]}}

OAuth 口令授权 → 发贴 → 时间线闭环实测:

=== token ===
{"id":2,"scope":"read write follow","me":"https://localhost:8129/users/by-id/BC1W3JR9LKovXVNMoq","refresh_token":"9T0VM6LKeAGoybONFyck68Oo4bo0TPY-powbe0MSFuU","access_token":"hG0rbSU5O9pyWu5sHAY5A4LMCd16VCN6SGrb0b7nxbY","created_at":1793587571,"expires_in":3153600000,"token_type":"Bearer"}
=== verify ===
{"id": "BC1W3JR9LKovXVNMoq", "username": "root", "acct": "root", "statuses_count": 1, "created_at": "2026-11-02T02:12:08.000Z"}
=== post ===
{"id": "BC1Z71dW94SZBwHhK4", "created_at": "2026-11-02T02:46:25.000Z", "content": "Akkoma 3.20.1 deploy verified: OAuth password grant   timeline OK", "visibility": "public", "url": "https://localhost:8129/notice/BC1Z71dW94SZBwHhK4"}
=== public tl ===
BC1Z71dW94SZBwHhK4 Akkoma 3.20.1 deploy verified: OAuth password grant   timeline OK
BC1WA8mX5CkB09Dxbs Hello Akkoma from quzuo test <a class="hashtag" data-tag="akkomatest" href="http

发贴、公开时间线、主页时间线全部返回真实数据,部署验证通过。

十五、更新流程

官方文档给出的升级序列(与首次部署同序,实测可复用):

git pull
./docker-resources/build.sh   # root 宿主换成第六章的显式 --build-arg 写法
./docker-resources/manage.sh mix deps.get
./docker-resources/manage.sh mix compile
./docker-resources/manage.sh mix ecto.migrate
docker compose restart akkoma

改配置(config/prod.secret.exs)后同样以 docker compose restart akkoma 生效,实测回显:

 Container akkoma-3.20.1-app Restarting
 Container akkoma-3.20.1-app Started

十六、排障实录汇总

#现象根因处置
1build.sh 两路构建均挂:addgroup: gid '0' in useroot 宿主 id -u/id -g=0,无法建 gid 0 组显式 --build-arg UID=1000 --build-arg GID=1000 + .env DOCKER_USER=1000:1000 + 源码树 chown -R 1000:1000
2mix deps.get 失败:Error in the HTTP2 framing layer(GitHub 源)瞬时网络故障原样重试即过
3mix compile 报一长串 the dependency is not available跳过了 deps.get严格按 deps.get → compile 顺序
4setup_db.psql 报 role/database already existscompose 环境变量已自动建库非故障,确认三个 CREATE EXTENSION 成功即可
5mix pleroma.frontend install masto-fe 报 refusing install用了仓库名而非 available 键名改用 mastodon-fe
6应用起不来 / Web 打不开instance gen 监听 IP 保持默认 127.0.0.1生成后改 http: [ip: {0, 0, 0, 0}] 并重启
7每次 compose 调用刷 version is obsolete 警告Compose v2 废弃 version 属性无害,可删该行消警

十七、小结与关联

Akkoma 的官方 Docker 路线本质是「依赖壳 + 源码 bind 挂载」:构建一次成型,之后代码、配置、数据全在宿主目录,升级即 git pull 重编译。拓扑只有应用与 PostgreSQL 两个服务(3.20.1 已彻底移除 Redis),空闲态常驻内存 200MiB 级,单机小实例成本极低。

Akkoma 3.20.1 Docker Compose 部署指南 - Quzuo