news 2026/10/28 1:51:07

AFFiNE 内网离线部署:镜像导入 + 编排 + 常见报错排查

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AFFiNE 内网离线部署:镜像导入 + 编排 + 常见报错排查

第 1 章 名词认一遍

名词

一句话解释

Docker

运行容器的引擎

镜像

程序打包好的"毛坯房"

容器

镜像跑起来的实例

Compose

用一个 YAML 管理多个容器

bind mount

宿主机目录挂进容器;删容器不删目录

named volume

Docker 管理的卷;down -v会删

migration

启动前一次性升级数据库的任务,退出码必须 0

externalUrl

AFFiNE 对外地址,影响附件与登录回调

healthcheck

容器的健康检查,healthy才算就绪


第 2 章 准备机器、材料、变量

2.1 检查机器

uname -m nproc free -h df -h / ip -o -4 addr show scope global

【你应该看到】

  • x86_64
  • CPU ≥ 2(建议 4)
  • 内存total≥ 3.5Gi
  • 根分区可用 ≥ 30G
  • 一个全局 IPv4(抄下来)

2.2 确认系统

. /etc/os-release && echo "$PRETTY_NAME"

【你应该看到】Ubuntu 22.04.x LTS。

2.3 检查材料

cd ~/offline ls -lh affine-images.tar affine/docker-compose.yml affine/config/config.json //这里主要是检查镜像包是不是大约468mb,如果只有几kb,说明下载的时候文件损坏了;同时确定docker的启动脚本(docker-compose.yml)和 AFFiNE 的配置文件(config.json)在正确的位置; ls -d docker-debs //因为我们的要求是进行离线下载,所以我们需要提前下载好docker的离线安装包放在这个文件夹里,这一步就是检查这个宝箱在不在; ls ~/offline/docker-debs/*.deb | wc -l //统计我们的宝箱的数量;

【你应该看到】

affine-images.tar 约 468M affine/docker-compose.yml affine/config/config.json docker-debs/ 64

镜像条目:

tar -xOf affine-images.tar manifest.json | python3 -c ' //找到一个叫manifest.json的文件,打印上面的文字; import json,sys d=json.load(sys.stdin) //接过前面递过来的上面的json代码,数一数有几个物品; print("条目数:", len(d)) //打印物品的个数 for x in d: print(" ", ", ".join(x.get("RepoTags") or [])) '

【你应该看到】条目数: 4,包含:
ghcr.io/toeverything/affine:stable、redis:7.2.4、redis:latest、pgvector/pgvector:pg16。

2.4 确认基础命令

这里主要是用来检查我们的工具全不全,如:bash , curl ,tar和gzip, ss , ip

bash (命令行外壳): 你的地基。你现在敲打所有命令的黑框框环境就是它提供的。 curl (网络探测器): 用来模拟浏览器发请求。 tar和gaip (打包/解压工具) ss(端口雷达): 巡逻兵。文档里用它来检查本机的 3010 端口 ip
for t in bash curl tar gzip python3 ss ip; do printf '%-10s ' "$t" command -v "$t" || echo MISSING done

【你应该看到】没有MISSING。

2.5 变量块(每新开终端都要执行)

把LAN_IP改成你的内网 IP,然后整段复制执行:

export指令在这里的作用主要是将这些变量的属性改为全局变量;

export OFFLINE=$HOME/offline export AFFINE_DIR=$OFFLINE/affine export AFFINE_CFG=$AFFINE_DIR/config/config.json export AFFINE_PORT=3010 export LAN_IP=192.168.72.128

逐行解释:

变量

作用

能不能改

OFFLINE

材料根目录

材料换路径时改

AFFINE_DIR

AFFiNE 部署目录

一般不改

AFFINE_CFG

配置文件路径

一般不改

AFFINE_PORT

对外端口

与 compose 的端口映射一起改

LAN_IP

本机内网 IP

必须改成你的

【判据】

echo "$LAN_IP / $AFFINE_PORT" ls -d "$AFFINE_DIR" "$AFFINE_CFG"

【你应该看到】

192.168.72.128 / 3010 /home/你的用户名/offline/affine /home/你的用户名/offline/affine/config/config.json

2.6 断网(建议)

sudo ip route del default curl -I --max-time 5 https://ghcr.io 2>&1 | head -3

【你应该看到】Could not resolve host/Network is unreachable之类失败。

【注意】浏览器要访问内网 IP 时,不要停网卡,只删默认路由。


第 3 章 离线安装 Docker(手工)

3.1 确认 deb 包

