Atomic Server Docker Compose 部署指南
以 Docker Compose 编排部署 Atomic Server 0.38.0(官方发布仓库 joepmeneer/atomic-server)全过程实测:镜像选型、端口与 subject 一致性、首启日志、config.toml 凭据、/setup 邀请、export/import 备份恢复与 10 项排障实录。
Atomic Server Docker Compose 部署指南
目标:使用官方镜像
joepmeneer/atomic-server:v0.38.0以 Docker Compose 方式部署图数据库 / headless CMS「Atomic Server」,覆盖镜像选型、编排文件、首启验证、数据持久化、凭据与邀请机制、备份恢复 CLI 与常见故障排查。全部步骤已在 Ubuntu 26.04.1 LTS + Docker 29.9.2 环境实测通过(2026-11-01)。
一、环境信息
| 项目 | 值 |
|---|---|
| 操作系统 | Ubuntu 26.04.1 LTS(Docker 主机) |
| Docker | 29.9.2(build a82e528),Compose 为 docker compose 子命令 |
| 镜像 | joepmeneer/atomic-server:v0.38.0(83.1MB) |
| 服务版本 | atomic-server 0.38.0(实测 --version 回显) |
| 服务端口 | 8139:8139(宿主端口与 ATOMIC_PORT 保持一致,原因见 4.1) |
| 数据持久化 | ./data:/atomic-storage(bind mount) |
| 自定义网络 | atomic-net,子网 10.89.58.0/24 |
| 编排目录 | ~/atomic-stack(docker-compose.yml 与 data 所在) |
⚠️ 网络说明:本次部署时宿主机直连 GitHub/Docker Hub 超时,
docker pull依赖 Docker daemon 已配置的代理192.168.1.72:7897自动成功;备用代理192.168.1.62:7897当时不可用。另实测到直连docker pull会命中 DaoCloud 公共加速器白名单拒绝(原文见 4.2),docker compose up -d的自动拉取则成功。
二、镜像选型说明
Atomic Server 官方文档安装页给出的容器化渠道原文是:
docker run -p 80:80 -p 443:443 -v atomic-storage:/atomic-storage joepmeneer/atomic-server
即官方镜像为 Docker Hub 上的 joepmeneer/atomic-server(来源:docs.atomicdata.dev 安装页,2026-11-01 实查)。GitHub Releases 不提供预编译二进制,ghcr.io/ontola/atomic-server 经实测不存在(manifest unknown),因此容器化部署只能走 Docker Hub 渠道。
对 joepmeneer/atomic-server 的标签清单实查(2026-11-01,Docker Hub API,共 114 个标签)与本地拉取结果:
| 标签 | 架构 | 说明 |
|---|---|---|
latest | 仅 arm64 | 最后推送 2026-06-22;amd64 主机拉取后启动报 exec format error(见 FAQ Q1) |
develop | 多架构 | 对应 0.41.0-beta.8,本地拉取体积 220MB |
v0.38.0 | amd64 + arm | 版本标签中的最高稳定线,本地拉取体积 83.1MB,本文基准 |
v0.37.0 / 0.36.0 等 | 多架构 | 历史版本 |
💡 说明:GitHub 上官方最新稳定版为 v0.40.4(2026-09-17),但 Docker Hub 版本标签最高只到
v0.38.0——发布仓库滞后于源码仓库。amd64 主机想要「稳定 + 可容器化」,当前可选的最新版本就是 0.38.0;本专栏的部署、配置、API 三篇均以它为基准。
三、前置条件
部署前确认 Docker 引擎可用、目标端口空闲:
docker --version
# Docker version 29.9.2, build a82e528
ss -tlnp | grep 8139
# (无输出 = 端口空闲)
docker compose 子命令随 Docker Engine 提供:
docker compose version
四、部署步骤
4.1 创建编排目录与 docker-compose.yml
mkdir -p ~/atomic-stack/data
cd ~/atomic-stack
编排文件 docker-compose.yml 全文(实测使用版本):
name: atomic-server-038-stack
services:
atomic-server:
image: joepmeneer/atomic-server:v0.38.0
container_name: atomic-server-0380-server
restart: unless-stopped
ports:
- "8139:8139"
environment:
- ATOMIC_DOMAIN=localhost
- ATOMIC_PORT=8139
- ATOMIC_LOG_LEVEL=info
volumes:
- ./data:/atomic-storage
networks:
- atomic-net
networks:
atomic-net:
driver: bridge
ipam:
config:
- subnet: 10.89.58.0/24
关键项解读:
ports: "8139:8139"与ATOMIC_PORT=8139必须一致。Atomic Server 的资源主键(subject)是由domain+port生成的完整 URL(本例http://localhost:8139);若宿主映射端口与服务监听端口不一致(如8139:9883),浏览器经宿主端口访问时服务器仍按 9883 生成 subject,数据引用会整体错位。ATOMIC_DOMAIN=localhost:对外域名,生产应改为实际域名(详见配置篇)。restart: unless-stopped:宿主机重启后自动拉起。./data:/atomic-storage:全部持久化数据落宿主目录(见第五章)。- 自定义网络固定子网
10.89.58.0/24,避免与既有网段冲突。
4.2 拉取镜像
先尝试直接拉取(实测会命中加速器白名单拒绝,如实记录):
docker pull joepmeneer/atomic-server:v0.38.0
v0.38.0: Pulling from joepmeneer/atomic-server
error from registry: 🚫 👀-> https://github.com/DaoCloud/public-image-mirror/issues/2328 🔗 这镜像不在白名单. this image is not in the allowlist.
⚠️ 排障实录:本机 Docker daemon 配置了 registry-mirror(DaoCloud 公共加速)与出站代理
192.168.1.72:7897。该镜像不在加速器白名单内时,显式docker pull直接报错;而docker compose up -d的自动拉取走 daemon 代理成功。遇到此报错不必手工换源,直接执行 4.3 让 compose 拉取即可;若 compose 也失败,按 FAQ Q2 检查 daemon 代理。
4.3 启动服务
docker compose up -d
实测回显(输出节选,实测首尾;中间为分层下载进度):
Image joepmeneer/atomic-server:v0.38.0 Pulling
4f4fb700ef54 Pulling fs layer 0B
619be1103602 Pulling fs layer 0B
107f326aa5c8 Pulling fs layer 0B
...
107f326aa5c8 Pull complete 0B
Image joepmeneer/atomic-server:v0.38.0 Pulled
Network atomic-server-038-stack_atomic-net Creating
Network atomic-server-038-stack_atomic-net Created
Container atomic-server-0380-server Creating
Container atomic-server-0380-server Created
Container atomic-server-0380-server Starting
Container atomic-server-0380-server Started
4.4 验证运行状态
docker compose ps
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
atomic-server-0380-server joepmeneer/atomic-server:v0.38.0 "/atomic-server-bin" atomic-server 8 seconds ago Up 8 seconds 80/tcp, 0.0.0.0:8139->8139/tcp, [::]:8139->8139/tcp
curl -s -o /dev/null -w 'HTTP:%{http_code} TYPE:%{content_type}\n' http://localhost:8139/
HTTP:200 TYPE:text/html
首页返回 HTML 即内嵌的 atomic-data-browser 前端。核对版本:
docker exec atomic-server-0380-server /atomic-server-bin --version
atomic-server 0.38.0
💡 说明:0.38.0 镜像的入口点是
/atomic-server-bin,不在 PATH 中,docker exec调用 CLI 子命令必须写全路径(develop标签镜像则位于/usr/local/bin/atomic-server)。
4.5 首启日志与初始化动作
全新空库首次启动的日志(docker compose logs 节选,实测首尾):
Atomic-server 0.38.0
Use --help for instructions. Visit https://docs.atomicdata.dev and https://github.com/atomicdata-dev/atomic-server for more info.
2026-11-01T10:41:54.150158Z INFO atomic_server::appstate: Initializing AppState
2026-11-01T10:41:54.150170Z INFO atomic_server::appstate: Opening database at "/atomic-storage/data/store"
2026-11-01T10:41:54.164855Z INFO atomic_server::appstate: Initialize: creating and populating new Database...
2026-11-01T10:41:54.213205Z INFO atomic_server::appstate: Setting default agent
2026-11-01T10:41:54.215129Z WARN atomic_server::appstate: No existing config found, created a new Config at "/atomic-storage/config/config.toml". Copy this to your client machine (running atomic-cli or atomic-data-browser) to log in with these credentials.
server = "http://localhost:8139"
agent = "http://localhost:8139/agents/uuIgCqY79Wq1ZLU7y1tHIisGWmdSkHC2oAsGaioFANg="
private_key = "aKyy/8Ij6aOibh6LhozEweJELzmo6seGLjxtFBQaw5U="
2026-11-01T10:41:54.215168Z INFO atomic_server::appstate: Default Agent is set: http://localhost:8139/agents/uuIgCqY79Wq1ZLU7y1tHIisGWmdSkHC2oAsGaioFANg=
2026-11-01T10:41:54.215171Z INFO atomic_server::appstate: Starting search service
2026-11-01T10:41:54.223860Z INFO atomic_server::appstate: Starting commit monitor
2026-11-01T10:41:54.326510Z INFO atomic_server::appstate: Creating initial Invite at http://localhost:8139/setup
2026-11-01T10:41:54.326535Z INFO atomic_lib::storelike: Building index (this could take a few minutes for larger databases)
2026-11-01T10:41:54.327904Z INFO atomic_server::appstate: Setting rights to Drive http://localhost:8139
2026-11-01T10:41:54.327955Z INFO atomic_server::appstate: Adding all resources to search index
2026-11-01T10:41:58.339518Z INFO atomic_server::search: Search index finished!
2026-11-01T10:41:58.339729Z INFO atomic_server::serve: Binding HTTP server to endpoint :::8139
__ _
____ _/ /_____ ____ ___ (_)____ ________ ______ _____ _____
/ __ `/ __/ __ \/ __ `__ \/ / ___/_____/ ___/ _ \/ ___/ | / / _ \/ ___/
/ /_/ / /_/ /_/ / / / / / / / /__/_____(__ ) __/ / | |/ / __/ /
\__,_/\__/\____/_/ /_/ /_/_/\___/ /____/\___/_/ |___/\___/_/
Visit http://localhost:8139
2026-11-01T10:41:58.339780Z INFO actix_server::builder: Starting 6 workers
2026-11-01T10:41:58.339800Z INFO actix_server::server: Actix runtime found; starting in Actix runtime
首启做了四件事:建库并填充核心本体(Initialize: creating and populating new Database)、生成默认 Agent 密钥对并写入 config.toml、创建一次性 /setup 邀请、构建全文检索索引后绑定端口。日志里 WARN 行打印的 server/agent/private_key 三元组就是这台服务器的根凭据,务必妥善保存(见第七章)。
4.6 访问控制与 /setup 邀请
Atomic Server 没有传统「admin 账号」,管理身份是持密钥的 Agent。首次部署后访问 http://localhost:8139/setup(浏览器打开即进入内嵌前端的注册页),或用 API 读取邀请资源:
curl -s -H 'Accept: application/ad+json' http://localhost:8139/setup
实测响应(节选,实测首尾):
{
"@id": "http://localhost:8139/setup",
"https://atomicdata.dev/properties/description": "Use this Invite to create an Agent, or use an existing one. Accepting will grant your Agent the necessary rights to edit the data in your Atomic Server. This can only be used once. If you, for whatever reason, need a new `/setup` invite, you can pass the `--initialize` flag to `atomic-server`.",
"https://atomicdata.dev/properties/invite/target": "http://localhost:8139",
"https://atomicdata.dev/properties/invite/usagesLeft": 1,
"https://atomicdata.dev/properties/invite/write": true,
"https://atomicdata.dev/properties/isA": [
"https://atomicdata.dev/classes/Invite"
],
"https://atomicdata.dev/properties/name": "Setup"
}
要点:该邀请 usagesLeft=1(一次性)、write=true(授予写权);用完后若需重发,给服务器加 --initialize 参数重启即可重建 /setup 邀请。默认读权限是开放的(匿名 GET 任意资源返回 200),写操作则必须经 Agent 签名(API 篇详解)。
五、数据持久化说明
./data:/atomic-storage 挂载目录在首启后的实际结构(实测 tree 输出):
/atomic-storage
/atomic-storage/config
/atomic-storage/config/config.toml
/atomic-storage/data
/atomic-storage/data/store
/atomic-storage/data/store/blobs
/atomic-storage/data/store/conf
/atomic-storage/data/store/db
/atomic-storage/data/store/snap.000000000081ADA0
存储引擎为 sled(嵌入式 KV),数据库目录实测占用:
du -sh /atomic-storage/data/store
# 2.5M /atomic-storage/data/store
⚠️ 注意:全文检索索引不在
/atomic-storage下,默认位于/root/.cache/atomic-data/search_index(show-config实测search_index_path字段)。本编排只持久化了/atomic-storage,因此删除重建后检索索引会丢失——但服务器重启时会自动全量重建(4.5 首启日志中的Building search index... / Search index finished!即该过程),数据本身不受影响。如需持久化索引,追加挂载-v ./search_index:/root/.cache/atomic-data/search_index。
六、环境变量表
0.38.0 的所有命令行参数都有对应 ATOMIC_* 环境变量(--help 的 [env: ...] 标注实测确认),部署常用项:
| 环境变量 | 对应参数 | 默认值 | 说明 |
|---|---|---|---|
ATOMIC_DOMAIN | --domain | localhost | 对外域名(不含端口与协议) |
ATOMIC_PORT | -p/--port | 9883 | HTTP 监听端口,与宿主映射保持一致 |
ATOMIC_PORT_HTTPS | --port-https | 9884 | HTTPS 监听端口 |
ATOMIC_IP | --ip | :: | 监听地址 |
ATOMIC_LOG_LEVEL | --log-level | info | warn/info/debug/trace |
ATOMIC_CONFIG_DIR | --config-dir | 镜像内为 /atomic-storage/config | 配置目录(config.toml 所在) |
ATOMIC_DATA_DIR | --data-dir | 镜像内为 /atomic-storage/data | 数据目录(store 所在) |
ATOMIC_SERVER_URL | --server-url | 由 domain+port 推导 | 经反向代理/隧道暴露时显式指定完整 URL |
ATOMIC_HTTPS / ATOMIC_EMAIL | --https / --email | 关 | 启用 LetsEncrypt 自动证书 |
ATOMIC_INITIALIZE | --initialize | 关 | 重建 /setup 邀请并重跑初始化 |
ATOMIC_REBUILD_INDEX | --rebuild-indexes | 关 | 全量重建索引 |
ATOMIC_PUBLIC_MODE | --public-mode | false | 跳过鉴权检查提升读性能 |
参数逐项语义、优先级与 show-config 全量输出见本专栏配置篇。
七、配置文件挂载(config.toml)
首启生成的 /atomic-storage/config/config.toml 实测内容:
server = "http://localhost:8139"
agent = "http://localhost:8139/agents/uuIgCqY79Wq1tHIisGWmdSkHC2oAsGaioFANg="
private_key = "aKyy/8Ij6aOibh6LhozEweJELzmo6seGLjxtFBQaw5U="
逐项说明:
server:本服务器根 URL(Drive 的 subject 即此值);agent:默认(根)Agent 的资源 URL;private_key:根 Agent 的 Ed25519 私钥(Base64)。持有它即可签名写入这台服务器的全部数据,等同最高权限口令;WARN 日志提示「Copy this to your client machine」——客户端(浏览器注册或 @tomic/lib)凭它登录。生产环境请把它当作真实密钥管理,不要随文档/仓库外泄;本例为实验环境的一次性密钥,如实展示。
该文件随 ./data 挂载持久化在宿主机(./data/config/config.toml),备份数据时应一并保存。
八、等价 docker run
与 4.1 编排等价的单命令形式:
docker run -d \
--name atomic-server-0380-server \
-p 8139:8139 \
-e ATOMIC_DOMAIN=localhost \
-e ATOMIC_PORT=8139 \
-e ATOMIC_LOG_LEVEL=info \
-v $(pwd)/data:/atomic-storage \
--restart unless-stopped \
joepmeneer/atomic-server:v0.38.0
| 维度 | Compose(本文) | docker run |
|---|---|---|
| 网络子网固定 | ipam.subnet 声明式 | 需 docker network create --subnet 另建 |
| 配置管理 | 文件化、可入 Git | 参数散在命令历史 |
| 升级换版本 | 改 image 一行 up -d | 删容器重跑 |
官方文档页的 docker run -p 80:80 -p 443:443 -v atomic-storage:/atomic-storage joepmeneer/atomic-server 是「直接暴露 80/443 + 命名卷」形态,适合单机快速起服务;生产建议按本文显式钉住 v0.38.0 标签(latest 在 amd64 不可用,见 FAQ Q1)。
九、常用运维命令
9.1 生命周期
docker compose stop # 停止(保留容器与数据)
docker compose start
docker compose restart
docker compose down # 停止并删除容器与网络,./data 数据保留
docker compose logs -f # 跟踪日志
docker compose ps # 状态一览(见 4.4)
9.2 查看生效配置与版本
docker exec atomic-server-0380-server /atomic-server-bin show-config
回显节选(实测首尾,完整字段见配置篇):
Config {
server_url: "http://localhost:8139",
...
config_file_path: "/atomic-storage/config/config.toml",
store_path: "/atomic-storage/data/store",
search_index_path: "/root/.cache/atomic-data/search_index",
}
9.3 备份(export)
服务运行中直接执行 CLI 备份会因 sled 单写锁失败(实测回显):
docker exec atomic-server-0380-server /atomic-server-bin export -p /atomic-storage/export-lock-test.json
Error: Failed opening DB at this location: "/atomic-storage/data/store" . Is another instance of Atomic Server running? IO error: could not acquire lock on "/atomic-storage/data/store/db": Os { code: 11, kind: WouldBlock, message: "Resource temporarily unavailable" }
正确做法:停服后用一次性进程对挂载卷执行 export(本文的备份/恢复回显采集自数据目录副本 data-test,避免污染在线库;读者对生产卷操作时把路径换回 data 即可):
cp -a data data-test
docker compose stop atomic-server
docker run --rm -v $(pwd)/data-test:/atomic-storage \
--entrypoint /atomic-server-bin joepmeneer/atomic-server:v0.38.0 \
export -p /atomic-storage/backups/2026-11-01.json
Succesfully exported data to /atomic-storage/backups/2026-11-01.json
ls -l data-test/backups/
# total 288
# -rw-r--r-- 1 root root 293143 Nov 1 19:29 2026-11-01.json
不带 -p 时默认写入配置目录下 config/backups/<时间戳>.json(实测回显:Succesfully exported data to /atomic-storage/config/backups/2026-11-01T11:29:55.730234396+00:00.json)。导出物是 JSON-AD 数组文件,本例 293KB。
9.4 恢复(import)
对备份文件直接 import 会因「Commit 不可直接创建」被拒(实测回显):
docker run --rm -v $(pwd)/data-test:/atomic-storage \
--entrypoint /atomic-server-bin joepmeneer/atomic-server:v0.38.0 \
import --file /atomic-storage/backups/2026-11-01.json
Importing...
Error: Unable to process resource in array. Failed to save http://localhost:8139/commits/+T/uuLBLcRbeQYjczSnfRSC09ujweoHW1kf98kM40lm6R4aiXdhdHLdXSG0+Yd+pkXS2dcmPKDZdmAAB6jWSAA==: Commits can not be edited or created directly.
恢复备份需加 --force(跳过校验、原样导入含 Commit 的完整状态):
du -sh data-test/data/store
# 2.6M data-test/data/store
docker run --rm -v $(pwd)/data-test:/atomic-storage \
--entrypoint /atomic-server-bin joepmeneer/atomic-server:v0.38.0 \
import --file /atomic-storage/backups/2026-11-01.json --force
Importing...
Sucesfully imported "/atomic-storage/backups/2026-11-01.json" to store.
du -sh data-test/data/store
# 7.6M data-test/data/store
⚠️ 关键限制(实测结论):import 恢复只适用于server_url 相同的灾难恢复。把同一备份导入另一台
server_url不同的实例(实验端口 8142)后,collections查询members=[]、search0 结果——因为导入资源的 subject 仍是原服务器的http://localhost:8139/...,被新实例视为「外部缓存资源」而不纳入本地集合。跨实例迁移需改写 subject,不在 import 能力范围内。
9.5 生成 .env 模板
docker run --rm -v $(pwd):/work -w /work \
--entrypoint /atomic-server-bin joepmeneer/atomic-server:v0.38.0 \
generate-dotenv
Successfully created /work/.env
生成的 .env 把全部 ATOMIC_* 选项以注释形式列出(节选,实测首尾):
# Generated by `atomic-server generate-dotenv`.
# Recreates the `/setup` Invite for creating a new Root User. Also re-runs various populate commands, and re-builds the index
# ATOMIC_INITIALIZE=
...
# How much logs you want. Also influences what is sent to your trace service, if you've set one (e.g. OpenTelemetry)
# Possible values: ["warn", "info", "debug", "trace"]
# RUST_LOG=info
当前目录已有 .env 时会直接 panic(实测回显):
thread 'main' panicked at server/src/bin.rs:118:17:
/work/.env already exists
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
9.6 reset(危险操作)
reset 子命令用于清空存储(help 原文标注 "Danger! Removes all data from the store")。实测在非交互终端执行会 panic 拒绝(保护机制):
thread 'main' panicked at server/src/bin.rs:100:14:
called `Result::unwrap()` on an `Err` value: IO(Custom { kind: NotConnected, error: "not a terminal" })
即它要求 TTY 交互确认;确要清空请在交互终端执行,并提前完成 9.3 备份。
十、常见问题
Q1:拉取 latest 后启动报 exec format error?
latest 标签仅构建了 arm64 架构(Docker Hub API 实测其 images 只有 architecture: "arm64"),amd64 主机无法执行。改用 v0.38.0(amd64+arm 多架构)。
Q2:docker pull 报「这镜像不在白名单 / this image is not in the allowlist」或直连超时?
本机 daemon 配置了 DaoCloud registry-mirror,该镜像不在其白名单;且宿主机直连 Docker Hub 超时。解法:确认 daemon 代理 192.168.1.72:7897 可用(systemctl show docker --property=Environment 或 /etc/docker/daemon.json 的 proxies 配置),然后直接用 docker compose up -d 触发自动拉取(实测成功)。备用代理 192.168.1.62:7897 当时不可用。
Q3:想用 ghcr.io 的官方镜像?
ghcr.io/ontola/atomic-server 实测 manifest unknown——组织迁移后官方容器渠道仍是 Docker Hub 的 joepmeneer/atomic-server。
Q4:export 报 could not acquire lock?
sled 同一时刻只允许一个进程持有数据库锁。先 docker compose stop,再用一次性进程执行 export(见 9.3)。
Q5:import 报 Commits can not be edited or created directly.?
备份文件包含 Commit 资源,常规导入路径禁止直接写 Commit;恢复整库用 --force(见 9.4)。
Q6:把备份导入新实例后集合/搜索全空? subject 归属问题:备份内资源 URL 全部指向原 server_url,新实例将其视为外部资源。import 仅适合同 server_url 恢复(见 9.4 ⚠️)。
Q7:容器重建后全文搜索无结果?
检索索引在 /root/.cache/atomic-data/search_index,未随卷持久化。重启后服务器自动重建(首启日志 Search index finished!);若怀疑索引不一致,用 --rebuild-indexes 强制重建。
Q8:generate-dotenv panic already exists?
当前目录已有 .env,先移除或换空目录(见 9.5)。
Q9:改了宿主映射端口后,页面数据错乱/资源指向 9883?
subject 由 domain+port 生成,宿主端口与服务端口不一致会导致引用错位。保持 ports 与 ATOMIC_PORT 一致,或经反代部署时显式设置 ATOMIC_SERVER_URL(见 4.1)。
Q10:如何启用 HTTPS?
追加 --https(ATOMIC_HTTPS=)与 --email(LetsEncrypt 联系邮箱);证书自动申请后落在 show-config 所示路径 /atomic-storage/config/https/{key,cert}.pem。子域名场景配 --https-dns 走 DNS-01 质询。
十一、参考链接
- 官方文档站(安装/API/规范):https://docs.atomicdata.dev
- GitHub 仓库:https://github.com/ontola/atomic-server
- 官方镜像仓库:https://hub.docker.com/r/joepmeneer/atomic-server
- Atomic Commits 规范:https://docs.atomicdata.dev/commits/intro.html
- Atomic Invites:https://docs.atomicdata.dev/invitations.html
- 站内继续阅读:《Atomic Server 介绍与选型指南》(选型背景与版本线溯源)