ls ~/offline/docker-debs/*.deb | wc -l

【你应该看到】64(至少 ≥ 4)。

3.2 用 apt 本地安装

cd ~/offline/docker-debs sudo apt-get install -y --no-download ./*.deb

【你应该看到】Setting up docker.io ...、Setting up docker-compose-v2 ...等。

--no-download的作用:禁止 apt 联网补包;本地包不全时会直接失败,而不是偷偷下载。

3.3 如果 apt 失败,用 dpkg 回退

dpkg(Debian Package Manager)是 Ubuntu 系统里最底层的软件安装工。它专门负责把.deb后缀的安装包解压、写进系统。

【这里为什么要装3次呢?】

因为dpkg是按字母顺序盲装的,所以一定会遇到“依赖顺序颠倒”的问题。

cd ~/offline/docker-debs sudo dpkg -i ./*.deb || true sudo dpkg -i ./*.deb || true sudo dpkg -i ./*.deb || true

装 3 轮是因为包的依赖顺序未必刚好;后面几轮会把前面缺的依赖补上。

【你应该看到】最后一轮基本没有dependency problems。

3.4 启动服务

这里是将containerd和 docker进行启动并常驻后台;

sudo systemctl enable --now containerd //systemctl: 它是 Linux 系统的“大管家”,专门负责管理后台程序。 //enable(开机自启) //--now(立即生效) sudo systemctl enable --now docker sleep 3

3.5 验证

docker version docker compose version

【你应该看到】

Client: Docker Engine ... Server: Docker Engine ... ... Docker Compose version v2.40.x

【如果当前用户 permission denied】

Docker 是一个权限极高的底层系统软件。为了安全,Linux 默认只允许超级管理员(root)去碰这个发动机。

newgrp docker

或者重新登录一次。

3.6 加入 docker 组(新用户需要)

sudo usermod -aG docker "$USER" newgrp docker

【判据】

这里的ps是用来查看进程相关的信息的;

docker ps

【你应该看到】空表或已有容器列表,不再报 permission denied。

第 4 章 导入镜像

【这一步做什么】把 tar 里的 4 个镜像导入本机 Docker。
【为什么】离线环境不能联网拉取;不导入,启动时会报pull access denied。
【命令】

docker load -i "$OFFLINE/affine-images.tar" //docker load:是docker专用的离线安装的指令 //-i 这里是input输入的意思后面跟的是文件路径; //"$OFFLINE/affine-images.tar":这就是提前准备好的、装了 4 个核心镜像的那个 468MB 的大压缩包的完整路径。

【你应该看到】

Loaded image: ghcr.io/toeverything/affine:stable Loaded image: redis:7.2.4 Loaded image: redis:latest Loaded image: pgvector/pgvector:pg16

【判据】

docker images --format '{{.Repository}}:{{.Tag}}\t{{.Size}}' \ | grep -E 'affine|pgvector|redis'

【你应该看到】至少这 3 类:

ghcr.io/toeverything/affine:stable 895MB pgvector/pgvector:pg16 ... redis:7.2.4 ... redis:latest ...

【如果不对】重新docker load;确认 tar 没损坏(大小约 468M)。


第 5 章 改写对外地址

【这一步做什么】把config.json的externalUrl从localhost改成你的内网 IP。
【为什么】AFFiNE 用它生成分享链接、附件地址、登录回调;写 localhost 时别的电脑打不开。
【命令:先备份】

cd "$AFFINE_DIR" cp -a config/config.json "config/config.json.bak.$(date +%Y%m%d-%H%M%S)" ls -1t config/config.json.bak.* | head -3

【你应该看到】至少一个config.json.bak.2026...文件。

【命令:改写】

python3 - "$AFFINE_CFG" "http://$LAN_IP:$AFFINE_PORT" <<'PY' import re, sys path, url = sys.argv[1], sys.argv[2] raw = open(path, encoding="utf-8").read() new, n = re.subn(r'("externalUrl"\s*:\s*)"[^"]*"', r'\1"%s"' % url, raw) if n == 0: sys.exit("config.json 里没找到 externalUrl 字段") open(path, "w", encoding="utf-8").write(new) print(f"已改写 {n} 处 -> {url}") PY

【你应该看到】

已改写 1 处 -> http://192.168.72.128:3010

【判据】

grep -n externalUrl "$AFFINE_CFG"

【你应该看到】

5: "externalUrl": "http://192.168.72.128:3010",

【如果不对】

  • 报没找到 externalUrl:打开文件确认字段名与格式:
grep -n 'external' "$AFFINE_CFG"
  • 手工改也可以:用编辑器把http://localhost:3010改成http://<LAN_IP>:3010。

第 6 章 启动容器

【这一步做什么】用docker compose up启动 4 个容器。
【为什么】--pull never是离线死命令:只用本地镜像;缺镜像立刻报错,不会联网卡住。
【命令】

cd "$AFFINE_DIR" mkdir -p data docker compose up -d --pull never // up:启动 // -d: 后台运行 // --pull never(离线护身符): 强制命令 Docker “永远不要(never)去网上拉取(pull)镜像”

【你应该看到】

Network affine_default Created Container affine_postgres Started Container affine_redis Started Container affine_migration_job Started Container affine_server Started

【判据:容器状态】

docker compose ps

【你应该看到】

NAME IMAGE STATUS affine_migration_job ghcr.io/toeverything/affine:stable exited (0) affine_postgres pgvector/pgvector:pg16 running (healthy) affine_redis redis:latest running (healthy) affine_server ghcr.io/toeverything/affine:stable running

第 7 章 验证

7.1 迁移任务

docker inspect -f '{{.State.ExitCode}}' affine_migration_job

【你应该看到】0。

7.2 容器健康

docker compose ps

【你应该看到】

  • affine_postgres:running (healthy)
  • affine_redis:running (healthy)
  • affine_server:running
  • affine_migration_job:exited (0)

7.3 入口层

curl -s -o /dev/null -w 'AFFiNE:3010 -> %{http_code}\n' http://127.0.0.1:3010/

【你应该看到】AFFiNE:3010 -> 302(或200)。

7.4 日志层

for c in affine_server affine_postgres affine_redis; do n=$(docker logs "$c" 2>&1 \ | grep -ciE "dial tcp|no such host|i/o timeout|ENOTFOUND|getaddrinfo" || true) printf '%-24s 网络失败线索: %s\n' "$c" "$n" done

【你应该看到】基本为 0。

【例外】127.0.0.1:587连接拒绝 = SMTP 探测,假警报。

7.5 数据落盘检查

ls -la "$AFFINE_DIR/data" du -sh "$AFFINE_DIR/data/storage" "$AFFINE_DIR/data/postgres" 2>/dev/null

【你应该看到】两个目录存在,postgres 目录里有内容(说明数据库初始化成功)。


第 8 章 浏览器首次初始化

8.1 打开

http://<LAN_IP>:3010

注意是http,不是https。

8.2 首次向导

  1. 设置管理员邮箱与密码。
    • 邮箱必须是合法域名:@example.com可以,@test.local会被拒。
  1. 点Continue。
  2. 看到All Settings Done后再点一次 Continue。

8.3 验证数据持久化

  1. 新建文档
  2. 输入文字
  3. 刷新页面
  4. 内容还在

8.4 用命令行确认数据真的落盘

ls -la ~/offline/affine/data/storage

【你应该看到】出现新的目录/文件(按时间排序最新)。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:50:26

启元 Q1 的数字身体 从 URDF 看懂机器人关节

一台机器人还没接上电源&#xff0c;开发者已经可以在电脑里查看它的身体结构。软件依据什么判断哪里是肩膀、手肘朝哪个方向弯&#xff0c;甚至前臂会不会碰到躯干&#xff1f;这些问题&#xff0c;需要先读懂机器人的模型文件。 这次从启元机器人官方开发者社区的资料下载页…

作者头像 李华
网站建设 2026/10/28 1:49:17

K8S:scale 与 delete pod 核心区别

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:48:08

电视直播软件 my-tv 完整指南:安装后 4 步到首次开播

电视直播软件 my-tv 完整指南&#xff1a;安装后 4 步到首次开播 【免费下载链接】my-tv 我的电视 电视直播软件&#xff0c;安装即可使用 项目地址: https://gitcode.com/GitHub_Trending/my/my-tv 我的电视 my-tv 是一款开源电视直播软件&#xff1a;免注册、不收费&a…

作者头像 李华
网站建设 2026/10/28 1:47:13

地球运转、时间系统与坐标系统:GNSS大地测量学基础总结

地球运转、时间系统与坐标系统&#xff1a;GNSS大地测量学基础总结在学习RTKLIB和GNSS定位的过程中&#xff0c;坐标系统和时间系统是最容易被忽略却又最基础的知识。不理解地球的运动规律&#xff0c;就无法理解为什么要定义这么多时间系统和坐标框架&#xff1b;不理解这些框…

作者头像 李华
网站建设 2026/10/28 1:46:31

如何系统学习 AI 系统?《AI System》全栈开源课程学习指南

如何系统学习 AI 系统&#xff1f;《AI System》全栈开源课程学习指南 【免费下载链接】AISystem AISystem 主要是指AI系统&#xff0c;包括AI芯片、AI编译器、AI推理和训练框架等AI全栈底层技术 项目地址: https://gitcode.com/GitHub_Trending/ai/AISystem 大多数 AI …

作者头像 李华